Skip to content

Commit

Permalink
Add iterator support to url_search_params
Browse files Browse the repository at this point in the history
  • Loading branch information
jasnell committed Oct 9, 2023
1 parent 88cded9 commit c114d0d
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 1 deletion.
42 changes: 42 additions & 0 deletions include/ada/url_search_params-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,48 @@ inline void url_search_params::sort() {
});
}

inline url_search_params_keys_iter url_search_params::get_keys() {
return url_search_params_keys_iter(*this);
}

/**
* @see https://url.spec.whatwg.org/#interface-urlsearchparams
*/
inline url_search_params_values_iter url_search_params::get_values() {
return url_search_params_values_iter(*this);
}

/**
* @see https://url.spec.whatwg.org/#interface-urlsearchparams
*/
inline url_search_params_entries_iter url_search_params::get_entries() {
return url_search_params_entries_iter(*this);
}

template <typename T, url_search_params_iter_type Type>
inline bool url_search_params_iter<T, Type>::is_done() {
return pos >= params.params.size();
}

template <>
inline std::optional<std::string> url_search_params_keys_iter::next() {
if (is_done()) return std::nullopt;
return params.params[pos++].first;
}

template <>
inline std::optional<std::string> url_search_params_values_iter::next() {
if (is_done()) return std::nullopt;
return params.params[pos++].second;
}

template <>
inline std::optional<std::pair<std::string, std::string>>
url_search_params_entries_iter::next() {
if (is_done()) return std::nullopt;
return params.params[pos++];
}

} // namespace ada

#endif // ADA_URL_SEARCH_PARAMS_INL_H
56 changes: 56 additions & 0 deletions include/ada/url_search_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@

namespace ada {

enum class url_search_params_iter_type {
keys,
values,
entries,
};

template <typename T, url_search_params_iter_type Type>
struct url_search_params_iter;

using url_search_params_keys_iter =
url_search_params_iter<std::string, url_search_params_iter_type::keys>;
using url_search_params_values_iter =
url_search_params_iter<std::string, url_search_params_iter_type::values>;
using url_search_params_entries_iter =
url_search_params_iter<std::pair<std::string, std::string>,
url_search_params_iter_type::entries>;

/**
* @see https://url.spec.whatwg.org/#interface-urlsearchparams
*/
Expand Down Expand Up @@ -74,6 +91,21 @@ struct url_search_params {
*/
inline std::string to_string();

/**
* @see https://url.spec.whatwg.org/#interface-urlsearchparams
*/
inline url_search_params_keys_iter get_keys();

/**
* @see https://url.spec.whatwg.org/#interface-urlsearchparams
*/
inline url_search_params_values_iter get_values();

/**
* @see https://url.spec.whatwg.org/#interface-urlsearchparams
*/
inline url_search_params_entries_iter get_entries();

private:
typedef std::pair<std::string, std::string> key_value_pair;
std::vector<key_value_pair> params{};
Expand All @@ -82,7 +114,31 @@ struct url_search_params {
* @see https://url.spec.whatwg.org/#concept-urlencoded-parser
*/
void initialize(std::string_view init);

template <typename T, url_search_params_iter_type Type>
friend struct url_search_params_iter;
}; // url_search_params

template <typename T, url_search_params_iter_type Type>
struct url_search_params_iter {
url_search_params_iter(const url_search_params_iter &u) = default;
url_search_params_iter(url_search_params_iter &&u) noexcept = default;
url_search_params_iter &operator=(url_search_params_iter &&u) noexcept =
default;
url_search_params_iter &operator=(const url_search_params_iter &u) = default;
~url_search_params_iter() = default;

inline std::optional<T> next();
inline bool is_done();

private:
inline url_search_params_iter(url_search_params &params_) : params(params_) {}

url_search_params &params;
size_t pos = 0;

friend struct url_search_params;
};

} // namespace ada
#endif
38 changes: 37 additions & 1 deletion tests/url_search_params.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,40 @@ TEST(url_search_params, has) {
ASSERT_TRUE(!search_params.has("key1", "value2"));
ASSERT_TRUE(!search_params.has("key3", "value3"));
SUCCEED();
}
}

TEST(url_search_params, iterators) {
auto search_params =
ada::url_search_params("key1=value1&key1=value2&key2=value3");
auto keys = search_params.get_keys();
ASSERT_EQ(keys.next(), "key1");
ASSERT_EQ(keys.next(), "key1");
ASSERT_EQ(keys.next(), "key2");
ASSERT_FALSE(keys.next().has_value());

auto values = search_params.get_values();
ASSERT_EQ(values.next(), "value1");
ASSERT_EQ(values.next(), "value2");
ASSERT_EQ(values.next(), "value3");
ASSERT_FALSE(keys.next().has_value());

auto entries = search_params.get_entries();
auto next = entries.next();
ASSERT_EQ(next->first, "key1");
ASSERT_EQ(next->second, "value1");
next = entries.next();
ASSERT_EQ(next->first, "key1");
ASSERT_EQ(next->second, "value2");
next = entries.next();
ASSERT_EQ(next->first, "key2");
ASSERT_EQ(next->second, "value3");
// At this point we can add a new entry and the iterator will pick it up.
search_params.append("foo", "bar");
next = entries.next();
ASSERT_EQ(next->first, "foo");
ASSERT_EQ(next->second, "bar");

ASSERT_FALSE(entries.next().has_value());

SUCCEED();
}

0 comments on commit c114d0d

Please sign in to comment.