6#ifndef UPA_URL_SEARCH_PARAMS_H
7#define UPA_URL_SEARCH_PARAMS_H
20# include <string_view>
21# include <type_traits>
31constexpr bool is_pair_v =
false;
33template<
class T1,
class T2>
34constexpr bool is_pair_v<std::pair<T1, T2>> =
true;
37template<
class T,
typename =
void>
38constexpr bool is_iterable_pairs_v =
false;
41constexpr bool is_iterable_pairs_v<T, std::void_t<
decltype(
43 std::begin(std::declval<T&>()) != std::end(std::declval<T&>()),
44 ++std::declval<decltype(std::begin(std::declval<T&>()))&>(),
45 *std::begin(std::declval<T&>())
46 )>> = is_pair_v<remove_cvref_t<decltype(*std::begin(std::declval<T&>()))>>;
49template<
class Base,
class T>
50using enable_if_not_base_of_t = std::enable_if_t<
51 !std::is_base_of_v<Base, std::decay_t<T>>,
int>;
59 class url_search_params_ptr;
103 noexcept(std::is_nothrow_move_constructible_v<name_value_list>);
110 template <
class StrT, enable_if_str_arg_t<StrT> = 0>
112 : params_(
do_parse(true,
std::forward<StrT>(query)))
120 detail::enable_if_not_base_of_t<url_search_params, ConT> = 0,
121 std::enable_if_t<detail::is_iterable_pairs_v<ConT>,
int> = 0
124 for (
const auto& p : cont) {
125 params_.emplace_back(make_string(p.first), make_string(p.second));
183 template <
class StrT, enable_if_str_arg_t<StrT> = 0>
184 void parse(StrT&& query);
192 template <
class TN,
class TV>
193 void append(TN&& name, TV&& value);
201 void del(
const TN& name);
209 template <
class TN,
class TV>
210 void del(
const TN& name,
const TV& value);
228 template <
class TN,
class TV>
238 template <
class UnaryPredicate>
249 [[nodiscard]]
const std::string*
get(
const TN& name)
const;
258 [[nodiscard]] std::list<std::string>
get_all(
const TN& name)
const;
267 [[nodiscard]]
bool has(
const TN& name)
const;
276 template <
class TN,
class TV>
277 [[nodiscard]]
bool has(
const TN& name,
const TV& value)
const;
285 template <
class TN,
class TV>
286 void set(TN&& name, TV&& value);
299 void serialize(std::string& query)
const;
306 [[nodiscard]] std::string
to_string()
const;
339 [[nodiscard]]
inline bool empty() const noexcept {
return params_.empty(); }
342 [[nodiscard]]
inline size_type size() const noexcept {
return params_.size(); }
351 template <
class StrT, enable_if_str_arg_t<StrT> = 0>
359 template <
class StrT, enable_if_str_arg_t<StrT> = 0>
360 static void urlencode(std::string& encoded, StrT&& value);
365 void clear_params() noexcept;
368 void parse_params(
std::string_view query);
372 static UPA_API
void urlencode_sv(
std::
string& encoded,
std::string_view value);
380 bool is_sorted_ = false;
381 url* url_ptr_ =
nullptr;
404 inline void init(
url* url_ptr) {
408 inline void set_url_ptr(
url* url_ptr)
noexcept {
410 ptr_->url_ptr_ = url_ptr;
413 inline void clear_params()
noexcept {
415 ptr_->clear_params();
417 inline void parse_params(std::string_view query) {
419 ptr_->parse_params(query);
422 UPA_CONSTEXPR_23
explicit operator bool()
const noexcept {
423 return static_cast<bool>(ptr_);
432 std::unique_ptr<url_search_params> ptr_;
443 : params_(other.params_)
444 , is_sorted_(other.is_sorted_)
450 noexcept(std::is_nothrow_move_constructible_v<name_value_list>)
451 : params_(
std::move(other.params_))
452 , is_sorted_(other.is_sorted_)
458 if (
this != std::addressof(other)) {
466 assert(url_ptr_ ==
nullptr);
467 move_params(std::move(other));
472 move_params(std::move(other));
486 assert(url_ptr_ ==
nullptr && other.url_ptr_ ==
nullptr);
490 swap(params_, other.params_);
491 swap(is_sorted_, other.is_sorted_);
494inline void url_search_params::clear_params() noexcept {
499inline void url_search_params::copy_params(
const url_search_params& other) {
500 params_ = other.params_;
501 is_sorted_ = other.is_sorted_;
505 params_ = std::move(other.params_);
506 is_sorted_ = other.is_sorted_;
509inline void url_search_params::parse_params(std::string_view query) {
514template <
class StrT, enable_if_str_arg_t<StrT>>
516 params_ =
do_parse(
true, std::forward<StrT>(query));
521template <
class TN,
class TV>
523 params_.emplace_back(
524 make_string(std::forward<TN>(name)),
525 make_string(std::forward<TV>(value))
533 const auto str_name = make_string(name);
535 params_.remove_if([&](
const value_type& item) {
536 return item.first == str_name;
541template <
class TN,
class TV>
543 const auto str_name = make_string(name);
544 const auto str_value = make_string(value);
546 params_.remove_if([&](
const value_type& item) {
547 return item.first == str_name && item.second == str_value;
554 const auto str_name = make_string(name);
557 return item.first == str_name;
561template <
class TN,
class TV>
563 const auto str_name = make_string(name);
564 const auto str_value = make_string(value);
567 return item.first == str_name && item.second == str_value;
571template <
class UnaryPredicate>
573#ifdef __cpp_lib_list_remove_return_type
574 const size_type count = params_.remove_if(p);
576 const size_type old_size = params_.size();
577 params_.remove_if(p);
578 const size_type count = old_size - params_.size();
586 const auto str_name = make_string(name);
587 for (
const auto& p : params_) {
588 if (p.first == str_name)
596 std::list<std::string> lst;
597 const auto str_name = make_string(name);
598 for (
const auto& p : params_) {
599 if (p.first == str_name)
600 lst.push_back(p.second);
607 const auto str_name = make_string(name);
608 for (
const auto& p : params_) {
609 if (p.first == str_name)
615template <
class TN,
class TV>
617 const auto str_name = make_string(name);
618 const auto str_value = make_string(value);
620 for (
const auto& p : params_) {
621 if (p.first == str_name && p.second == str_value)
627template <
class TN,
class TV>
629 auto str_name = make_string(std::forward<TN>(name));
630 auto str_value = make_string(std::forward<TV>(value));
632 bool is_match =
false;
633 for (
auto it = params_.begin(); it != params_.end(); ) {
634 if (it->first == str_name) {
636 it = params_.erase(it);
639 it->second = std::move(str_value);
645 append(std::move(str_name), std::move(str_value));
659 return url_utf::compare_by_code_units(
660 a.first.data(), a.first.data() + a.first.size(),
661 b.first.data(), b.first.data() + b.first.size()) < 0;
668template <
class StrT, enable_if_str_arg_t<StrT>>
672 const auto str_query = make_string(std::forward<StrT>(query));
673 auto b = str_query.begin();
674 const auto e = str_query.end();
677 if (rem_qmark && b != e && *b ==
'?')
682 std::string* pval = &name;
684 for (
auto it = b; it != e; ++it) {
690 pval->push_back(*it);
694 url_utf::check_fix_utf8(name);
695 url_utf::check_fix_utf8(value);
696 lst.emplace_back(std::move(name), std::move(value));
705 pval->push_back(
' ');
708 if (std::distance(it, e) > 2) {
710 const auto uc1 =
static_cast<unsigned char>(*(++itc));
711 const auto uc2 =
static_cast<unsigned char>(*(++itc));
712 if (detail::is_hex_char(uc1) && detail::is_hex_char(uc2)) {
713 const char c =
static_cast<char>((detail::hex_char_to_num(uc1) << 4) + detail::hex_char_to_num(uc2));
721 pval->push_back(*it);
726 url_utf::check_fix_utf8(name);
727 url_utf::check_fix_utf8(value);
728 lst.emplace_back(std::move(name), std::move(value));
733template <
class StrT, enable_if_str_arg_t<StrT>>
735 const auto str_value = make_string(std::forward<StrT>(value));
736 urlencode_sv(encoded, str_value);
740 auto it = params_.begin();
741 if (it != params_.end()) {
743 urlencode_sv(query, it->first);
744 query.push_back(
'=');
745 urlencode_sv(query, it->second);
746 if (++it == params_.end())
748 query.push_back(
'&');
name_value_pair value_type
const_iterator begin() const noexcept
url_search_params()=default
Default constructor.
url_search_params & operator=(const url_search_params &other)
Copy assignment.
bool empty() const noexcept
void set(TN &&name, TV &&value)
const_reverse_iterator rend() const noexcept
void append(TN &&name, TV &&value)
const_iterator cbegin() const noexcept
const_iterator cend() const noexcept
static void urlencode(std::string &encoded, StrT &&value)
bool has(const TN &name) const
url_search_params & safe_assign(url_search_params &&other)
Safe move assignment.
url_search_params(StrT &&query)
Parsing constructor.
std::pair< std::string, std::string > name_value_pair
const_reverse_iterator crend() const noexcept
const_iterator end() const noexcept
~url_search_params()=default
destructor
name_value_list::size_type size_type
std::list< std::string > get_all(const TN &name) const
void clear()
Clears parameters.
const std::string * get(const TN &name) const
url_search_params(ConT &&cont)
const_reverse_iterator crbegin() const noexcept
size_type size() const noexcept
friend class detail::url_search_params_ptr
void swap(url_search_params &other) noexcept
Swaps the contents of two url_search_params.
static name_value_list do_parse(bool rem_qmark, StrT &&query)
size_type remove(const TN &name)
name_value_list::const_iterator const_iterator
size_type remove_if(UnaryPredicate p)
name_value_list::const_reverse_iterator const_reverse_iterator
std::string to_string() const
const_reverse_iterator rbegin() const noexcept
void serialize(std::string &query) const
const_reverse_iterator reverse_iterator
std::list< name_value_pair > name_value_list
std::ostream & operator<<(std::ostream &os, const url &url)
Performs stream output on URL.
void swap(url &lhs, url &rhs) noexcept
Swaps the contents of two URLs.