diff --git a/include/boost/url/detail/any_query_iter.hpp b/include/boost/url/detail/any_query_iter.hpp index fa7f404c..add73767 100644 --- a/include/boost/url/detail/any_query_iter.hpp +++ b/include/boost/url/detail/any_query_iter.hpp @@ -231,6 +231,60 @@ class plain_params_iter ) noexcept override; }; +class plain_value_iter_base +{ +protected: + BOOST_URL_DECL + static + void + measure_impl( + string_view key, + string_view const* value, + std::size_t& n) noexcept; + + BOOST_URL_DECL + static + void + copy_impl( + string_view key, + string_view const* value, + char*& dest, + char const* end) noexcept; +}; + +// iterates params in a +// decoded params range +// decoding values only +template +class plain_value_iter + : public any_query_iter + , public plain_value_iter_base +{ + FwdIt it_; + FwdIt end_; + +public: + plain_value_iter( + FwdIt first, + FwdIt last) noexcept + : it_(first) + , end_(last) + { + } + + bool + measure( + std::size_t& n, + error_code& + ) noexcept override; + + void + copy( + char*& dest, + char const* end + ) noexcept override; +}; + //------------------------------------------------ template @@ -251,6 +305,15 @@ make_plain_params_iter( first, last); } +template +plain_value_iter +make_plain_value_iter( + FwdIt first, FwdIt last) +{ + return plain_value_iter( + first, last); +} + } // detail } // urls } // boost diff --git a/include/boost/url/detail/impl/any_query_iter.hpp b/include/boost/url/detail/impl/any_query_iter.hpp index f286b472..65ce9d49 100644 --- a/include/boost/url/detail/impl/any_query_iter.hpp +++ b/include/boost/url/detail/impl/any_query_iter.hpp @@ -53,6 +53,43 @@ copy( dest, end); } +template +bool +plain_value_iter:: +measure( + std::size_t& n, + error_code&) noexcept +{ + if(it_ == end_) + return false; + query_param_view v(*it_++); + if(v.has_value) + measure_impl( + v.key, &v.value, n); + else + measure_impl( + v.key, nullptr, n); + return true; +} + +template +void +plain_value_iter:: +copy( + char*& dest, + char const* end) noexcept +{ + params::value_type v(*it_++); + if(v.has_value) + copy_impl( + v.key, &v.value, + dest, end); + else + copy_impl( + v.key, nullptr, + dest, end); +} + } // detail } // urls } // boost diff --git a/include/boost/url/detail/impl/any_query_iter.ipp b/include/boost/url/detail/impl/any_query_iter.ipp index 64f84d7b..15bcad79 100644 --- a/include/boost/url/detail/impl/any_query_iter.ipp +++ b/include/boost/url/detail/impl/any_query_iter.ipp @@ -13,6 +13,7 @@ #include #include #include +#include namespace boost { namespace urls { @@ -71,10 +72,8 @@ measure( if(! p_) return false; string_view s(p_, n_); - static auto constexpr cs = - pchars + '/' + '?'; urls::validate_pct_encoding( - s, ec, {}, cs); + s, ec, {}, query_chars); if(ec.failed()) return false; n += s.size(); @@ -152,10 +151,8 @@ measure( if(! p_) return false; string_view s(p_, n_); - static auto constexpr cs = - pchars + '/' + '?'; n += urls::pct_encode_bytes( - s, {}, cs); + s, {}, query_chars); increment(); return true; } @@ -167,13 +164,11 @@ copy( char const* end) noexcept { BOOST_ASSERT(p_ != nullptr); - static auto constexpr cs = - pchars + '/' + '?'; dest += pct_encode( dest, end, string_view(p_, n_), {}, - cs); + query_chars); increment(); } @@ -187,19 +182,17 @@ measure_impl( std::size_t& n, error_code& ec) noexcept { - static constexpr auto cs = - pchars + '/' + '?'; pct_decode_opts opt; opt.plus_to_space = true; validate_pct_encoding( - key, ec, opt, cs); + key, ec, opt, query_chars); if(ec.failed()) return false; n += key.size(); if(value) { validate_pct_encoding( - *value, ec, opt, cs); + *value, ec, opt, query_chars); if(ec.failed()) return false; n += 1 + value->size(); @@ -217,17 +210,15 @@ copy_impl( { (void)end; // avoid self-copy + std::size_t n = key.size(); + BOOST_ASSERT(end - n >= dest); if( key.data() != dest && key.data() != nullptr) { - std::size_t n = - key.size(); - BOOST_ASSERT( - end - n >= dest); std::memcpy(dest, key.data(), n); - dest += n; } + dest += n; if(value) { BOOST_ASSERT( @@ -255,15 +246,13 @@ measure_impl( string_view const* value, std::size_t& n) noexcept { - static constexpr auto cs = - pchars + '/' + '?'; n += pct_encode_bytes( - key, {}, cs); + key, {}, query_chars); if(value) { ++n; // '=' n += pct_encode_bytes( - *value, {}, cs); + *value, {}, query_chars); } } @@ -275,15 +264,53 @@ copy_impl( char*& dest, char const* end) noexcept { - static constexpr auto cs = - pchars + '/' + '?'; dest += pct_encode( - dest, end, key, {}, cs); + dest, end, key, {}, query_chars); + if(value) + { + *dest++ = '='; + dest += pct_encode( + dest, end, *value, {}, query_chars); + } +} + +//------------------------------------------------ + +void +plain_value_iter_base:: +measure_impl( + string_view key, + string_view const* value, + std::size_t& n) noexcept +{ + n += key.size(); + if(value) + { + ++n; // '=' + n += pct_encode_bytes( + *value, {}, query_chars); + } +} + +void +plain_value_iter_base:: +copy_impl( + string_view key, + string_view const* value, + char*& dest, + char const* end) noexcept +{ + // avoid self-copy + std::size_t n = key.size(); + BOOST_ASSERT(end - n >= dest); + // iterator for value only + BOOST_ASSERT(key.data() == dest); + dest += n; if(value) { *dest++ = '='; dest += pct_encode( - dest, end, *value, {}, cs); + dest, end, *value, {}, query_chars); } } diff --git a/include/boost/url/impl/params.ipp b/include/boost/url/impl/params.ipp index 1f422fe1..e46539b6 100644 --- a/include/boost/url/impl/params.ipp +++ b/include/boost/url/impl/params.ipp @@ -169,10 +169,24 @@ replace_value( string_view value) -> iterator { - (void)pos; - (void)value; - // VFALCO TODO - return {}; + auto const r = + u_->param(pos.i_); + string_view key{ + u_->s_ + r.pos + 1, + r.nk - 1}; + value_type v{ + key, value, true }; + BOOST_ASSERT(pos.u_ == u_); + using detail:: + make_plain_value_iter; + u_->edit_params( + pos.i_, + pos.i_ + 1, + make_plain_value_iter( + &v, &v + 1), + make_plain_value_iter( + &v, &v + 1)); + return pos; } auto diff --git a/include/boost/url/impl/params_encoded.ipp b/include/boost/url/impl/params_encoded.ipp index 7335a7b5..a65d594d 100644 --- a/include/boost/url/impl/params_encoded.ipp +++ b/include/boost/url/impl/params_encoded.ipp @@ -139,10 +139,10 @@ replace_value( string_view value) -> iterator { - (void)pos; - (void)value; - // VFALCO TODO - return {}; + return emplace_at( + pos, + (*pos).key, + value); } auto diff --git a/test/unit/params.cpp b/test/unit/params.cpp index a58d9ffe..50150ae3 100644 --- a/test/unit/params.cpp +++ b/test/unit/params.cpp @@ -219,9 +219,18 @@ class params_test } // replace_value(iterator, string_view) - // replace_value(iterator, Value) { - // VFALCO TODO + url u = parse_uri_reference( + "/?k0=0&k%31=0&k2=#f").value(); + params p = u.params(pa_.allocator()); + auto it = p.replace_value( + p.begin() + 1, + "1"); + BOOST_TEST(it == p.begin() + 1); + BOOST_TEST_EQ(u.encoded_query(), + "k0=0&k%31=1&k2="); + BOOST_TEST_EQ(u.string(), + "/?k0=0&k%31=1&k2=#f"); } // emplace_at(iterator, string_view, string_view) diff --git a/test/unit/params_encoded.cpp b/test/unit/params_encoded.cpp index 9d85bfc0..240959e6 100644 --- a/test/unit/params_encoded.cpp +++ b/test/unit/params_encoded.cpp @@ -216,9 +216,18 @@ class params_encoded_test } // replace_value(iterator, string_view) - // replace_value(iterator, Value) { - // VFALCO TODO + url u = parse_uri_reference( + "/?k0=0&k%31=0&k2=#f").value(); + params_encoded p = u.encoded_params(); + auto it = p.replace_value( + p.begin() + 1, + "1"); + BOOST_TEST(it == p.begin() + 1); + BOOST_TEST(u.encoded_query() == + "k0=0&k%31=1&k2="); + BOOST_TEST(u.string() == + "/?k0=0&k%31=1&k2=#f"); } // emplace_at(iterator, string_view, string_view)