// // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/url // #ifndef BOOST_URL_PARAMS_ENCODED_REF_HPP #define BOOST_URL_PARAMS_ENCODED_REF_HPP #include #include #include #include namespace boost { namespace urls { #ifndef BOOST_URL_DOCS class url_base; class params_encoded_view; #endif /** Mutable encoded query parameter proxy This container exposes the percent-encoded query parameters of a @ref url_base as a bidirectional range while allowing mutation of the underlying URL. It references the URL’s buffer directly, so the url must stay alive for the lifetime of the proxy. @par Example @code url u( "?first=John&last=Doe" ); params_encoded_ref p = u.encoded_params(); @endcode Strings produced when elements are returned have type @ref param_pct_view and represent encoded strings. Strings passed to member functions may contain percent escapes, and throw exceptions on invalid inputs. @par Iterator Invalidation Changes to the underlying character buffer can invalidate iterators which reference it. Modifications made through the container invalidate some iterators to the underlying character buffer: @li @ref append : Only `end()`. @li @ref assign, @ref clear, `operator=` : All params. @li @ref erase : Erased params and all params after (including `end()`). @li @ref insert : All params at or after the insertion point (including `end()`). @li @ref replace, @ref set : Modified params and all params after (including `end()`). @par Reads vs. writes Even though this type can be used to mutate the referenced URL, this is still a proxy and every observer function inherited from @ref params_encoded_base (for example @ref contains, @ref find, and @ref get_or) behaves like the corresponding function on @ref params_encoded_view: it inspects the current encoded query and does not perform any modifications. */ class BOOST_SYMBOL_VISIBLE params_encoded_ref : public params_encoded_base { friend class url_base; url_base* u_ = nullptr; params_encoded_ref( url_base& u) noexcept; public: //-------------------------------------------- // // Special Members // //-------------------------------------------- /** Constructor After construction, both views reference the same url. Ownership is not transferred; the caller is responsible for ensuring the lifetime of the url extends until it is no longer referenced. @par Postconditions @code &this->url() == &other.url(); @endcode @par Complexity Constant. @par Exception Safety Throws nothing. @param other The other view. */ params_encoded_ref( params_encoded_ref const& other) = default; /** Assignment The previous contents of this are replaced by the contents of `other.
All iterators are invalidated. @note The strings referenced by `other` must not come from the underlying url, or else the behavior is undefined. @par Effects @code this->assign( other.begin(), other.end() ); @endcode @par Complexity Linear in `other.buffer().size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. @param other The params to assign. @return `*this` */ params_encoded_ref& operator=( params_encoded_ref const& other); /** Assignment After assignment, the previous contents of the query parameters are replaced by the contents of the initializer-list.
All iterators are invalidated. @par Preconditions None of character buffers referenced by `init` may overlap the character buffer of the underlying url, or else the behavior is undefined. @par Effects @code this->assign( init.begin(), init.end() ); @endcode @par Complexity Linear in `init.size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error `init` contains an invalid percent-encoding. @param init The list of params to assign. @return `*this` */ params_encoded_ref& operator=(std::initializer_list< param_pct_view> init); /** Conversion @par Complexity Constant. @par Exception Safety Throws nothing. @return A view of the params. */ operator params_encoded_view() const noexcept; //-------------------------------------------- // // Observers // //-------------------------------------------- /** Return the referenced url This function returns the url referenced by the view. @par Example @code url u( "?key=value" ); assert( &u.encoded_params().url() == &u ); @endcode @par Exception Safety @code Throws nothing. @endcode @return A reference to the url. */ url_base& url() const noexcept { return *u_; } //-------------------------------------------- // // Modifiers // //-------------------------------------------- /** Clear the contents of the container
All iterators are invalidated. @par Effects @code this->url().remove_query(); @endcode @par Postconditions @code this->empty() == true && this->url().has_query() == false @endcode @par Complexity Constant. @par Exception Safety Throws nothing. */ void clear() noexcept; //-------------------------------------------- /** Assign params This function replaces the entire contents of the view with the params in the initializer-list.
All iterators are invalidated. @note The strings referenced by the inputs must not come from the underlying url, or else the behavior is undefined. @par Example @code url u; u.encoded_params().assign({ { "first", "John" }, { "last", "Doe" } }); @endcode @par Complexity Linear in `init.size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error `init` contains an invalid percent-encoding. @param init The list of params to assign. */ void assign( std::initializer_list< param_pct_view> init); /** Assign params This function replaces the entire contents of the view with the params in the range.
All iterators are invalidated. @note The strings referenced by the inputs must not come from the underlying url, or else the behavior is undefined. @par Mandates @code std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_pct_view >::value == true @endcode @par Complexity Linear in the size of the range. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error The range contains an invalid percent-encoding. @param first The first element to assign. @param last One past the last element to assign. */ template void assign(FwdIt first, FwdIt last); //-------------------------------------------- /** Append params This function appends a param to the view.
The `end()` iterator is invalidated. @par Example @code url u; u.encoded_params().append( { "first", "John" } ); @endcode @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error `p` contains an invalid percent-encoding. @return An iterator to the new element. @param p The param to append. */ iterator append( param_pct_view const& p); /** Append params This function appends the params in an initializer-list to the view.
The `end()` iterator is invalidated. @par Example @code url u; u.encoded_params().append({ {"first", "John"}, {"last", "Doe"} }); @endcode @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error `init` contains an invalid percent-encoding. @return An iterator to the first new element. @param init The list of params to append. */ iterator append( std::initializer_list< param_pct_view> init); /** Append params This function appends a range of params to the view.
The `end()` iterator is invalidated. @note The strings referenced by the inputs must not come from the underlying url, or else the behavior is undefined. @par Mandates @code std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_pct_view >::value == true @endcode @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error The range contains an invalid percent-encoding. @return An iterator to the first new element. @param first The first element to append. @param last One past the last element to append. @return An iterator to the first new element. */ template iterator append( FwdIt first, FwdIt last); //-------------------------------------------- /** Insert params This function inserts a param before the specified position.
All iterators that are equal to `before` or come after are invalidated. @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error `p` contains an invalid percent-encoding. @return An iterator to the inserted element. @param before An iterator before which the param is inserted. This may be equal to `end()`. @param p The param to insert. */ iterator insert( iterator before, param_pct_view const& p); /** Insert params This function inserts the params in an initializer-list before the specified position.
All iterators that are equal to `before` or come after are invalidated. @note The strings referenced by the inputs must not come from the underlying url, or else the behavior is undefined. @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error `init` contains an invalid percent-encoding. @return An iterator to the first element inserted, or `before` if `init.size() == 0`. @param before An iterator before which the element is inserted. This may be equal to `end()`. @param init The list of params to insert. */ iterator insert( iterator before, std::initializer_list< param_pct_view> init); /** Insert params This function inserts a range of params before the specified position.
All iterators that are equal to `before` or come after are invalidated. @note The strings referenced by the inputs must not come from the underlying url, or else the behavior is undefined. @par Mandates @code std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_pct_view >::value == true @endcode @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error The range contains an invalid percent-encoding. @return An iterator to the first element inserted, or `before` if `first == last`. @param before An iterator before which the element is inserted. This may be equal to `end()`. @param first The first element to insert. @param last One past the last element to insert. @return An iterator to the first element inserted. */ template iterator insert( iterator before, FwdIt first, FwdIt last); //-------------------------------------------- /** Erase params This function removes an element from the container.
All iterators that are equal to `pos` or come after are invalidated. @par Example @code url u( "?first=John&last=Doe" ); params_encoded_ref::iterator it = u.encoded_params().erase( u.encoded_params().begin() ); assert( u.encoded_query() == "last=Doe" ); @endcode @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Throws nothing. @return An iterator to one past the removed element. @param pos An iterator to the element. */ iterator erase(iterator pos) noexcept; /** Erase params This function removes a range of params from the container.
All iterators that are equal to `first` or come after are invalidated. @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Throws nothing. @return An iterator to one past the removed range. @param first The first element to remove. @param last One past the last element to remove. @return An iterator to one past the removed range. */ iterator erase( iterator first, iterator last) noexcept; /** Erase params
All iterators are invalidated. @par Postconditions @code this->count( key, ic ) == 0 @endcode @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Exceptions thrown on invalid input. @throw system_error `key` contains an invalid percent-encoding. @return The number of params removed from the container. @param key The key to match. By default, a case-sensitive comparison is used. @param ic An optional parameter. If the value @ref ignore_case is passed here, the comparison is case-insensitive. */ std::size_t erase( pct_string_view key, ignore_case_param ic = {}) noexcept; //-------------------------------------------- /** Replace params This function replaces the contents of the element at `pos` with the specified param.
All iterators that are equal to `pos` or come after are invalidated. @note The strings passed in must not come from the element being replaced, or else the behavior is undefined. @par Example @code url u( "?first=John&last=Doe" ); u.encoded_params().replace( u.encoded_params().begin(), { "title", "Mr" }); assert( u.encoded_query() == "title=Mr&last=Doe" ); @endcode @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error `p` contains an invalid percent-encoding. @return An iterator to the element. @param pos An iterator to the element. @param p The param to assign. */ iterator replace( iterator pos, param_pct_view const& p); /** Replace params This function replaces a range of params with the params in an initializer-list.
All iterators that are equal to `from` or come after are invalidated. @note The strings referenced by the inputs must not come from the underlying url, or else the behavior is undefined. @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error `init` contains an invalid percent-encoding. @return An iterator to the first element inserted, or one past `to` if `init.size() == 0`. @param from,to The range of params to replace. @param init The list of params to assign. */ iterator replace( iterator from, iterator to, std::initializer_list< param_pct_view> init); /** Replace params This function replaces a range of params with a range of params.
All iterators that are equal to `from` or come after are invalidated. @note The strings referenced by the inputs must not come from the underlying url, or else the behavior is undefined. @par Mandates @code std::is_convertible< std::iterator_traits< FwdIt >::reference_type, param_pct_view >::value == true @endcode @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error The range contains an invalid percent-encoding. @return An iterator to the first element inserted, or one past `to` if `first == last`. @param from The first element to replace. @param to One past the last element to replace. @param first The first element to insert. @param last One past the last element to insert. @return An iterator to the first element inserted, or one past `to` if `first == last`. */ template iterator replace( iterator from, iterator to, FwdIt first, FwdIt last); //-------------------------------------------- /** Remove the value on an element This function removes the value of an element at the specified position. After the call returns, `has_value` for the element is false.
All iterators that are equal to `pos` or come after are invalidated. @par Example @code url u( "?first=John&last=Doe" ); u.encoded_params().unset( u.encoded_params().begin() ); assert( u.encoded_query() == "first&last=Doe" ); @endcode @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Throws nothing. @return An iterator to the element. @param pos An iterator to the element. */ iterator unset( iterator pos) noexcept; /** Set a value This function replaces the value of an element at the specified position.
All iterators that are equal to `pos` or come after are invalidated. @note The string passed in must not come from the element being replaced, or else the behavior is undefined. @par Example @code url u( "?id=42&id=69" ); u.encoded_params().set( u.encoded_params().begin(), "none" ); assert( u.encoded_query() == "id=none&id=69" ); @endcode @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error `value` contains an invalid percent-encoding. @return An iterator to the element. @param pos An iterator to the element. @param value The value to assign. The empty string still counts as a value. That is, `has_value` for the element is true. */ iterator set( iterator pos, pct_string_view value); /** Set a value This function performs one of two actions depending on the value of `this->contains( key, ic )`. @li If key is contained in the view then one of the matching params has its value changed to the specified value. The remaining params with a matching key are erased. Otherwise, @li If `key` is not contained in the view, then the function apppends the param `{ key, value }`.
All iterators are invalidated. @note The strings passed in must not come from the element being replaced, or else the behavior is undefined. @par Example @code url u( "?id=42&id=69" ); u.encoded_params().set( "id", "none" ); assert( u.encoded_params().count( "id" ) == 1 ); @endcode @par Postconditions @code this->count( key, ic ) == 1 && this->find( key, ic )->value == value @endcode @par Complexity Linear in `this->url().encoded_query().size()`. @par Exception Safety Strong guarantee. Calls to allocate may throw. Exceptions thrown on invalid input. @throw system_error `key` or `value` contain an invalid percent-encoding. @return An iterator to the appended or modified element. @param key The key to match. By default, a case-sensitive comparison is used. @param value The value to assign. The empty string still counts as a value. That is, `has_value` for the element is true. @param ic An optional parameter. If the value @ref ignore_case is passed here, the comparison is case-insensitive. */ iterator set( pct_string_view key, pct_string_view value, ignore_case_param ic = {}); private: template void assign(FwdIt first, FwdIt last, std::forward_iterator_tag); // Doxygen cannot render ` = delete` template void assign(FwdIt first, FwdIt last, std::input_iterator_tag) = delete; template iterator insert( iterator before, FwdIt first, FwdIt last, std::forward_iterator_tag); // Doxygen cannot render ` = delete` template iterator insert( iterator before, FwdIt first, FwdIt last, std::input_iterator_tag) = delete; }; } // urls } // boost // This is in // // #include //------------------------------------------------ // // std::ranges::enable_borrowed_range // //------------------------------------------------ #ifdef BOOST_URL_HAS_CONCEPTS #include namespace std::ranges { template<> inline constexpr bool enable_borrowed_range< boost::urls::params_encoded_ref> = true; } // std::ranges #endif #endif