diff --git a/include/boost/url/impl/params_encoded_base.hpp b/include/boost/url/impl/params_encoded_base.hpp
index 5ff1e0dd1..c220bfe7d 100644
--- a/include/boost/url/impl/params_encoded_base.hpp
+++ b/include/boost/url/impl/params_encoded_base.hpp
@@ -130,6 +130,27 @@ contains(
begin().it_, key, ic) != end();
}
+inline
+pct_string_view
+params_encoded_base::
+get_or(
+ pct_string_view key,
+ pct_string_view value,
+ ignore_case_param ic) const noexcept
+{
+ auto it = find_impl(
+ begin().it_, key, ic);
+ detail::params_iter_impl end_(ref_, 0);
+ if(it.equal(end_))
+ return value;
+
+ param_pct_view const p = it.dereference();
+ if(! p.has_value)
+ return pct_string_view();
+
+ return p.value;
+}
+
inline
auto
params_encoded_base::
diff --git a/include/boost/url/params_base.hpp b/include/boost/url/params_base.hpp
index e972d4273..6553da5d5 100644
--- a/include/boost/url/params_base.hpp
+++ b/include/boost/url/params_base.hpp
@@ -29,11 +29,12 @@ namespace urls {
# pragma warning(disable: 4251)
#endif
-/** Common functionality for query parameter containers
+/** Decoded query parameter helper base
- The library uses this base class
- to provide common member functions for
- containers of query parameters.
+ This base centralizes the read-only,
+ percent-decoded query parameter algorithms
+ (iteration, lookup, counting) that are
+ shared by @ref params_view and @ref params_ref.
This class should not be instantiated
directly; Instead, use one of the
@@ -319,6 +320,45 @@ class BOOST_URL_DECL params_base
core::string_view key,
ignore_case_param ic = {}) const noexcept;
+ /** Return the value for a key or a fallback
+
+ This convenience function searches for the
+ first parameter matching `key` and returns
+ its decoded value. If no parameter with the
+ specified key exists, the provided fallback
+ `value` is returned instead. When the key is
+ found but the parameter has no value, an
+ empty string is returned.
+
+ @par Example
+ @code
+ url_view u( "/path?first=John&last=Doe" );
+ assert( u.params().get_or( "first", "n/a" ) == "John" );
+ assert( u.params().get_or( "missing", "n/a" ) == "n/a" );
+ @endcode
+
+ @par Complexity
+ Linear in `this->buffer().size()`.
+
+ @par Exception Safety
+ Calls to allocate may throw.
+
+ @param key The key to match.
+ @param value The fallback string returned
+ when no matching key exists. If this
+ parameter is omitted, an empty string is
+ used.
+ @param ic Optional case-insensitive compare
+ indicator.
+
+ @return The decoded value or the fallback.
+ */
+ std::string
+ get_or(
+ core::string_view key,
+ core::string_view value = {},
+ ignore_case_param ic = {}) const;
+
/** Find a matching key
This function examines the parameters
diff --git a/include/boost/url/params_encoded_base.hpp b/include/boost/url/params_encoded_base.hpp
index 3e26cb4ec..98cd67a17 100644
--- a/include/boost/url/params_encoded_base.hpp
+++ b/include/boost/url/params_encoded_base.hpp
@@ -21,13 +21,15 @@
namespace boost {
namespace urls {
-/** Common functionality for containers
+/** Percent-encoded query helper base
- This base class is used by the library
- to provide common member functions for
- containers. This cannot be instantiated
- directly; Instead, use one of the
- containers or functions:
+ This base implements the shared
+ percent-encoded query parameter view
+ functionality used by @ref params_encoded_view
+ and @ref params_encoded_ref. It cannot be
+ instantiated directly; instead, use one of
+ those containers or the corresponding ref
+ adaptors.
@par Containers
@li @ref params_ref
@@ -319,6 +321,46 @@ class BOOST_URL_DECL params_encoded_base
pct_string_view key,
ignore_case_param ic = {}) const noexcept;
+ /** Return the value for a key or a fallback
+
+ This convenience function searches for the
+ first parameter matching `key` and returns
+ its percent-encoded value. If no parameter
+ with the specified key exists, the provided
+ fallback `value` is returned instead. When
+ the key is found but the corresponding
+ parameter has no value, an empty string is
+ returned.
+
+ @par Example
+ @code
+ url_view u( "/path?first=John&last=Doe" );
+ assert( u.encoded_params().get_or(
+ "missing", "n%2Fa" ) == "n%2Fa" );
+ @endcode
+
+ @par Complexity
+ Linear in `this->buffer().size()`.
+
+ @par Exception Safety
+ Throws nothing.
+
+ @param key The key to match.
+ @param value The fallback string returned
+ when no matching key exists. If this
+ parameter is omitted, an empty string is
+ used.
+ @param ic Optional case-insensitive compare
+ indicator.
+
+ @return The encoded value or the fallback.
+ */
+ pct_string_view
+ get_or(
+ pct_string_view key,
+ pct_string_view value = {},
+ ignore_case_param ic = {}) const noexcept;
+
/** Find a matching key
This function examines the parameters
diff --git a/include/boost/url/params_encoded_ref.hpp b/include/boost/url/params_encoded_ref.hpp
index 67cb6a403..4ac8d230a 100644
--- a/include/boost/url/params_encoded_ref.hpp
+++ b/include/boost/url/params_encoded_ref.hpp
@@ -24,21 +24,14 @@ class url_base;
class params_encoded_view;
#endif
-/** A view representing query parameters in a URL
+/** Mutable encoded query parameter proxy
- Objects of this type are used to interpret
- the query parameters as a bidirectional view
- of key value pairs.
-
- The view does not retain ownership of the
- elements and instead references the original
- url. The caller is responsible for ensuring
- that the lifetime of the referenced url
- extends until it is no longer referenced.
-
- The view is modifiable; calling non-const
- members causes changes to the referenced
- url.
+ 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
@@ -69,6 +62,17 @@ class params_encoded_view;
@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_URL_DECL params_encoded_ref
: public params_encoded_base
diff --git a/include/boost/url/params_encoded_view.hpp b/include/boost/url/params_encoded_view.hpp
index 624dba84f..ec553e862 100644
--- a/include/boost/url/params_encoded_view.hpp
+++ b/include/boost/url/params_encoded_view.hpp
@@ -26,17 +26,13 @@ namespace implementation_defined {
struct query_rule_t;
}
-/** A view representing query parameters in a URL
+/** Non-owning encoded query parameter view
- Objects of this type are used to interpret
- the query parameters as a bidirectional view
- of key/value pairs.
-
- The view does not retain ownership of the
- elements and instead references the original
- character buffer. The caller is responsible
- for ensuring that the lifetime of the buffer
- extends until it is no longer referenced.
+ This read-only range exposes the raw
+ percent-encoded key/value pairs stored in a
+ query string. It does not copy the underlying
+ buffer; callers must ensure the referenced
+ character storage outlives the view.
@par Example
@code
@@ -45,11 +41,9 @@ namespace implementation_defined {
params_encoded_view 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.
+ Iteration yields @ref param_pct_view values,
+ so encoded strings and escape validation are
+ preserved for callers that want exact bytes.
@par Iterator Invalidation
Changes to the underlying character buffer
diff --git a/include/boost/url/params_ref.hpp b/include/boost/url/params_ref.hpp
index de2e53361..5ce4d5bc1 100644
--- a/include/boost/url/params_ref.hpp
+++ b/include/boost/url/params_ref.hpp
@@ -25,19 +25,15 @@ class url_base;
class params_view;
#endif
-/** A view representing query parameters in a URL
-
- Objects of this type are used to interpret
- the query parameters as a bidirectional view
- of key/value pairs.
- The view does not retain ownership of the
- elements and instead references the original
- url. The caller is responsible for ensuring
- that the lifetime of the referenced url
- extends until it is no longer referenced.
- The view is modifiable; calling non-const
- members causes changes to the referenced
- url.
+/** Mutable decoded query parameter proxy
+
+ This container presents the decoded query
+ parameters of a @ref url_base as a bidirectional
+ range whose modifying operations update the
+ underlying URL in-place. It references (but
+ does not own) the character buffer, so the
+ referenced URL must stay alive while the proxy
+ is used.
@@ -76,6 +72,16 @@ class params_view;
@li @ref replace, @ref set : Modified
elements and all elements
after (including `end()`).
+
+ @par Reads vs. writes
+ Although this is a mutable proxy, all
+ observer helpers inherited from
+ @ref params_base (such as @ref contains,
+ @ref find, and @ref get_or) operate in the
+ same way as they do on @ref params_view:
+ they perform their lookup against the
+ current contents of the referenced URL
+ without modifying it.
*/
class BOOST_URL_DECL params_ref
: public params_base
diff --git a/include/boost/url/params_view.hpp b/include/boost/url/params_view.hpp
index fb3d2b782..4ff9f63b8 100644
--- a/include/boost/url/params_view.hpp
+++ b/include/boost/url/params_view.hpp
@@ -17,17 +17,14 @@
namespace boost {
namespace urls {
-/** A view representing query parameters in a URL
+/** Non-owning decoded query parameter view
- Objects of this type are used to interpret
- the query parameters as a bidirectional view
- of key/value pairs.
-
- The view does not retain ownership of the
- elements and instead references the original
- character buffer. The caller is responsible
- for ensuring that the lifetime of the buffer
- extends until it is no longer referenced.
+ This read-only range interprets the query
+ string of a URL as bidirectional key/value
+ pairs with percent-decoding applied on
+ access. It merely references the original
+ character buffer; callers must keep that
+ buffer alive while the view is used.
@par Example
@code
@@ -36,9 +33,8 @@ namespace urls {
params_view p = u.params();
@endcode
- Percent escapes in strings returned when
- dereferencing iterators are automatically
- decoded.
+ Strings retrieved from the iterators are
+ automatically percent-decoded.
@par Iterator Invalidation
Changes to the underlying character buffer
diff --git a/include/boost/url/segments_base.hpp b/include/boost/url/segments_base.hpp
index 3c50ba6ae..779513536 100644
--- a/include/boost/url/segments_base.hpp
+++ b/include/boost/url/segments_base.hpp
@@ -20,13 +20,14 @@
namespace boost {
namespace urls {
-/** Common functionality for containers
-
- This base class is used by the library
- to provide common member functions for
- containers. This cannot be instantiated
- directly; Instead, use one of the
- containers or functions:
+/** Decoded path segment helper base
+
+ Provides the shared decoded path-segment
+ algorithms (iteration, lookup, comparison)
+ used by @ref segments_view and
+ @ref segments_ref. This base cannot be
+ instantiated directly; instead, use one of
+ the concrete containers below.
@par Containers
@li @ref segments_ref
diff --git a/include/boost/url/segments_encoded_base.hpp b/include/boost/url/segments_encoded_base.hpp
index 7390c00cc..d181a121b 100644
--- a/include/boost/url/segments_encoded_base.hpp
+++ b/include/boost/url/segments_encoded_base.hpp
@@ -20,13 +20,13 @@
namespace boost {
namespace urls {
-/** Common functionality for containers
+/** Percent-encoded path segment helper base
- This base class is used by the library
- to provide common member functions for
- containers. This cannot be instantiated
- directly; Instead, use one of the
- containers or functions:
+ Implements the shared encoded-segment
+ algorithms reused by @ref segments_encoded_view
+ and @ref segments_encoded_ref. It is not
+ intended to be instantiated directly; use
+ one of those concrete containers instead.
@par Containers
@li @ref segments_ref
diff --git a/include/boost/url/segments_encoded_ref.hpp b/include/boost/url/segments_encoded_ref.hpp
index 7e35fb6af..30abc4633 100644
--- a/include/boost/url/segments_encoded_ref.hpp
+++ b/include/boost/url/segments_encoded_ref.hpp
@@ -24,22 +24,13 @@ class url_base;
class segments_encoded_view;
#endif
-/** A view representing path segments in a URL
-
- Objects of this type are used to interpret
- the path as a bidirectional view of segments,
- where each segment is a string which may
- contain percent-escapes.
-
- The view does not retain ownership of the
- elements and instead references the original
- character buffer. The caller is responsible
- for ensuring that the lifetime of the buffer
- extends until it is no longer referenced.
-
- The view is modifiable; calling non-const
- members causes changes to the referenced
- url.
+/** Mutable encoded path segment proxy
+
+ Exposes the percent-encoded segments of a
+ @ref url_base as a bidirectional range that
+ can modify the underlying URL. The proxy uses
+ the URL’s storage directly, so the url must
+ outlive any references.
@par Example
@code
diff --git a/include/boost/url/segments_encoded_view.hpp b/include/boost/url/segments_encoded_view.hpp
index 847fc553c..db1ebed0a 100644
--- a/include/boost/url/segments_encoded_view.hpp
+++ b/include/boost/url/segments_encoded_view.hpp
@@ -22,17 +22,13 @@
namespace boost {
namespace urls {
-/** A view representing path segments in a URL
+/** Non-owning encoded path segment view
- Objects of this type are used to interpret
- the path as a bidirectional view of segment
- strings.
-
- The view does not retain ownership of the
- elements and instead references the original
- character buffer. The caller is responsible
- for ensuring that the lifetime of the buffer
- extends until it is no longer referenced.
+ Exposes the raw percent-encoded segments of
+ a URL path as a read-only bidirectional range.
+ The view references the original buffer, so
+ callers must keep that storage alive while
+ iterating.
@par Example
@code
@@ -43,11 +39,9 @@ namespace urls {
assert( ps.buffer().data() == u.buffer().data() );
@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.
+ Elements are returned as encoded strings,
+ preserving escape sequences for callers that
+ need the exact byte representation.
@par Iterator Invalidation
Changes to the underlying character buffer
diff --git a/include/boost/url/segments_ref.hpp b/include/boost/url/segments_ref.hpp
index 8c26f185c..d9dbb3312 100644
--- a/include/boost/url/segments_ref.hpp
+++ b/include/boost/url/segments_ref.hpp
@@ -24,22 +24,14 @@ class url_base;
class segments_view;
#endif
-/** A view representing path segments in a URL
-
- Objects of this type are used to interpret
- the path as a bidirectional view of segments,
- where each segment is a string with percent
- escapes automatically decoded.
-
- The view does not retain ownership of the
- elements and instead references the original
- character buffer. The caller is responsible
- for ensuring that the lifetime of the buffer
- extends until it is no longer referenced.
-
- The view is modifiable; calling non-const
- members causes changes to the referenced
- url.
+/** Mutable decoded path segment proxy
+
+ Presents the decoded path segments of a
+ @ref url_base as a bidirectional range whose
+ modifiers update the underlying URL. The proxy
+ references the URL’s storage directly, so the
+ owning URL must remain alive while the proxy
+ is used.
@par Example
@code
diff --git a/include/boost/url/segments_view.hpp b/include/boost/url/segments_view.hpp
index c8560dca7..77fb2a80d 100644
--- a/include/boost/url/segments_view.hpp
+++ b/include/boost/url/segments_view.hpp
@@ -18,17 +18,13 @@
namespace boost {
namespace urls {
-/** A view representing path segments in a URL
+/** Non-owning decoded path segment view
- Objects of this type are used to interpret
- the path as a bidirectional view of segment
- strings.
-
- The view does not retain ownership of the
- elements and instead references the original
- character buffer. The caller is responsible
- for ensuring that the lifetime of the buffer
- extends until it is no longer referenced.
+ Presents the path of a URL as a read-only
+ bidirectional range of percent-decoded
+ segments. The range references the original
+ buffer, so callers must keep that storage
+ alive for as long as the view is accessed.
@par Example
@code
@@ -39,9 +35,8 @@ namespace urls {
assert( ps.buffer().data() == u.buffer().data() );
@endcode
- Percent escapes in strings returned when
- dereferencing iterators are automatically
- decoded.
+ Any percent-escapes are decoded on demand
+ when iterators are dereferenced.
@par Iterator Invalidation
Changes to the underlying character buffer
diff --git a/src/params_base.cpp b/src/params_base.cpp
index ca1532ea5..a27d58be0 100644
--- a/src/params_base.cpp
+++ b/src/params_base.cpp
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
namespace boost {
namespace urls {
@@ -203,6 +204,27 @@ count(
return n;
}
+std::string
+params_base::
+get_or(
+ core::string_view key,
+ core::string_view value,
+ ignore_case_param ic) const
+{
+ auto it = find_impl(
+ begin().it_, key, ic);
+ detail::params_iter_impl end_(ref_, 0);
+ if(it.equal(end_))
+ return std::string(value);
+
+ param_pct_view const p = it.dereference();
+ if(! p.has_value)
+ return std::string();
+
+ auto opt = opt_;
+ return p.value.decode(opt);
+}
+
//------------------------------------------------
//
// (implementation)
@@ -282,4 +304,3 @@ operator<<(
} // urls
} // boost
-
diff --git a/test/unit/params_base.cpp b/test/unit/params_base.cpp
index 82a0e2da6..97d320fa5 100644
--- a/test/unit/params_base.cpp
+++ b/test/unit/params_base.cpp
@@ -283,6 +283,32 @@ struct params_base_test
BOOST_TEST(p.contains("F", ignore_case));
BOOST_TEST(! p.contains("G", ignore_case));
}
+
+ // get_or()
+ {
+ url_view u(
+ "?first=John&empty=&novalue&encoded=John%20Doe");
+ params_view p = u.params();
+
+ BOOST_TEST_EQ(p.get_or("first", "n/a"), "John");
+ BOOST_TEST_EQ(p.get_or("encoded", "n/a"), "John Doe");
+ BOOST_TEST_EQ(p.get_or("missing", "n/a"), "n/a");
+ BOOST_TEST_EQ(p.get_or("novalue", "fallback"), "");
+ BOOST_TEST_EQ(p.get_or("empty", "fallback"), "");
+ BOOST_TEST_EQ(
+ p.get_or("FIRST", "n/a", ignore_case), "John");
+ }
+
+ // javadoc
+ {
+ url_view u("/path?first=John&last=Doe");
+ BOOST_TEST_EQ(
+ u.params().get_or("first", "n/a"),
+ "John");
+ BOOST_TEST_EQ(
+ u.params().get_or("missing", "n/a"),
+ "n/a");
+ }
}
void
diff --git a/test/unit/params_encoded_base.cpp b/test/unit/params_encoded_base.cpp
index 6e354ac01..d1534d82a 100644
--- a/test/unit/params_encoded_base.cpp
+++ b/test/unit/params_encoded_base.cpp
@@ -283,6 +283,30 @@ struct params_encoded_base_test
BOOST_TEST(p.contains("F", ignore_case));
BOOST_TEST(! p.contains("G", ignore_case));
}
+
+ // get_or()
+ {
+ url_view u(
+ "?first=John&empty=&novalue&encoded=John%20Doe");
+ params_encoded_view p = u.encoded_params();
+
+ BOOST_TEST_EQ(p.get_or("first", "n%2Fa"), "John");
+ BOOST_TEST_EQ(p.get_or("encoded", "n%2Fa"), "John%20Doe");
+ BOOST_TEST_EQ(p.get_or("missing", "n%2Fa"), "n%2Fa");
+ BOOST_TEST_EQ(p.get_or("novalue", "fallback"), "");
+ BOOST_TEST_EQ(p.get_or("empty", "fallback"), "");
+ BOOST_TEST_EQ(
+ p.get_or("FIRST", "n%2Fa", ignore_case), "John");
+ }
+
+ // javadoc
+ {
+ url_view u("/path?first=John&last=Doe");
+ BOOST_TEST_EQ(
+ u.encoded_params().get_or(
+ "missing", "n%2Fa"),
+ "n%2Fa");
+ }
}
void