diff --git a/doc/HelpCard.odg b/doc/HelpCard.odg
index bc0e09e4..d7afa2a7 100644
Binary files a/doc/HelpCard.odg and b/doc/HelpCard.odg differ
diff --git a/doc/images/HelpCard.svg b/doc/images/HelpCard.svg
index a27253f4..4e32452c 100644
--- a/doc/images/HelpCard.svg
+++ b/doc/images/HelpCard.svg
@@ -381,7 +381,7 @@
- Pathsegmentssegments_encodedsegments_encoded_viewsegments_view
+ Pathsegments_encoded_refsegments_encoded_viewsegments_refsegments_viewparse_path
diff --git a/doc/qbk/0.main.qbk b/doc/qbk/0.main.qbk
index e4638c1b..7def120f 100644
--- a/doc/qbk/0.main.qbk
+++ b/doc/qbk/0.main.qbk
@@ -81,9 +81,9 @@
[def __query_param_view__ [link url.ref.boost__urls__query_param_view `query_param_view`]]
[def __result__ [link url.ref.boost__urls__result `result`]]
[def __segments__ [link url.ref.boost__urls__segments `segments`]]
-[def __segments_view__ [link url.ref.boost__urls__segments_view `segments_view`]]
[def __segments_encoded__ [link url.ref.boost__urls__segments_encoded `segments_encoded`]]
-[def __segments_encoded_view__ [link url.ref.boost__urls__segments_encoded_view `segments_encoded_view`]]
+[def __segments_encoded_ref__ [link url.ref.boost__urls__segments_encoded_ref `segments_encoded_ref`]]
+[def __segments_ref__ [link url.ref.boost__urls__segments_ref `segments_ref`]]
[def __static_url__ [link url.ref.boost__urls__static_url `static_url`]]
[def __string_view__ [link url.ref.boost__urls__string_view `string_view`]]
[def __url__ [link url.ref.boost__urls__url `url`]]
diff --git a/doc/qbk/3.4.path.qbk b/doc/qbk/3.4.path.qbk
index acd125ec..bfecd351 100644
--- a/doc/qbk/3.4.path.qbk
+++ b/doc/qbk/3.4.path.qbk
@@ -39,7 +39,7 @@ are represented using containers modeling bidirectional ranges. For
example the member function
[link url.ref.boost__urls__url_view_base.encoded_segments `encoded_segments`]
returns a container called
-[link url.ref.boost__urls__segments_encoded_view `segments_encoded_view`]
+[link url.ref.boost__urls__segments_encoded_ref `segments_encoded_ref`]
which may be iterated, and references the underlying character buffer
without taking ownership. Here we define the function `segs` which
returns a `std::list` formed by appending each segment in the path:
diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml
index 592d4fdf..9481ca08 100644
--- a/doc/qbk/quickref.xml
+++ b/doc/qbk/quickref.xml
@@ -62,10 +62,10 @@
params_view
params_encoded_view
pct_string_view
- segments_const_view
- segments_const_encoded_view
- segments_encoded_view
segments_view
+ segments_encoded_ref
+ segments_encoded_view
+ segments_ref
diff --git a/example/route/route.cpp b/example/route/route.cpp
index 63f394e7..4cfe90ab 100644
--- a/example/route/route.cpp
+++ b/example/route/route.cpp
@@ -19,7 +19,7 @@
#include
-#include
+#include
#include
#include
#include
diff --git a/include/boost/url.hpp b/include/boost/url.hpp
index 5d23d401..9dfe2cd7 100644
--- a/include/boost/url.hpp
+++ b/include/boost/url.hpp
@@ -14,6 +14,7 @@
#include
#include
+#include
#include
#include
#include
@@ -21,20 +22,22 @@
#include
#include
#include
+#include
#include
-#include
#include
#include
+#include
#include
#include
-#include
-#include
+#include
#include
#include
-#include
-#include
-#include
+#include
#include
+#include
+#include
+#include
+#include
#include
#include
#include
diff --git a/include/boost/url/detail/any_params_iter.hpp b/include/boost/url/detail/any_params_iter.hpp
index 3745f09f..5a4c7f82 100644
--- a/include/boost/url/detail/any_params_iter.hpp
+++ b/include/boost/url/detail/any_params_iter.hpp
@@ -10,12 +10,9 @@
#ifndef BOOST_URL_DETAIL_ANY_PARAMS_ITER_HPP
#define BOOST_URL_DETAIL_ANY_PARAMS_ITER_HPP
-#include
#include
#include
#include
-#include
-#include
#include
#include
#include
@@ -56,6 +53,10 @@ public:
}
};
+//------------------------------------------------
+//
+// any_params_iter
+//
//------------------------------------------------
/* An iterator to a type-erased,
@@ -132,6 +133,10 @@ public:
char const* end) noexcept = 0;
};
+//------------------------------------------------
+//
+// query_iter
+//
//------------------------------------------------
// A string of plain query params
@@ -157,85 +162,9 @@ private:
};
//------------------------------------------------
-
-// Validating and copying from
-// a string of encoded params_view
-class params_encoded_iter_base
-{
-protected:
- BOOST_URL_DECL
- static
- bool
- measure_impl(
- param_pct_view const& v,
- std::size_t& n,
- error_code& ec) noexcept;
-
- BOOST_URL_DECL
- static
- void
- copy_impl(
- char*& dest,
- char const* end,
- param_pct_view const& v) noexcept;
-};
-
-// A range of encoded query params_view
-template
-struct params_encoded_iter
- : any_params_iter
- , private params_encoded_iter_base
-{
- BOOST_STATIC_ASSERT(
- std::is_convertible<
- typename std::iterator_traits<
- FwdIt>::reference,
- param_pct_view>::value);
-
- params_encoded_iter(
- FwdIt first,
- FwdIt last) noexcept
- : any_params_iter(
- first == last)
- , it0_(first)
- , it_(first)
- , end_(last)
- {
- }
-
-private:
- FwdIt it0_;
- FwdIt it_;
- FwdIt end_;
-
- void
- rewind() noexcept override
- {
- it_ = it0_;
- }
-
- bool
- measure(
- std::size_t& n,
- error_code& ec) noexcept override
- {
- if(it_ == end_)
- return false;
- return measure_impl(
- *it_++, n, ec);
- }
-
- void
- copy(
- char*& dest,
- char const* end
- ) noexcept override
- {
- copy_impl(
- dest, end, *it_++);
- }
-};
-
+//
+// params_iter
+//
//------------------------------------------------
class params_iter_base
@@ -300,8 +229,7 @@ private:
{
if(it_ == end_)
return false;
- measure_impl(
- param_view(*it_++), n);
+ measure_impl(*it_++, n);
return true;
}
@@ -314,6 +242,100 @@ private:
}
};
+//------------------------------------------------
+//
+// params_encoded_iter
+//
+//------------------------------------------------
+
+// Validating and copying from
+// a string of encoded params
+class params_encoded_iter_base
+{
+protected:
+ BOOST_URL_DECL
+ static
+ bool
+ measure_impl(
+ param_pct_view const& v,
+ std::size_t& n,
+ error_code& ec) noexcept;
+
+ BOOST_URL_DECL
+ static
+ void
+ copy_impl(
+ char*& dest,
+ char const* end,
+ param_view const& v) noexcept;
+};
+
+// A range of encoded query params_view
+template
+struct params_encoded_iter
+ : any_params_iter
+ , private params_encoded_iter_base
+{
+ BOOST_STATIC_ASSERT(
+ std::is_convertible<
+ typename std::iterator_traits<
+ FwdIt>::reference,
+ param_pct_view>::value);
+
+ BOOST_STATIC_ASSERT(
+ std::is_convertible<
+ typename std::iterator_traits<
+ FwdIt>::reference,
+ param_view>::value);
+
+ params_encoded_iter(
+ FwdIt first,
+ FwdIt last) noexcept
+ : any_params_iter(
+ first == last)
+ , it0_(first)
+ , it_(first)
+ , end_(last)
+ {
+ }
+
+private:
+ FwdIt it0_;
+ FwdIt it_;
+ FwdIt end_;
+
+ void
+ rewind() noexcept override
+ {
+ it_ = it0_;
+ }
+
+ bool
+ measure(
+ std::size_t& n,
+ error_code& ec) noexcept override
+ {
+ if(it_ == end_)
+ return false;
+ return measure_impl(
+ *it_++, n, ec);
+ }
+
+ void
+ copy(
+ char*& dest,
+ char const* end
+ ) noexcept override
+ {
+ copy_impl(
+ dest, end, *it_++);
+ }
+};
+
+//------------------------------------------------
+//
+// param_value_iter
+//
//------------------------------------------------
// An iterator which outputs
@@ -344,6 +366,10 @@ private:
void copy(char*&, char const*) noexcept override;
};
+//------------------------------------------------
+//
+// param_encoded_value_iter
+//
//------------------------------------------------
// An iterator which outputs
@@ -376,15 +402,6 @@ private:
//------------------------------------------------
-template
-params_encoded_iter
-make_params_encoded_iter(
- FwdIt first, FwdIt last)
-{
- return params_encoded_iter<
- FwdIt>(first, last);
-}
-
template
params_iter
make_params_iter(
@@ -394,10 +411,14 @@ make_params_iter(
FwdIt>(first, last);
}
-bool
-ci_decoded_key_equal(
- decode_view key,
- string_view match) noexcept;
+template
+params_encoded_iter
+make_params_encoded_iter(
+ FwdIt first, FwdIt last)
+{
+ return params_encoded_iter<
+ FwdIt>(first, last);
+}
} // detail
} // urls
diff --git a/include/boost/url/detail/any_path_iter.hpp b/include/boost/url/detail/any_path_iter.hpp
deleted file mode 100644
index fed897d6..00000000
--- a/include/boost/url/detail/any_path_iter.hpp
+++ /dev/null
@@ -1,298 +0,0 @@
-//
-// Copyright (c) 2019 Vinnie Falco (vinnie.falco@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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_DETAIL_ANY_PATH_ITER_HPP
-#define BOOST_URL_DETAIL_ANY_PATH_ITER_HPP
-
-#include
-#include
-#include
-
-namespace boost {
-namespace urls {
-namespace detail {
-
-struct BOOST_SYMBOL_VISIBLE
- any_path_iter
-{
- string_view front;
-
- BOOST_URL_DECL
- virtual
- ~any_path_iter() noexcept = 0;
-
- virtual
- bool
- measure(
- std::size_t& n,
- error_code& ec) noexcept = 0;
-
- virtual
- void
- copy(
- char*& dest,
- char const* end) noexcept = 0;
-};
-
-//------------------------------------------------
-
-// iterates segments in an
-// encoded path string
-class BOOST_SYMBOL_VISIBLE
- enc_path_iter
- : public any_path_iter
-{
- std::size_t n_;
- char const* p_;
- char const* end_;
-
- void
- increment() noexcept;
-
-public:
- explicit
- enc_path_iter(
- string_view s) noexcept;
-
- bool
- measure(
- std::size_t& n,
- error_code& ec) noexcept override;
-
- void
- copy(
- char*& dest,
- char const* end) noexcept override;
-};
-
-//------------------------------------------------
-
-// iterates segments in an
-// plain path string
-class BOOST_SYMBOL_VISIBLE
- plain_path_iter :
- public any_path_iter
-{
- std::size_t n_;
- char const* p_;
- char const* end_;
-
- void
- increment() noexcept;
-
-public:
- explicit
- plain_path_iter(
- string_view s) noexcept;
-
- bool
- measure(
- std::size_t& n,
- error_code& ec) noexcept override;
-
- void
- copy(
- char*& dest,
- char const* end) noexcept override;
-};
-
-//------------------------------------------------
-
-// iterates segments in an
-// plain path string
-class BOOST_SYMBOL_VISIBLE
- view_path_iter :
- public any_path_iter
-{
- std::size_t n_;
- decode_view::const_iterator p_;
- decode_view::const_iterator end_;
- bool done_{false};
-
- void
- increment() noexcept;
-
-public:
- explicit
- view_path_iter(
- decode_view s) noexcept;
-
- bool
- measure(
- std::size_t& n,
- error_code& ec) noexcept override;
-
- void
- copy(
- char*& dest,
- char const* end) noexcept override;
-};
-
-//------------------------------------------------
-
-class enc_segs_iter_base
-{
-protected:
- BOOST_URL_DECL
- static
- bool
- measure_impl(
- string_view s,
- std::size_t& n,
- error_code& ec) noexcept;
-
- BOOST_URL_DECL
- static
- void
- copy_impl(
- string_view s,
- char*& dest,
- char const* end) noexcept;
-};
-
-// iterates segments in an
-// encoded segment range
-template
-class enc_segs_iter
- : public any_path_iter
- , public enc_segs_iter_base
-{
- FwdIt it_;
- FwdIt end_;
-
-public:
- enc_segs_iter(
- FwdIt first,
- FwdIt last) noexcept
- : it_(first)
- , end_(last)
- {
- if (it_ != end_)
- front = *first;
- }
-
- bool
- measure(
- std::size_t& n,
- error_code& ec
- ) noexcept override
- {
- if(it_ == end_)
- return false;
- if(! measure_impl(
- *it_, n, ec))
- return false;
- ++it_;
- return true;
- }
-
- void
- copy(
- char*& dest,
- char const* end
- ) noexcept override
- {
- copy_impl(*it_,
- dest, end);
- ++it_;
- }
-};
-
-//------------------------------------------------
-
-class plain_segs_iter_base
-{
-protected:
- BOOST_URL_DECL
- static
- void
- measure_impl(
- string_view s,
- std::size_t& n) noexcept;
-
- BOOST_URL_DECL
- static
- void
- copy_impl(
- string_view s,
- char*& dest,
- char const* end) noexcept;
-};
-
-// iterates segments in a
-// plain segment range
-template
-class plain_segs_iter
- : public any_path_iter
- , public plain_segs_iter_base
-{
- FwdIt it_;
- FwdIt end_;
-
-public:
- plain_segs_iter(
- FwdIt first,
- FwdIt last) noexcept
- : it_(first)
- , end_(last)
- {
- if (first != last)
- front = *first;
- }
-
- bool
- measure(
- std::size_t& n,
- error_code&
- ) noexcept override
- {
- if(it_ == end_)
- return false;
- measure_impl(*it_, n);
- ++it_;
- return true;
- }
-
- void
- copy(
- char*& dest,
- char const* end
- ) noexcept override
- {
- copy_impl(*it_,
- dest, end);
- ++it_;
- }
-};
-
-//------------------------------------------------
-
-template
-enc_segs_iter
-make_enc_segs_iter(
- FwdIt first, FwdIt last)
-{
- return enc_segs_iter(
- first, last);
-}
-
-template
-plain_segs_iter
-make_plain_segs_iter(
- FwdIt first, FwdIt last)
-{
- return plain_segs_iter(
- first, last);
-}
-
-} // detail
-} // urls
-} // boost
-
-#endif
diff --git a/include/boost/url/detail/any_segments_iter.hpp b/include/boost/url/detail/any_segments_iter.hpp
new file mode 100644
index 00000000..d9d25f57
--- /dev/null
+++ b/include/boost/url/detail/any_segments_iter.hpp
@@ -0,0 +1,297 @@
+//
+// Copyright (c) 2019 Vinnie Falco (vinnie.falco@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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_DETAIL_ANY_SEGMENTS_ITER_HPP
+#define BOOST_URL_DETAIL_ANY_SEGMENTS_ITER_HPP
+
+#include
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace urls {
+namespace detail {
+
+class BOOST_SYMBOL_VISIBLE
+ any_segments_iter
+{
+ string_view* s_ = nullptr;
+
+protected:
+ explicit
+ any_segments_iter(
+ string_view* s = nullptr) noexcept
+ : s_(s)
+ {
+ }
+
+public:
+ string_view front;
+
+ // Return the input string or nullptr
+ string_view*
+ input() const noexcept
+ {
+ return s_;
+ }
+
+ // Rewind the iterator to the beginning
+ virtual
+ void
+ rewind() noexcept = 0;
+
+ // Measure and increment the current
+ // element. n is increased by the
+ // encoded size. Returns false on
+ // end of range.
+ virtual bool measure(
+ std::size_t& n) noexcept = 0;
+
+ // Copy and increment the current
+ // element. encoding is performed
+ // if needed.
+ virtual
+ void
+ copy(
+ char*& dest,
+ char const* end) noexcept = 0;
+};
+
+//------------------------------------------------
+
+// iterates segments in an
+// plain path string
+struct BOOST_SYMBOL_VISIBLE
+ path_iter :
+ public any_segments_iter
+{
+ explicit
+ path_iter(
+ string_view s) noexcept;
+
+private:
+ string_view s_;
+ std::size_t n_ = 0;
+ char const* p_ = nullptr;
+ char const* p0_;
+ char const* end_;
+
+ static string_view clean(string_view s) noexcept;
+ void increment() noexcept;
+ void rewind() noexcept override;
+ bool measure(std::size_t&) noexcept override;
+ void copy(char*&, char const*) noexcept override;
+};
+
+//------------------------------------------------
+
+// iterates segments in an
+// encoded path string
+struct BOOST_SYMBOL_VISIBLE
+ path_encoded_iter
+ : public any_segments_iter
+{
+ explicit
+ path_encoded_iter(
+ pct_string_view s) noexcept;
+
+private:
+ string_view s_;
+ std::size_t n_ = 0;
+ char const* p_ = nullptr;
+ char const* p0_;
+ char const* end_;
+
+ static string_view clean(pct_string_view s) noexcept;
+ void increment() noexcept;
+ void rewind() noexcept override;
+ bool measure(std::size_t&) noexcept override;
+ void copy(char*&, char const*) noexcept override;
+};
+
+//------------------------------------------------
+//
+// segments_iter
+//
+//------------------------------------------------
+
+class segments_iter_base
+{
+protected:
+ BOOST_URL_DECL static void measure_impl(
+ string_view, std::size_t&) noexcept;
+ BOOST_URL_DECL static void copy_impl(
+ string_view, char*&, char const*) noexcept;
+};
+
+// iterates segments in a
+// plain segment range
+template
+struct segments_iter
+ : any_segments_iter
+ , segments_iter_base
+{
+ BOOST_STATIC_ASSERT(
+ std::is_convertible<
+ typename std::iterator_traits<
+ FwdIt>::reference,
+ string_view>::value);
+
+ segments_iter(
+ FwdIt first,
+ FwdIt last) noexcept
+ : it_(first)
+ , it0_(first)
+ , end_(last)
+ {
+ if (first != last)
+ front = *first;
+ }
+
+private:
+ FwdIt it_;
+ FwdIt it0_;
+ FwdIt end_;
+
+ void
+ rewind() noexcept override
+ {
+ it_ = it0_;
+ }
+
+ bool
+ measure(
+ std::size_t& n) noexcept override
+ {
+ if(it_ == end_)
+ return false;
+ measure_impl(*it_, n);
+ ++it_;
+ return true;
+ }
+
+ void
+ copy(
+ char*& dest,
+ char const* end
+ ) noexcept override
+ {
+ copy_impl(*it_, dest, end);
+ ++it_;
+ }
+};
+
+//------------------------------------------------
+//
+// segments_encoded_iter
+//
+//------------------------------------------------
+
+// Validating and copying from
+// a string of encoded segments
+class segments_encoded_iter_base
+{
+protected:
+ BOOST_URL_DECL static bool measure_impl(
+ pct_string_view, std::size_t&) noexcept;
+ BOOST_URL_DECL static void copy_impl(
+ string_view, char*&, char const*) noexcept;
+};
+
+// iterates segments in an
+// encoded segment range
+template
+struct segments_encoded_iter
+ : public any_segments_iter
+ , public segments_encoded_iter_base
+{
+ BOOST_STATIC_ASSERT(
+ std::is_convertible<
+ typename std::iterator_traits<
+ FwdIt>::reference,
+ pct_string_view>::value);
+
+ BOOST_STATIC_ASSERT(
+ std::is_convertible<
+ typename std::iterator_traits<
+ FwdIt>::reference,
+ string_view>::value);
+
+ segments_encoded_iter(
+ FwdIt first,
+ FwdIt last) noexcept
+ : it_(first)
+ , it0_(first)
+ , end_(last)
+ {
+ if (it_ != end_)
+ front = *first;
+ }
+
+private:
+ FwdIt it_;
+ FwdIt it0_;
+ FwdIt end_;
+
+ void
+ rewind() noexcept override
+ {
+ it_ = it0_;
+ }
+
+ bool
+ measure(
+ std::size_t& n) noexcept override
+ {
+ if(it_ == end_)
+ return false;
+ if(! measure_impl(*it_, n))
+ return false;
+ ++it_;
+ return true;
+ }
+
+ void
+ copy(
+ char*& dest,
+ char const* end
+ ) noexcept override
+ {
+ copy_impl(*it_, dest, end);
+ ++it_;
+ }
+};
+
+//------------------------------------------------
+
+template
+segments_iter
+make_segments_iter(
+ FwdIt first, FwdIt last)
+{
+ return segments_iter<
+ FwdIt>(first, last);
+}
+
+template
+segments_encoded_iter
+make_segments_encoded_iter(
+ FwdIt first, FwdIt last)
+{
+ return segments_encoded_iter<
+ FwdIt>(first, last);
+}
+
+} // detail
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/detail/config.hpp b/include/boost/url/detail/config.hpp
index 3fdf7d2e..a038a37d 100644
--- a/include/boost/url/detail/config.hpp
+++ b/include/boost/url/detail/config.hpp
@@ -83,10 +83,6 @@
#define BOOST_URL_STRTOK_ARG(T, name) T&& name = {}
#endif
-#ifndef BOOST_URL_STACK_BYTES
-#define BOOST_URL_STACK_BYTES 4096
-#endif
-
#if BOOST_WORKAROUND( BOOST_GCC_VERSION, < 80000 ) || \
BOOST_WORKAROUND( BOOST_CLANG_VERSION, < 30900 )
#define BOOST_URL_RETURN(x) return std::move((x))
diff --git a/include/boost/url/detail/encode.hpp b/include/boost/url/detail/encode.hpp
index 17e0300e..51c8a0c9 100644
--- a/include/boost/url/detail/encode.hpp
+++ b/include/boost/url/detail/encode.hpp
@@ -13,6 +13,7 @@
#include
#include
+#include
#include
namespace boost {
@@ -250,10 +251,10 @@ encode_unchecked(
// escapes. Characters not in the
// allowed set are escaped, and
// escapes are passed through unchanged.
-
+//
template
std::size_t
-re_encoded_size(
+re_encoded_size_unchecked(
string_view s,
encode_opts const&,
CharSet const& allowed) noexcept
@@ -273,6 +274,13 @@ re_encoded_size(
}
else
{
+ BOOST_ASSERT(end - it >= 3);
+ BOOST_ASSERT(
+ grammar::hexdig_value(
+ it[1]) >= 0);
+ BOOST_ASSERT(
+ grammar::hexdig_value(
+ it[2]) >= 0);
n += 3;
it += 3;
}
@@ -285,7 +293,7 @@ re_encoded_size(
template
std::size_t
re_encode_unchecked(
- char* dest,
+ char*& dest_,
char const* const end,
string_view s,
encode_opts const& opt,
@@ -310,9 +318,10 @@ re_encode_unchecked(
*dest++ = hex[c&0xf];
};
(void)end;
- std::size_t dn = 0;
+ auto dest = dest_;
auto const dest0 = dest;
auto const last = s.end();
+ std::size_t dn = 0;
auto it = s.begin();
if(opt.space_to_plus)
{
@@ -377,6 +386,7 @@ re_encode_unchecked(
}
}
}
+ dest_ = dest;
return dest - dest0 - dn;
}
diff --git a/include/boost/url/detail/impl/any_params_iter.ipp b/include/boost/url/detail/impl/any_params_iter.ipp
index fe60377b..669e92be 100644
--- a/include/boost/url/detail/impl/any_params_iter.ipp
+++ b/include/boost/url/detail/impl/any_params_iter.ipp
@@ -128,86 +128,7 @@ increment() noexcept
//------------------------------------------------
//
-// params_encoded_iter_base
-//
-//------------------------------------------------
-
-bool
-params_encoded_iter_base::
-measure_impl(
- param_pct_view const& v,
- std::size_t& n,
- error_code& ec) noexcept
-{
- decode_opts opt;
- opt.plus_to_space = true;
- auto rv = detail::validate_encoding(
- v.key, opt, query_chars);
- if(! rv)
- {
- ec = rv.error();
- return false;
- }
- n += v.key.size();
- if(v.has_value)
- {
- rv = detail::validate_encoding(
- v.value, opt, query_chars);
- if(! rv)
- {
- ec = rv.error();
- return false;
- }
- n += 1 + v.value.size();
- }
- return true;
-}
-
-void
-params_encoded_iter_base::
-copy_impl(
- char*& dest,
- char const* end,
- param_pct_view const& v) noexcept
-{
- (void)end;
- {
- // avoid self-copy
- auto const kn = v.key.size();
- BOOST_ASSERT(end - kn >= dest);
- if( v.key.data() != dest &&
- kn > 0)
- {
- std::memcpy(
- dest,
- v.key.data(),
- kn);
- }
- dest += kn;
- }
- if(v.has_value)
- {
- BOOST_ASSERT(
- end - 1 >= dest);
- *dest++ = '=';
- auto const vn =
- v.value.size();
- BOOST_ASSERT(
- end - vn >= dest);
- if(vn > 0)
- {
- std::memcpy(
- dest,
- v.value.data(),
- vn);
- dest += vn;
- }
- }
-}
-
-//------------------------------------------------
-//
-// params_iter_base
+// params_iter
//
//------------------------------------------------
@@ -254,6 +175,89 @@ copy_impl(
}
}
+//------------------------------------------------
+//
+// params_encoded_iter
+//
+//------------------------------------------------
+
+bool
+params_encoded_iter_base::
+measure_impl(
+ param_pct_view const& v,
+ std::size_t& n,
+ error_code& ec) noexcept
+{
+ decode_opts opt;
+ opt.plus_to_space = true;
+ auto rv = detail::validate_encoding(
+ v.key, opt, query_chars);
+ if(! rv)
+ {
+ ec = rv.error();
+ return false;
+ }
+ n += v.key.size();
+ if(v.has_value)
+ {
+ rv = detail::validate_encoding(
+ v.value, opt, query_chars);
+ if(! rv)
+ {
+ ec = rv.error();
+ return false;
+ }
+ n += 1 + v.value.size();
+ }
+ return true;
+}
+
+void
+params_encoded_iter_base::
+copy_impl(
+ char*& dest,
+ char const* end,
+ param_view const& v) noexcept
+{
+ (void)end;
+ {
+ // avoid self-copy
+ auto const kn = v.key.size();
+ BOOST_ASSERT(end - kn >= dest);
+ if( v.key.data() != dest &&
+ kn > 0)
+ {
+ std::memcpy(
+ dest,
+ v.key.data(),
+ kn);
+ }
+ dest += kn;
+ }
+ if(v.has_value)
+ {
+ BOOST_ASSERT(
+ end - 1 >= dest);
+ *dest++ = '=';
+ auto const vn =
+ v.value.size();
+ BOOST_ASSERT(
+ end - vn >= dest);
+ if(vn > 0)
+ {
+ std::memcpy(
+ dest,
+ v.value.data(),
+ vn);
+ dest += vn;
+ }
+ }
+}
+
+//------------------------------------------------
+//
+// param_value_iter
+//
//------------------------------------------------
void
@@ -298,6 +302,10 @@ copy(char*& it, char const* end) noexcept
detail::param_value_chars);
}
+//------------------------------------------------
+//
+// param_encoded_value_iter
+//
//------------------------------------------------
void
@@ -354,30 +362,6 @@ copy(char*& it, char const* end) noexcept
it += value_.size();
}
-//------------------------------------------------
-
-bool
-ci_decoded_key_equal(
- decode_view key,
- string_view match) noexcept
-{
- if( key.size() !=
- match.size())
- return false;
- auto it0 = key.begin();
- auto it1 = match.begin();
- auto const end = match.end();
- while(it1 != end)
- {
- if( grammar::to_lower(*it0) !=
- grammar::to_lower(*it1))
- return false;
- ++it0;
- ++it1;
- }
- return true;
-}
-
} // detail
} // urls
} // boost
diff --git a/include/boost/url/detail/impl/any_path_iter.ipp b/include/boost/url/detail/impl/any_path_iter.ipp
deleted file mode 100644
index 3d3d42de..00000000
--- a/include/boost/url/detail/impl/any_path_iter.ipp
+++ /dev/null
@@ -1,328 +0,0 @@
- //
-// Copyright (c) 2019 Vinnie Falco (vinnie.falco@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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_DETAIL_IMPL_ANY_PATH_ITER_IPP
-#define BOOST_URL_DETAIL_IMPL_ANY_PATH_ITER_IPP
-
-#include
-#include
-#include
-#include
-#include
-
-namespace boost {
-namespace urls {
-namespace detail {
-
-any_path_iter::
-~any_path_iter() noexcept = default;
-
-//------------------------------------------------
-
-void
-enc_path_iter::
-increment() noexcept
-{
- p_ += n_;
- if(p_ == end_)
- {
- p_ = nullptr;
- return;
- }
- ++p_;
- string_view s(p_, end_ - p_);
- auto pos = s.find_first_of('/');
- if(pos != string_view::npos)
- n_ = pos;
- else
- n_ = s.size();
-}
-
-enc_path_iter::
-enc_path_iter(
- string_view s) noexcept
- : end_(s.data() + s.size())
-{
- if(s.empty())
- {
- n_ = 0;
- p_ = nullptr;
- return;
- }
- std::size_t pos;
- if(s.starts_with('/'))
- s.remove_prefix(1);
- pos = s.find_first_of('/');
- p_ = s.data();
- if(pos != string_view::npos)
- n_ = pos;
- else
- n_ = s.size();
- front = { p_, n_ };
-}
-
-bool
-enc_path_iter::
-measure(
- std::size_t& n,
- error_code& ec) noexcept
-{
- if(! p_)
- return false;
- string_view s(p_, n_);
- auto rn = urls::decode(s, {}, pchars);
- if( !rn )
- {
- ec = rn.error();
- return false;
- }
- n += s.size();
- increment();
- return true;
-}
-
-void
-enc_path_iter::
-copy(
- char*& dest,
- char const* end) noexcept
-{
- (void)end;
- BOOST_ASSERT(static_cast<
- std::size_t>(
- end - dest) >= n_);
- BOOST_ASSERT(p_ != nullptr);
- if(n_ > 0)
- {
- std::memcpy(
- dest, p_, n_);
- dest += n_;
- }
- increment();
-}
-
-//------------------------------------------------
-
-void
-plain_path_iter::
-increment() noexcept
-{
- p_ += n_;
- if(p_ == end_)
- {
- p_ = nullptr;
- return;
- }
- ++p_;
- string_view s(p_, end_ - p_);
- auto pos = s.find_first_of('/');
- if(pos != string_view::npos)
- n_ = pos;
- else
- n_ = s.size();
-}
-
-plain_path_iter::
-plain_path_iter(
- string_view s) noexcept
- : end_(s.data() + s.size())
-{
- if(s.empty())
- {
- n_ = 0;
- p_ = nullptr;
- return;
- }
- std::size_t pos;
- if(s.starts_with('/'))
- s.remove_prefix(1);
- pos = s.find_first_of('/');
- p_ = s.data();
- if(pos != string_view::npos)
- n_ = pos;
- else
- n_ = s.size();
- front = { p_, n_ };
-}
-
-bool
-plain_path_iter::
-measure(
- std::size_t& n,
- error_code&) noexcept
-{
- if(! p_)
- return false;
- string_view s(p_, n_);
- n += urls::encoded_size(
- s, {}, pchars);
- increment();
- return true;
-}
-
-void
-plain_path_iter::
-copy(
- char*& dest,
- char const* end) noexcept
-{
- BOOST_ASSERT(p_ != nullptr);
- dest += encode(
- dest,
- end,
- string_view(p_, n_),
- {},
- pchars);
- increment();
-}
-
-//------------------------------------------------
-
-void
-view_path_iter::
-increment() noexcept
-{
- std::advance(p_, n_);
- if(p_ == end_)
- {
- done_ = true;
- return;
- }
- ++p_;
- auto pos = p_;
- n_ = 0;
- while (pos != end_)
- {
- if (*pos == '/')
- break;
- ++pos;
- ++n_;
- }
-}
-
-view_path_iter::
-view_path_iter(
- decode_view s) noexcept
- : n_(0)
- , end_(s.end())
-{
- if(s.empty())
- {
- p_ = s.end();
- done_ = true;
- return;
- }
- p_ = s.begin();
- if (!s.empty() && s.front() == '/')
- ++p_;
- auto pos = p_;
- while (pos != end_)
- {
- if (*pos == '/')
- break;
- ++pos;
- ++n_;
- }
- front = { p_.base(), pos.base() };
-}
-
-bool
-view_path_iter::
-measure(
- std::size_t& n,
- error_code&) noexcept
-{
- if (done_)
- return false;
- auto it = p_;
- auto end = std::next(p_, n_);
- n += encoded_size_impl(it, end, {}, pchars);
- increment();
- return true;
-}
-
-void
-view_path_iter::
-copy(
- char*& dest,
- char const* end) noexcept
-{
- BOOST_ASSERT(!done_);
- auto it = p_;
- auto last = std::next(p_, n_);
- dest += encode_impl(
- dest, end, it, last, {}, pchars);
- increment();
-}
-
-//------------------------------------------------
-
-bool
-enc_segs_iter_base::
-measure_impl(
- string_view s,
- std::size_t& n,
- error_code& ec) noexcept
-{
- auto rn = urls::decode(s, {}, pchars);
- if( !rn )
- {
- ec = rn.error();
- return false;
- }
- n += s.size();
- return true;
-}
-
-void
-enc_segs_iter_base::
-copy_impl(
- string_view s,
- char*& dest,
- char const* end) noexcept
-{
- (void)end;
- BOOST_ASSERT(static_cast<
- std::size_t>(end - dest) >=
- s.size());
- if(! s.empty())
- {
- std::memcpy(dest,
- s.data(), s.size());
- dest += s.size();
- }
-}
-
-//------------------------------------------------
-
-void
-plain_segs_iter_base::
-measure_impl(
- string_view s,
- std::size_t& n) noexcept
-{
- n += encoded_size(s, {}, pchars);
-}
-
-void
-plain_segs_iter_base::
-copy_impl(
- string_view s,
- char*& dest,
- char const* end) noexcept
-{
- dest += encode(
- dest, end, s, {}, pchars);
-}
-
-} // detail
-} // urls
-} // boost
-
-#endif
diff --git a/include/boost/url/detail/impl/any_segments_iter.ipp b/include/boost/url/detail/impl/any_segments_iter.ipp
new file mode 100644
index 00000000..27bcb0ab
--- /dev/null
+++ b/include/boost/url/detail/impl/any_segments_iter.ipp
@@ -0,0 +1,297 @@
+//
+// Copyright (c) 2019 Vinnie Falco (vinnie.falco@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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_DETAIL_IMPL_ANY_SEGMENTS_ITER_IPP
+#define BOOST_URL_DETAIL_IMPL_ANY_SEGMENTS_ITER_IPP
+
+#include
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace urls {
+namespace detail {
+
+//------------------------------------------------
+//
+// path_iter
+//
+//------------------------------------------------
+
+path_iter::
+path_iter(
+ string_view s) noexcept
+ : any_segments_iter(&s_)
+ , s_(clean(s))
+ , p0_(s.data())
+ , end_(s.data() + s.size())
+{
+ rewind();
+ front = { p_, n_ };
+}
+
+string_view
+path_iter::
+clean(string_view s) noexcept
+{
+ // prevent null
+ if(s.data() == nullptr)
+ return string_view("", 0);
+ return s;
+}
+
+void
+path_iter::
+increment() noexcept
+{
+ p_ += n_;
+ if(p_ == end_)
+ {
+ p_ = nullptr;
+ return;
+ }
+ ++p_;
+ string_view s(p_, end_ - p_);
+ auto pos = s.find_first_of('/');
+ if(pos != string_view::npos)
+ n_ = pos;
+ else
+ n_ = s.size();
+}
+
+void
+path_iter::
+rewind() noexcept
+{
+ if(p0_ != end_)
+ {
+ auto p0 = p0_;
+ if(*p0 == '/')
+ ++p0;
+ p_ = p0;
+ auto p = p0;
+ while(p != end_)
+ {
+ if(*p == '/')
+ break;
+ ++p;
+ }
+ n_ = p - p0;
+ }
+}
+
+bool
+path_iter::
+measure(
+ std::size_t& n) noexcept
+{
+ if(! p_)
+ return false;
+ string_view s(p_, n_);
+ n += urls::encoded_size(
+ s, {}, pchars);
+ increment();
+ return true;
+}
+
+void
+path_iter::
+copy(
+ char*& dest,
+ char const* end) noexcept
+{
+ BOOST_ASSERT(p_ != nullptr);
+ dest += encode(
+ dest,
+ end,
+ string_view(p_, n_),
+ {},
+ pchars);
+ increment();
+}
+
+//------------------------------------------------
+//
+// path_encoded_iter
+//
+//------------------------------------------------
+
+path_encoded_iter::
+path_encoded_iter(
+ pct_string_view s) noexcept
+ : any_segments_iter(&s_)
+ , s_(clean(s))
+ , p0_(s.data())
+ , end_(s.data() + s.size())
+{
+ rewind();
+ front = { p_, n_ };
+}
+
+string_view
+path_encoded_iter::
+clean(pct_string_view s) noexcept
+{
+ // prevent null
+ if(s.data() == nullptr)
+ return string_view("", 0);
+ return s;
+}
+
+void
+path_encoded_iter::
+increment() noexcept
+{
+ p_ += n_;
+ if(p_ == end_)
+ {
+ p_ = nullptr;
+ return;
+ }
+ ++p_;
+ string_view s(p_, end_ - p_);
+ auto pos = s.find_first_of('/');
+ if(pos != string_view::npos)
+ n_ = pos;
+ else
+ n_ = s.size();
+}
+
+void
+path_encoded_iter::
+rewind() noexcept
+{
+ if(p0_ != end_)
+ {
+ auto p0 = p0_;
+ if(*p0 == '/')
+ ++p0;
+ p_ = p0;
+ auto p = p0;
+ while(p != end_)
+ {
+ if(*p == '/')
+ break;
+ ++p;
+ }
+ n_ = p - p0;
+ }
+}
+
+bool
+path_encoded_iter::
+measure(
+ std::size_t& n) noexcept
+{
+ if(! p_)
+ return false;
+ string_view s(p_, n_);
+ encode_opts opt;
+ n += detail::re_encoded_size_unchecked(
+ s,
+ opt,
+ pchars);
+ increment();
+ return true;
+}
+
+void
+path_encoded_iter::
+copy(
+ char*& dest,
+ char const* end) noexcept
+{
+ (void)end;
+ BOOST_ASSERT(static_cast<
+ std::size_t>(
+ end - dest) >= n_);
+ BOOST_ASSERT(p_ != nullptr);
+ if(n_ > 0)
+ {
+ string_view s(p_, n_);
+ encode_opts opt;
+ detail::re_encode_unchecked(
+ dest,
+ end,
+ s,
+ opt,
+ pchars);
+ }
+ increment();
+}
+
+//------------------------------------------------
+//
+// segments_iter_base
+//
+//------------------------------------------------
+
+void
+segments_iter_base::
+measure_impl(
+ string_view s,
+ std::size_t& n) noexcept
+{
+ n += encoded_size(s, {}, pchars);
+}
+
+void
+segments_iter_base::
+copy_impl(
+ string_view s,
+ char*& dest,
+ char const* end) noexcept
+{
+ dest += encode(
+ dest, end, s, {}, pchars);
+}
+
+//------------------------------------------------
+//
+// segments_encoded_iter_base
+//
+//------------------------------------------------
+
+bool
+segments_encoded_iter_base::
+measure_impl(
+ pct_string_view s,
+ std::size_t& n) noexcept
+{
+ encode_opts opt;
+ n += detail::re_encoded_size_unchecked(
+ s,
+ opt,
+ pchars);
+ return true;
+}
+
+void
+segments_encoded_iter_base::
+copy_impl(
+ string_view s,
+ char*& dest,
+ char const* end) noexcept
+{
+ encode_opts opt;
+ detail::re_encode_unchecked(
+ dest,
+ end,
+ s,
+ opt,
+ pchars);
+}
+
+} // detail
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/detail/impl/segments_encoded_iterator_impl.ipp b/include/boost/url/detail/impl/segments_encoded_iterator_impl.ipp
deleted file mode 100644
index ca791874..00000000
--- a/include/boost/url/detail/impl/segments_encoded_iterator_impl.ipp
+++ /dev/null
@@ -1,131 +0,0 @@
-//
-// 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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_DETAIL_IMPL_SEGMENTS_ENCODED_ITERATOR_IMPL_IPP
-#define BOOST_URL_DETAIL_IMPL_SEGMENTS_ENCODED_ITERATOR_IMPL_IPP
-
-#include
-#include
-#include
-
-namespace boost {
-namespace urls {
-namespace detail {
-
-segments_encoded_iterator_impl::
-segments_encoded_iterator_impl(
- string_view s,
- std::size_t nseg) noexcept
- : begin_(s.data())
- , pos_(s.data())
- , next_(s.data())
- , end_(s.data() + s.size())
-{
- if(nseg == 0)
- {
- next_ = nullptr;
- return;
- }
- auto const n = path_prefix(s);
- begin_ += n;
- next_ += n;
- pos_ += n;
- auto const i = string_view(
- begin_, s.size() - n
- ).find_first_of('/');
- if(i != string_view::npos)
- next_ += i;
- else
- next_ = end_;
- s_ = string_view(
- pos_, next_ - pos_);
-}
-
-segments_encoded_iterator_impl::
-segments_encoded_iterator_impl(
- string_view s,
- std::size_t nseg,
- int) noexcept
- : i_(nseg)
- , begin_(s.data())
- , pos_(s.data() + s.size())
- , end_(s.data() + s.size())
-{
- auto const n = path_prefix(s);
- begin_ += n;
-}
-
-void
-segments_encoded_iterator_impl::
-increment() noexcept
-{
- BOOST_ASSERT(next_ != nullptr);
- ++i_;
- pos_ = next_;
- // "/" segment
- auto rv = grammar::parse(
- next_, end_,
- detail::slash_segment_rule);
- if( !rv )
- {
- next_ = nullptr;
- return;
- }
- s_ = *rv;
-}
-
-void
-segments_encoded_iterator_impl::
-decrement() noexcept
-{
- BOOST_ASSERT(i_ != 0);
- --i_;
- if(i_ == 0)
- {
- next_ = pos_;
- pos_ = begin_;
- s_ = string_view(
- pos_, next_ - pos_);
- return;
- }
- while(--pos_ != begin_)
- {
- if(*pos_ != '/')
- continue;
- // "/" segment
- next_ = pos_;
- s_ = *grammar::parse(
- next_, end_,
- detail::slash_segment_rule);
- return;
- }
- next_ = pos_;
- if(*next_ == '/')
- {
- // "/" segment
- s_ = *grammar::parse(
- next_, end_,
- detail::slash_segment_rule);
- }
- else
- {
- // segment-nz
- s_ = *grammar::parse(
- next_, end_,
- detail::slash_segment_rule);
- }
-}
-
-
-} // detail
-} // url
-} // boost
-
-#endif
diff --git a/include/boost/url/detail/impl/segments_iter_impl.ipp b/include/boost/url/detail/impl/segments_iter_impl.ipp
new file mode 100644
index 00000000..0249ade5
--- /dev/null
+++ b/include/boost/url/detail/impl/segments_iter_impl.ipp
@@ -0,0 +1,141 @@
+//
+// 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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_DETAIL_IMPL_SEGMENTS_ITER_IMPL_IPP
+#define BOOST_URL_DETAIL_IMPL_SEGMENTS_ITER_IMPL_IPP
+
+#include
+#include
+#include
+
+namespace boost {
+namespace urls {
+namespace detail {
+
+// begin
+segments_iter_impl::
+segments_iter_impl(
+ detail::path_ref const& ref_) noexcept
+ : ref(ref_)
+{
+ pos = path_prefix(ref.string());
+ auto const end = ref.end();
+ char const* const p0 =
+ ref.data() + pos;
+ auto p = p0;
+ //dn = 0;
+ while(p != end)
+ {
+ if(*p == '/')
+ break;
+ if(*p != '%')
+ {
+ ++p;
+ continue;
+ }
+ p += 3;
+ dn += 2;
+ }
+ next = p - ref.data();
+ dn = p - p0 - dn;
+ s_ = detail::make_pct_string_view(
+ p0, p - p0, dn);
+}
+
+// end
+segments_iter_impl::
+segments_iter_impl(
+ detail::path_ref const& ref_,
+ int) noexcept
+ : ref(ref_)
+ , pos(ref.size())
+ , next(ref.size())
+ , index(ref.nseg())
+{
+}
+
+void
+segments_iter_impl::
+increment() noexcept
+{
+ BOOST_ASSERT(
+ index != ref.nseg());
+ ++index;
+ pos = next;
+ if(index == ref.nseg())
+ return;
+ // "/" segment
+ auto const end = ref.end();
+ auto p = ref.data() + pos;
+ BOOST_ASSERT(p != end);
+ BOOST_ASSERT(*p == '/');
+ ++p;
+ dn = 0;
+ auto const p0 = p;
+ while(p != end)
+ {
+ if(*p == '/')
+ break;
+ if(*p != '%')
+ {
+ ++p;
+ continue;
+ }
+ p += 3;
+ dn += 2;
+ }
+ next = p - ref.data();
+ dn = p - p0 - dn;
+ s_ = detail::make_pct_string_view(
+ p0, p - p0, dn);
+}
+
+void
+segments_iter_impl::
+decrement() noexcept
+{
+ BOOST_ASSERT(index != 0);
+ --index;
+ if(index == 0)
+ {
+ next = pos;
+ pos = path_prefix(ref.string());
+ s_ = string_view(
+ ref.data() + pos,
+ next - pos);
+ BOOST_ASSERT(! s_.ends_with('/'));
+ return;
+ }
+ auto const begin = ref.data() +
+ path_prefix(ref.string());
+ next = pos;
+ auto p = ref.data() + next;
+ auto const p1 = p;
+ BOOST_ASSERT(p != begin);
+ dn = 0;
+ while(p != begin)
+ {
+ --p;
+ if(*p == '/')
+ break;
+ if(*p == '%')
+ dn += 2;
+ }
+ dn = p1 - p - dn;
+ pos = p - ref.data();
+ s_ = detail::make_pct_string_view(
+ p + 1, p1 - p - 1, dn);
+}
+
+} // detail
+} // url
+} // boost
+
+#endif
diff --git a/include/boost/url/detail/impl/segments_iterator_impl.ipp b/include/boost/url/detail/impl/segments_iterator_impl.ipp
deleted file mode 100644
index 25f26741..00000000
--- a/include/boost/url/detail/impl/segments_iterator_impl.ipp
+++ /dev/null
@@ -1,131 +0,0 @@
-//
-// 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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_DETAIL_IMPL_SEGMENTS_ITERATOR_IMPL_IPP
-#define BOOST_URL_DETAIL_IMPL_SEGMENTS_ITERATOR_IMPL_IPP
-
-#include
-#include
-#include
-
-namespace boost {
-namespace urls {
-namespace detail {
-
-segments_iterator_impl::
-segments_iterator_impl(
- string_view s,
- std::size_t nseg) noexcept
- : begin_(s.data())
- , pos_(s.data())
- , next_(s.data())
- , end_(s.data() + s.size())
-{
- if(nseg == 0)
- {
- next_ = nullptr;
- return;
- }
- auto const n = path_prefix(s);
- begin_ += n;
- next_ += n;
- pos_ += n;
- t_ = *grammar::parse(
- next_, end_, segment_rule);
-}
-
-segments_iterator_impl::
-segments_iterator_impl(
- string_view s,
- std::size_t nseg,
- int) noexcept
- : i_(nseg)
- , begin_(s.data() + path_prefix(s))
- , pos_(s.data() + s.size())
- , end_(s.data() + s.size())
-{
-}
-
-decode_view
-segments_iterator_impl::
-dereference() const noexcept
-{
- decode_opts opt;
- opt.plus_to_space = false;
- return t_.decoded(opt);
-}
-
-
-void
-segments_iterator_impl::
-increment() noexcept
-{
- BOOST_ASSERT(next_ != nullptr);
- ++i_;
- pos_ = next_;
- // "/" segment
- auto rv = grammar::parse(
- next_, end_,
- detail::slash_segment_rule);
- if(! rv )
- {
- next_ = nullptr;
- return;
- }
- t_ = *rv;
-}
-
-void
-segments_iterator_impl::
-decrement() noexcept
-{
- BOOST_ASSERT(i_ != 0);
- --i_;
- if(i_ == 0)
- {
- next_ = begin_;
- pos_ = begin_;
- t_ = *grammar::parse(
- next_, end_, segment_rule);
- return;
- }
- while(--pos_ != begin_)
- {
- if(*pos_ != '/')
- continue;
- // "/" segment
- next_ = pos_;
- t_ = *grammar::parse(
- next_, end_,
- detail::slash_segment_rule);
- return;
- }
- next_ = pos_;
- if(*next_ == '/')
- {
- // "/" segment
- t_ = *grammar::parse(
- next_, end_,
- detail::slash_segment_rule);
- }
- else
- {
- // segment-nz
- t_ = *grammar::parse(
- next_, end_,
- detail::slash_segment_rule);
- }
-}
-
-} // detail
-} // url
-} // boost
-
-#endif
diff --git a/include/boost/url/detail/impl/url_impl.ipp b/include/boost/url/detail/impl/url_impl.ipp
index 633f655f..d187bdd2 100644
--- a/include/boost/url/detail/impl/url_impl.ipp
+++ b/include/boost/url/detail/impl/url_impl.ipp
@@ -150,6 +150,72 @@ apply_frag(
decoded_[id_frag] = s.decoded_size();
}
+//------------------------------------------------
+
+path_ref::
+path_ref(
+ string_view s,
+ std::size_t dn,
+ std::size_t nseg) noexcept
+ : data_(s.data())
+ , size_(s.size())
+ , nseg_(nseg)
+ , dn_(dn)
+{
+}
+
+pct_string_view
+path_ref::
+string() const noexcept
+{
+ if(impl_)
+ return make_pct_string_view(
+ impl_->cs_ +
+ impl_->offset(id_path),
+ impl_->len(id_path),
+ impl_->decoded_[id_path]);
+ return make_pct_string_view(
+ data_, size_, dn_);
+}
+
+std::size_t
+path_ref::
+size() const noexcept
+{
+ if(impl_)
+ return impl_->len(id_path);
+ return size_;
+}
+
+char const*
+path_ref::
+data() const noexcept
+{
+ if(impl_)
+ return impl_->cs_ +
+ impl_->offset(id_path);
+ return data_;
+}
+
+char const*
+path_ref::
+end() const noexcept
+{
+ if(impl_)
+ return impl_->cs_ +
+ impl_->offset(id_query);
+ return data_ + size_;
+}
+
+std::size_t
+path_ref::
+nseg() const noexcept
+{
+ if(impl_)
+ return impl_->nseg_;
+ return nseg_;
+}
+
} // detail
} // urls
} // boost
diff --git a/include/boost/url/detail/path.hpp b/include/boost/url/detail/path.hpp
index f2c9b8c6..c0c7cf0d 100644
--- a/include/boost/url/detail/path.hpp
+++ b/include/boost/url/detail/path.hpp
@@ -21,42 +21,53 @@ namespace detail {
inline
std::size_t
path_prefix(
- string_view s) noexcept
+ char const* p,
+ std::size_t n) noexcept
{
- switch(s.size())
+ switch(n)
{
case 0:
return 0;
case 1:
- if(s[0] == '/')
+ if(p[0] == '/')
return 1;
return 0;
case 2:
- if(s[0] == '/')
+ if(p[0] == '/')
return 1;
- if( s[0] == '.' &&
- s[1] == '/')
+ if( p[0] == '.' &&
+ p[1] == '/')
return 2;
return 0;
default:
- if(s[0] == '/')
+ if(p[0] == '/')
{
- if( s[1] == '.' &&
- s[2] == '/')
+ if( p[1] == '.' &&
+ p[2] == '/')
return 3;
return 1;
}
- if( s[0] == '.' &&
- s[1] == '/')
+ if( p[0] == '.' &&
+ p[1] == '/')
return 2;
break;
}
return 0;
}
+// VFALCO DEPRECATED
+inline
+std::size_t
+path_prefix(
+ string_view s) noexcept
+{
+ return path_prefix(
+ s.data(), s.size());
+}
+
// returns the number of adjusted
// segments based on the malleable prefix.
inline
diff --git a/include/boost/url/detail/segments_encoded_iterator_impl.hpp b/include/boost/url/detail/segments_encoded_iterator_impl.hpp
deleted file mode 100644
index 99797eb4..00000000
--- a/include/boost/url/detail/segments_encoded_iterator_impl.hpp
+++ /dev/null
@@ -1,72 +0,0 @@
-//
-// 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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_DETAIL_SEGMENTS_ENCODED_ITERATOR_IMPL_HPP
-#define BOOST_URL_DETAIL_SEGMENTS_ENCODED_ITERATOR_IMPL_HPP
-
-#include
-#include
-
-namespace boost {
-namespace urls {
-namespace detail {
-
-struct segments_encoded_iterator_impl
-{
- std::size_t i_ = 0;
- string_view s_;
- char const* begin_ = nullptr;
- char const* pos_ = nullptr;
- char const* next_ = nullptr;
- char const* end_ = nullptr;
-
- BOOST_URL_DECL
- segments_encoded_iterator_impl(
- string_view s,
- std::size_t nseg) noexcept;
-
- // end ctor
- BOOST_URL_DECL
- segments_encoded_iterator_impl(
- string_view s,
- std::size_t nseg,
- int) noexcept;
-
- segments_encoded_iterator_impl() = default;
-
- segments_encoded_iterator_impl(
- segments_encoded_iterator_impl const&) noexcept = default;
-
- segments_encoded_iterator_impl& operator=(
- segments_encoded_iterator_impl const&) noexcept = default;
-
- BOOST_URL_DECL
- void
- increment() noexcept;
-
- BOOST_URL_DECL
- void
- decrement() noexcept;
-
- bool
- equal(
- segments_encoded_iterator_impl const& other) const noexcept
- {
- return
- next_ == other.next_ &&
- end_ == other.end_;
- }
-};
-
-} // detail
-} // urls
-} // boost
-
-#endif
diff --git a/include/boost/url/detail/segments_iter_impl.hpp b/include/boost/url/detail/segments_iter_impl.hpp
new file mode 100644
index 00000000..0671301a
--- /dev/null
+++ b/include/boost/url/detail/segments_iter_impl.hpp
@@ -0,0 +1,79 @@
+//
+// 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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_DETAIL_SEGMENTS_ITER_IMPL_HPP
+#define BOOST_URL_DETAIL_SEGMENTS_ITER_IMPL_HPP
+
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace urls {
+namespace detail {
+
+struct segments_iter_impl
+ : private parts_base
+{
+ path_ref ref;
+ std::size_t pos = 0;
+ std::size_t next = 0;
+ std::size_t index = 0;
+ std::size_t dn = 0;
+private:
+ pct_string_view s_;
+public:
+
+ segments_iter_impl() = default;
+ segments_iter_impl(
+ segments_iter_impl const&) noexcept = default;
+ segments_iter_impl& operator=(
+ segments_iter_impl const&) noexcept = default;
+
+ // begin
+ BOOST_URL_DECL
+ segments_iter_impl(
+ detail::path_ref const&) noexcept;
+
+ // end
+ BOOST_URL_DECL
+ segments_iter_impl(
+ detail::path_ref const&,
+ int) noexcept;
+
+ BOOST_URL_DECL
+ void
+ increment() noexcept;
+
+ BOOST_URL_DECL
+ void
+ decrement() noexcept;
+
+ pct_string_view
+ dereference() const noexcept
+ {
+ return s_;
+ }
+
+ bool
+ equal(
+ segments_iter_impl const& other) const noexcept
+ {
+ BOOST_ASSERT(ref.alias_of(other.ref));
+ return index == other.index;
+ }
+};
+
+} // detail
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/detail/segments_iterator_impl.hpp b/include/boost/url/detail/segments_iterator_impl.hpp
deleted file mode 100644
index 43ab293a..00000000
--- a/include/boost/url/detail/segments_iterator_impl.hpp
+++ /dev/null
@@ -1,78 +0,0 @@
-//
-// 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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_DETAIL_SEGMENTS_ITERATOR_IMPL_HPP
-#define BOOST_URL_DETAIL_SEGMENTS_ITERATOR_IMPL_HPP
-
-#include
-#include
-#include
-#include
-
-namespace boost {
-namespace urls {
-namespace detail {
-
-struct segments_iterator_impl
-{
- std::size_t i_ = 0;
- char const* begin_ = nullptr;
- char const* pos_ = nullptr;
- char const* next_ = nullptr;
- char const* end_ = nullptr;
- pct_string_view t_;
-
- BOOST_URL_DECL
- segments_iterator_impl(
- string_view s,
- std::size_t nseg) noexcept;
-
- // end ctor
- BOOST_URL_DECL
- segments_iterator_impl(
- string_view s,
- std::size_t nseg,
- int) noexcept;
-
- segments_iterator_impl() = default;
-
- segments_iterator_impl(
- segments_iterator_impl const&) noexcept = default;
-
- segments_iterator_impl& operator=(
- segments_iterator_impl const&) noexcept = default;
-
- BOOST_URL_DECL
- decode_view
- dereference() const noexcept;
-
- BOOST_URL_DECL
- void
- increment() noexcept;
-
- BOOST_URL_DECL
- void
- decrement() noexcept;
-
- bool
- equal(
- segments_iterator_impl const& other) const noexcept
- {
- return
- next_ == other.next_ &&
- end_ == other.end_;
- }
-};
-
-} // detail
-} // urls
-} // boost
-
-#endif
diff --git a/include/boost/url/detail/url_impl.hpp b/include/boost/url/detail/url_impl.hpp
index e53b5d6c..2de19c1c 100644
--- a/include/boost/url/detail/url_impl.hpp
+++ b/include/boost/url/detail/url_impl.hpp
@@ -76,6 +76,8 @@ struct url_impl : parts_base
pos_t offset(int) const noexcept;
string_view get(int) const noexcept;
string_view get(int, int) const noexcept;
+ pct_string_view pct_get(int) const noexcept;
+ pct_string_view pct_get(int, int) const noexcept;
void set_size(int, pos_t) noexcept;
void split(int, std::size_t) noexcept;
void adjust(int, int, std::size_t) noexcept;
@@ -95,6 +97,56 @@ struct url_impl : parts_base
//------------------------------------------------
+// this allows a path to come from a
+// url_impl or a separate string_view
+class path_ref
+ : private parts_base
+{
+ url_impl const* impl_ = nullptr;
+ char const* data_ = nullptr;
+ std::size_t size_ = 0;
+ std::size_t nseg_ = 0;
+ std::size_t dn_ = 0;
+
+public:
+ path_ref() = default;
+ path_ref(string_view,
+ std::size_t, std::size_t) noexcept;
+ pct_string_view string() const noexcept;
+ std::size_t size() const noexcept;
+ char const* data() const noexcept;
+ char const* end() const noexcept;
+ std::size_t nseg() const noexcept;
+
+ path_ref(
+ url_impl const& impl) noexcept
+ : impl_(&impl)
+ {
+ }
+
+ bool
+ alias_of(
+ url_impl const& impl) const noexcept
+ {
+ return impl_ == &impl;
+ }
+
+ bool
+ alias_of(
+ path_ref const& ref) const noexcept
+ {
+ if(impl_)
+ return impl_ == ref.impl_;
+ BOOST_ASSERT(data_ != ref.data_ || (
+ size_ == ref.size_ &&
+ nseg_ == ref.nseg_ &&
+ dn_ == ref.dn_));
+ return data_ == ref.data_;
+ }
+};
+
+//------------------------------------------------
+
// return length of [first, last)
inline
auto
@@ -156,6 +208,37 @@ get(int first,
offset(last) - offset(first) };
}
+// return id as pct-string
+inline
+pct_string_view
+url_impl::
+pct_get(
+ int id) const noexcept
+{
+ return make_pct_string_view(
+ cs_ + offset(id),
+ len(id),
+ decoded_[id]);
+}
+
+// return [first, last) as pct-string
+inline
+pct_string_view
+url_impl::
+pct_get(
+ int first,
+ int last) const noexcept
+{
+ auto const pos = offset(first);
+ std::size_t n = 0;
+ for(auto i = first; i < last;)
+ n += decoded_[i++];
+ return make_pct_string_view(
+ cs_ + pos,
+ offset(last) - pos,
+ n);
+}
+
//------------------------------------------------
// change id to size n
diff --git a/include/boost/url/grammar/detail/copied_strings.hpp b/include/boost/url/grammar/detail/copied_strings.hpp
deleted file mode 100644
index c3437bfe..00000000
--- a/include/boost/url/grammar/detail/copied_strings.hpp
+++ /dev/null
@@ -1,149 +0,0 @@
-//
-// Copyright (c) 2019 Vinnie Falco (vinnie.falco@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/vinniefalco/http_proto
-//
-
-#ifndef BOOST_URL_GRAMMAR_DETAIL_COPIED_STRINGS_HPP
-#define BOOST_URL_GRAMMAR_DETAIL_COPIED_STRINGS_HPP
-
-#include
-#include
-#include
-
-namespace boost {
-namespace urls {
-namespace grammar {
-namespace detail {
-
-/** Common functionality for copied strings
-
- This base class is used by the library
- to provide the functionality for copied
- strings.
- Users should not use this class directly.
- Instead, construct an instance of
- @ref copied_strings instead.
-*/
-class copied_strings_base
-{
-public:
- /** Destructor
-
- Destruction invalidates any strings
- previously returned by this object.
- */
- BOOST_URL_DECL
- ~copied_strings_base();
-
- /** Return a string, or a copy if it overlaps the protected buffer
-
- This function checks if the passed string
- view overlaps the protected character buffer
- set on construction. If there is no overlap,
- the same view is returned. However if the
- character buffer would overlap, then a copy
- is returned instead.
- */
- BOOST_URL_DECL
- string_view
- maybe_copy(
- string_view s);
-
-private:
- template
- friend class copied_strings;
-
- struct dynamic_buf
- {
- dynamic_buf* next;
- };
-
- bool
- is_overlapping(
- string_view s) const noexcept;
-
- /** Constructor
- */
- BOOST_URL_DECL
- copied_strings_base(
- string_view s,
- char* local_buf,
- std::size_t local_size) noexcept;
-
- string_view s_;
- char* local_buf_;
- std::size_t local_remain_;
- dynamic_buf* dynamic_list_ = nullptr;
-};
-
-//------------------------------------------------
-
-/** Helper to copy strings if they overlap a protected character buffer
-
- Objects of this type are declared on the
- stack as local variables in functions which
- accept @ref string_view parameters that
- modify an underlying character buffer. The
- purpose is to make a copy of the parameter
- if the parameter overlaps the protected
- character buffer.
-
- @par Example
- In this example we implement the append
- member function. The use of copied strings
- handles the case where the passed string `s`
- points into `s_`.
- @code
- struct container
- {
- std::string s_;
-
- void append( string_view s )
- {
- copied_strings<4096> cs( s_ );
- s = cs.maybe_copy( s );
- s_.append( s.data(), s.size() );
- }
- };
- @endcode
-
- @tparam BufferSize The number of bytes of
- inline storage. This is how many characters
- can be copied before dynamic allocation is
- required.
-*/
-template<
- std::size_t BufferSize>
-class copied_strings
- : public copied_strings_base
-{
- char buf_[BufferSize];
-
-public:
- /** Constructor
-
- This constructs storage for copying
- strings that overlap the protected
- character buffer.
-
- @param s The character buffer to protect
- */
- explicit
- copied_strings(
- string_view s) noexcept
- : copied_strings_base(
- s, buf_, sizeof(buf_))
- {
- }
-};
-
-} // detail
-} // grammar
-} // urls
-} // boost
-
-#endif
diff --git a/include/boost/url/grammar/detail/impl/copied_strings.ipp b/include/boost/url/grammar/detail/impl/copied_strings.ipp
deleted file mode 100644
index ab4ad7de..00000000
--- a/include/boost/url/grammar/detail/impl/copied_strings.ipp
+++ /dev/null
@@ -1,99 +0,0 @@
-//
-// Copyright (c) 2019 Vinnie Falco (vinnie.falco@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/vinniefalco/http_proto
-//
-
-#ifndef BOOST_URL_GRAMMAR_DETAIL_IMPL_COPIED_STRINGS_IPP
-#define BOOST_URL_GRAMMAR_DETAIL_IMPL_COPIED_STRINGS_IPP
-
-#include
-#include
-
-namespace boost {
-namespace urls {
-namespace grammar {
-namespace detail {
-
-bool
-copied_strings_base::
-is_overlapping(
- string_view s) const noexcept
-{
- auto const b1 = s_.data();
- auto const e1 = b1 + s_.size();
- auto const b2 = s.data();
- auto const e2 = b2 + s.size();
- auto const less_equal =
- std::less_equal();
- if(less_equal(e1, b2))
- return false;
- if(less_equal(e2, b1))
- return false;
- return true;
-}
-
-copied_strings_base::
-~copied_strings_base()
-{
- while(dynamic_list_)
- {
- auto p = dynamic_list_;
- dynamic_list_ =
- dynamic_list_->next;
- delete[] p;
- }
-}
-
-copied_strings_base::
-copied_strings_base(
- string_view s,
- char* local_buf,
- std::size_t local_size) noexcept
- : s_(s)
- , local_buf_(local_buf)
- , local_remain_(local_size)
-{
-}
-
-string_view
-copied_strings_base::
-maybe_copy(
- string_view s)
-{
- if(! is_overlapping(s))
- return s;
- if(local_remain_ >= s.size())
- {
- std::memcpy(local_buf_,
- s.data(), s.size());
- s = string_view(
- local_buf_, s.size());
- local_buf_ += s.size();
- local_remain_ -= s.size();
- return s;
- }
- auto const n =
- sizeof(dynamic_buf);
- auto p = new dynamic_buf[1 +
- sizeof(n) * ((s.size() +
- sizeof(n) - 1) /
- sizeof(n))];
- std::memcpy(p + 1,
- s.data(), s.size());
- s = string_view(reinterpret_cast<
- char const*>(p + 1), s.size());
- p->next = dynamic_list_;
- dynamic_list_ = p;
- return s;
-}
-
-} // detail
-} // grammar
-} // urls
-} // boost
-
-#endif
diff --git a/include/boost/url/impl/decode_view.ipp b/include/boost/url/impl/decode_view.ipp
index 6052f1e0..d2577cff 100644
--- a/include/boost/url/impl/decode_view.ipp
+++ b/include/boost/url/impl/decode_view.ipp
@@ -11,7 +11,6 @@
#define BOOST_URL_IMPL_PCT_ENCODED_VIEW_IPP
#include
-#include
#include
namespace boost {
@@ -66,22 +65,6 @@ decode_view(
s, opt).value(BOOST_URL_POS);
}
-#if 0
-decode_view
-decode_view::
-maybe_copy(
- grammar::detail::copied_strings_base& sp) const
-{
- decode_opts opt;
- opt.plus_to_space =
- plus_to_space_;
- return decode_view(
- sp.maybe_copy(encoded()),
- dn_,
- opt);
-}
-#endif
-
//------------------------------------------------
auto
diff --git a/include/boost/url/impl/params_encoded_view.ipp b/include/boost/url/impl/params_encoded_view.ipp
index 50699228..b12b54d0 100644
--- a/include/boost/url/impl/params_encoded_view.ipp
+++ b/include/boost/url/impl/params_encoded_view.ipp
@@ -29,8 +29,8 @@ namespace urls {
std::size_t
params_encoded_view::
erase(
- string_view key,
- ignore_case_param ic)
+ pct_string_view key,
+ ignore_case_param ic) noexcept
{
// VFALCO we can't cache end() here
// because it will be invalidated
diff --git a/include/boost/url/impl/parse_path.ipp b/include/boost/url/impl/parse_path.ipp
new file mode 100644
index 00000000..903c165d
--- /dev/null
+++ b/include/boost/url/impl/parse_path.ipp
@@ -0,0 +1,66 @@
+//
+// 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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_IMPL_PARSE_PATH_IPP
+#define BOOST_URL_IMPL_PARSE_PATH_IPP
+
+#include
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace urls {
+
+result
+parse_path(string_view s) noexcept
+{
+ if(s.empty())
+ return segments_encoded_view(
+ detail::path_ref(s, 0, 0));
+ if(s[0] == '/')
+ {
+ auto rv = grammar::parse(
+ s, detail::path_abempty_rule);
+ if(! rv)
+ return rv.error();
+
+ // VFALCO We are needlessly recalculating
+ // the decoded size here.
+ return segments_encoded_view(
+ detail::path_ref(
+ rv->string(),
+ detail::decode_bytes_unchecked(
+ rv->string()),
+ detail::path_segments(
+ rv->string(),
+ rv->size())));
+ }
+ {
+ auto rv = grammar::parse(
+ s, detail::path_rootless_rule);
+ if(! rv)
+ return rv.error();
+ return segments_encoded_view(
+ detail::path_ref(
+ rv->string(),
+ detail::decode_bytes_unchecked(
+ rv->string()),
+ detail::path_segments(
+ rv->string(),
+ rv->size())));
+ }
+}
+
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/impl/segments.hpp b/include/boost/url/impl/segments.hpp
deleted file mode 100644
index b201e4ab..00000000
--- a/include/boost/url/impl/segments.hpp
+++ /dev/null
@@ -1,403 +0,0 @@
-//
-// 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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_IMPL_SEGMENTS_HPP
-#define BOOST_URL_IMPL_SEGMENTS_HPP
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace boost {
-namespace urls {
-
-//------------------------------------------------
-
-class segments::iterator
-{
- detail::segments_iterator_impl impl_;
-
- friend class segments;
-
- iterator(
- string_view s,
- std::size_t nseg) noexcept
- : impl_(s, nseg)
- {
- }
-
- // end ctor
- iterator(
- string_view s,
- std::size_t nseg,
- int) noexcept
- : impl_(s, nseg, 0)
- {
- }
-
-public:
- using value_type = std::string;
- using reference = decode_view;
- using pointer = void const*;
- using difference_type = std::ptrdiff_t;
- using iterator_category =
- std::bidirectional_iterator_tag;
-
- iterator() noexcept = default;
-
- iterator(iterator const&) noexcept = default;
-
- iterator&
- operator=(iterator const&) noexcept = default;
-
- reference
- operator*() const noexcept
- {
- return impl_.dereference();
- }
-
- iterator&
- operator++() noexcept
- {
- impl_.increment();
- return *this;
- }
-
- iterator&
- operator--() noexcept
- {
- impl_.decrement();
- return *this;
- }
-
- iterator
- operator++(int) noexcept
- {
- auto tmp = *this;
- ++*this;
- return tmp;
- }
-
- iterator
- operator--(int) noexcept
- {
- auto tmp = *this;
- --*this;
- return tmp;
- }
-
- bool
- operator==(
- iterator const& other) const noexcept
- {
- return impl_.equal(other.impl_);
- }
-
- bool
- operator!=(
- iterator const& other) const noexcept
- {
- return !impl_.equal(other.impl_);
- }
-};
-
-//------------------------------------------------
-//
-// Members
-//
-//------------------------------------------------
-
-inline
-bool
-segments::
-is_absolute() const noexcept
-{
- return
- u_->u_.len(id_path) != 0 &&
- u_->s_[u_->u_.offset(id_path)] == '/';
-}
-
-inline
-segments&
-segments::
-operator=(std::initializer_list<
- string_view> init)
-{
- assign(init.begin(), init.end());
- return *this;
-}
-
-template
-auto
-segments::
-assign(FwdIt first, FwdIt last) ->
- typename std::enable_if<
- std::is_convertible::reference,
- string_view>::value>::type
-{
- u_->edit_segments(
- 0,
- size(),
- detail::make_plain_segs_iter(
- first, last),
- detail::make_plain_segs_iter(
- first, last));
-}
-
-//------------------------------------------------
-//
-// Element Access
-//
-//------------------------------------------------
-
-inline
-auto
-segments::
-front() const ->
- decode_view
-{
- BOOST_ASSERT(! empty());
- return *begin();
-}
-
-inline
-auto
-segments::
-back() const ->
- decode_view
-{
- BOOST_ASSERT(! empty());
- return *std::prev(end());
-}
-
-//------------------------------------------------
-//
-// Iterators
-//
-//------------------------------------------------
-
-inline
-auto
-segments::
-begin() const noexcept ->
- iterator
-{
- return iterator(
- u_->encoded_path(), u_->u_.nseg_);
-}
-
-inline
-auto
-segments::
-end() const noexcept ->
- iterator
-{
- return iterator(
- u_->encoded_path(), u_->u_.nseg_, 0);
-}
-
-//------------------------------------------------
-//
-// Capacity
-//
-//------------------------------------------------
-
-inline
-bool
-segments::
-empty() const noexcept
-{
- return size() == 0;
-}
-
-inline
-std::size_t
-segments::
-size() const noexcept
-{
- return u_->u_.nseg_;
-}
-
-//------------------------------------------------
-//
-// Modifiers
-//
-//------------------------------------------------
-
-inline
-void
-segments::
-clear() noexcept
-{
- erase(begin(), end());
-}
-
-//------------------------------------------------
-
-inline
-auto
-segments::
-insert(
- iterator before,
- std::initializer_list<
- string_view> init) ->
- iterator
-{
- return insert(
- before,
- init.begin(),
- init.end());
-}
-
-template
-auto
-segments::
-insert(
- iterator before,
- FwdIt first,
- FwdIt last) ->
- typename std::enable_if<
- std::is_convertible::reference,
- string_view>::value,
- iterator>::type
-{
- return insert(before, first, last,
- typename std::iterator_traits<
- FwdIt>::iterator_category{});
-}
-
-template
-auto
-segments::
-insert(
- iterator before,
- FwdIt first,
- FwdIt last,
- std::forward_iterator_tag) ->
- iterator
-{
- u_->edit_segments(
- before.impl_.i_,
- before.impl_.i_,
- detail::make_plain_segs_iter(
- first, last),
- detail::make_plain_segs_iter(
- first, last));
- return std::next(begin(), before.impl_.i_);
-}
-
-//------------------------------------------------
-
-inline
-auto
-segments::
-replace(
- iterator pos,
- string_view s) ->
- iterator
-{
- return replace(
- pos, std::next(pos),
- &s, &s + 1);
-}
-
-inline
-auto
-segments::
-replace(
- iterator from,
- iterator to,
- std::initializer_list<
- string_view> init) ->
- iterator
-{
- return replace(
- from,
- to,
- init.begin(),
- init.end());
-}
-
-template
-auto
-segments::
-replace(
- iterator from,
- iterator to,
- FwdIt first,
- FwdIt last) ->
- typename std::enable_if<
- std::is_convertible::reference,
- string_view>::value,
- iterator>::type
-{
- BOOST_ASSERT(from.impl_.begin_ >= u_->string().data());
- BOOST_ASSERT(from.impl_.end_ <= u_->string().data() +
- u_->string().size());
- BOOST_ASSERT(to.impl_.begin_ >= u_->string().data());
- BOOST_ASSERT(to.impl_.end_ >= u_->string().data() +
- u_->string().size());
- u_->edit_segments(
- from.impl_.i_,
- to.impl_.i_,
- detail::make_plain_segs_iter(
- first, last),
- detail::make_plain_segs_iter(
- first, last));
- return std::next(begin(), from.impl_.i_);
-}
-
-//------------------------------------------------
-
-inline
-auto
-segments::
-erase(
- iterator pos) noexcept ->
- iterator
-{
- return erase(pos, std::next(pos));
-}
-
-//------------------------------------------------
-
-inline
-void
-segments::
-push_back(
- string_view s)
-{
- insert(end(), s);
-}
-
-inline
-void
-segments::
-pop_back() noexcept
-{
- erase(std::prev(end()));
-}
-
-} // urls
-} // boost
-
-#endif
diff --git a/include/boost/url/impl/segments.ipp b/include/boost/url/impl/segments.ipp
deleted file mode 100644
index 3c421379..00000000
--- a/include/boost/url/impl/segments.ipp
+++ /dev/null
@@ -1,81 +0,0 @@
-//
-// 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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_IMPL_SEGMENTS_IPP
-#define BOOST_URL_IMPL_SEGMENTS_IPP
-
-#include
-#include
-#include
-#include
-
-namespace boost {
-namespace urls {
-
-//------------------------------------------------
-//
-// Modifiers
-//
-//------------------------------------------------
-
-auto
-segments::
-insert(
- iterator before,
- string_view s) ->
- iterator
-{
- BOOST_ASSERT(
- before.impl_.pos_ >=
- u_->string().data());
- BOOST_ASSERT(
- before.impl_.pos_ <=
- u_->string().data() +
- u_->string().size());
- grammar::detail::copied_strings<
- BOOST_URL_STACK_BYTES> cs(
- u_->string());
- s = cs.maybe_copy(s);
- u_->edit_segments(
- before.impl_.i_,
- before.impl_.i_,
- detail::make_plain_segs_iter(
- &s, &s + 1),
- detail::make_plain_segs_iter(
- &s, &s + 1));
- return std::next(begin(), before.impl_.i_);
-}
-
-auto
-segments::
-segments::
-erase(
- iterator first,
- iterator last) noexcept ->
- iterator
-{
- BOOST_ASSERT(first.impl_.pos_ >= u_->string().data());
- BOOST_ASSERT(last.impl_.pos_ >= u_->string().data());
- BOOST_ASSERT(first.impl_.pos_ <= u_->string().data() +
- u_->string().size());
- BOOST_ASSERT(last.impl_.pos_ <= u_->string().data() +
- u_->string().size());
- string_view s;
- u_->edit_segments(
- first.impl_.i_, last.impl_.i_,
- detail::make_enc_segs_iter(&s, &s),
- detail::make_enc_segs_iter(&s, &s));
- return std::next(begin(), first.impl_.i_);
-}
-
-} // urls
-} // boost
-
-#endif
diff --git a/include/boost/url/impl/segments_base.hpp b/include/boost/url/impl/segments_base.hpp
new file mode 100644
index 00000000..3cee838d
--- /dev/null
+++ b/include/boost/url/impl/segments_base.hpp
@@ -0,0 +1,128 @@
+//
+// 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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_IMPL_SEGMENTS_BASE_HPP
+#define BOOST_URL_IMPL_SEGMENTS_BASE_HPP
+
+#include
+#include
+
+namespace boost {
+namespace urls {
+
+class segments_base::iterator
+{
+ detail::segments_iter_impl it_;
+ mutable grammar::recycled_ptr<
+ std::string> s_ = nullptr;
+ mutable bool valid_ = false;
+
+ friend class segments_base;
+ friend class segments_ref;
+
+ iterator(detail::path_ref const&) noexcept;
+ iterator(detail::path_ref const&, int) noexcept;
+ iterator(detail::segments_iter_impl const& it) noexcept
+ : it_(it)
+ {
+ }
+
+ BOOST_URL_DECL
+ string_view
+ dereference() const;
+
+public:
+ using value_type = std::string;
+ using reference = string_view;
+ using pointer = string_view;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category =
+ std::bidirectional_iterator_tag;
+
+ iterator() = default;
+ iterator(iterator const&) = default;
+ iterator& operator=(
+ iterator const&) = default;
+
+ reference
+ operator*() const
+ {
+ return dereference();
+ }
+
+ struct arrow_proxy
+ {
+ string_view s;
+
+ string_view const*
+ operator->()
+ {
+ return &s;
+ }
+ };
+
+ arrow_proxy
+ operator->() const
+ {
+ return arrow_proxy{
+ dereference()};
+ }
+
+ iterator&
+ operator++() noexcept
+ {
+ valid_ = false;
+ it_.increment();
+ return *this;
+ }
+
+ iterator&
+ operator--() noexcept
+ {
+ valid_ = false;
+ it_.decrement();
+ return *this;
+ }
+
+ iterator
+ operator++(int) noexcept
+ {
+ auto tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ iterator
+ operator--(int) noexcept
+ {
+ auto tmp = *this;
+ --*this;
+ return tmp;
+ }
+
+ bool
+ operator==(
+ iterator const& other) const noexcept
+ {
+ return it_.equal(other.it_);
+ }
+
+ bool
+ operator!=(
+ iterator const& other) const noexcept
+ {
+ return ! it_.equal(other.it_);
+ }
+};
+
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/impl/segments_base.ipp b/include/boost/url/impl/segments_base.ipp
new file mode 100644
index 00000000..d816c5ef
--- /dev/null
+++ b/include/boost/url/impl/segments_base.ipp
@@ -0,0 +1,122 @@
+//
+// 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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_IMPL_SEGMENTS_BASE_IPP
+#define BOOST_URL_IMPL_SEGMENTS_BASE_IPP
+
+#include
+
+namespace boost {
+namespace urls {
+
+string_view
+segments_base::
+iterator::
+dereference() const
+{
+ if(! valid_)
+ {
+ // VFALCO This could be better,
+ // we should never shrink size() for
+ // a recycled std::string, because
+ // otherwise when we resize it larger
+ // we will again have to value-init (?)
+ // the new chars.
+ s_.acquire();
+ (*it_.dereference()).assign_to(*s_);
+ valid_ = true;
+ }
+ return *s_;
+}
+
+// begin
+segments_base::
+iterator::
+iterator(
+ detail::path_ref const& ref) noexcept
+ : it_(ref)
+{
+}
+
+// end
+segments_base::
+iterator::
+iterator(
+ detail::path_ref const& ref,
+ int) noexcept
+ : it_(ref, 0)
+{
+}
+
+//------------------------------------------------
+
+pct_string_view
+segments_base::
+buffer() const noexcept
+{
+ return ref_.string();
+}
+
+bool
+segments_base::
+is_absolute() const noexcept
+{
+ return ref_.string().starts_with('/');
+}
+
+bool
+segments_base::
+empty() const noexcept
+{
+ return ref_.nseg() == 0;
+}
+
+std::size_t
+segments_base::
+size() const noexcept
+{
+ return ref_.nseg();
+}
+
+std::string
+segments_base::
+front() const noexcept
+{
+ BOOST_ASSERT(! empty());
+ return *begin();
+}
+
+std::string
+segments_base::
+back() const noexcept
+{
+ BOOST_ASSERT(! empty());
+ return *--end();
+}
+
+auto
+segments_base::
+begin() const noexcept ->
+ iterator
+{
+ return iterator(ref_);
+}
+
+auto
+segments_base::
+end() const noexcept ->
+ iterator
+{
+ return iterator(ref_, 0);
+}
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/impl/segments_encoded.hpp b/include/boost/url/impl/segments_encoded.hpp
deleted file mode 100644
index 8bd77b5a..00000000
--- a/include/boost/url/impl/segments_encoded.hpp
+++ /dev/null
@@ -1,373 +0,0 @@
-//
-// 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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_IMPL_SEGMENTS_ENCODED_HPP
-#define BOOST_URL_IMPL_SEGMENTS_ENCODED_HPP
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace boost {
-namespace urls {
-
-class segments_encoded::iterator
-{
- friend class segments_encoded;
-
- detail::segments_encoded_iterator_impl impl_;
-
- iterator(
- string_view s,
- std::size_t nseg) noexcept
- : impl_(s, nseg)
- {
- }
-
- // end ctor
- iterator(
- string_view s,
- std::size_t nseg,
- int) noexcept
- : impl_(s, nseg, 0)
- {
- }
-
-public:
- using value_type = std::string;
- using reference = string_view;
- using pointer = void const*;
- using difference_type = std::ptrdiff_t;
- using iterator_category =
- std::bidirectional_iterator_tag;
-
- iterator() = default;
-
- iterator(iterator const&) noexcept = default;
-
- iterator& operator=(iterator const&) noexcept = default;
-
- reference
- operator*() const noexcept
- {
- return impl_.s_;
- }
-
- iterator&
- operator++() noexcept
- {
- impl_.increment();
- return *this;
- }
-
- iterator&
- operator--() noexcept
- {
- impl_.decrement();
- return *this;
- }
-
- iterator
- operator++(int) noexcept
- {
- auto tmp = *this;
- ++*this;
- return tmp;
- }
-
- iterator
- operator--(int) noexcept
- {
- auto tmp = *this;
- --*this;
- return tmp;
- }
-
- bool
- operator==(
- iterator const& other) const noexcept
- {
- return impl_.equal(other.impl_);
- }
-
- bool
- operator!=(
- iterator const& other) const noexcept
- {
- return !impl_.equal(other.impl_);
- }
-};
-
-//------------------------------------------------
-//
-// Members
-//
-//------------------------------------------------
-
-inline
-segments_encoded::
-segments_encoded(
- url_base& u) noexcept
- : u_(&u)
-{
-}
-
-inline
-bool
-segments_encoded::
-is_absolute() const noexcept
-{
- return
- u_->u_.len(id_path) != 0 &&
- u_->s_[u_->u_.offset(id_path)] == '/';
-}
-
-inline
-segments_encoded&
-segments_encoded::
-operator=(std::initializer_list init)
-{
- assign( init.begin(), init.end() );
- return *this;
-}
-
-template
-auto
-segments_encoded::
-assign(
- FwdIt first, FwdIt last) ->
- typename std::enable_if<
- std::is_convertible::reference,
- string_view>::value>::type
-{
- u_->edit_segments(
- 0,
- size(),
- detail::make_enc_segs_iter(first, last),
- detail::make_enc_segs_iter(first, last));
-}
-
-//------------------------------------------------
-//
-// Element Access
-//
-//------------------------------------------------
-
-inline
-string_view
-segments_encoded::
-front() const noexcept
-{
- BOOST_ASSERT(!empty());
- return *begin();
-}
-
-inline
-string_view
-segments_encoded::
-back() const noexcept
-{
- BOOST_ASSERT(! empty());
- return *std::prev(end());
-}
-
-//------------------------------------------------
-//
-// Capacity
-//
-//------------------------------------------------
-
-inline
-bool
-segments_encoded::
-empty() const noexcept
-{
- return size() == 0;
-}
-
-inline
-std::size_t
-segments_encoded::
-size() const noexcept
-{
- return u_->u_.nseg_;
-}
-
-//------------------------------------------------
-//
-// Modifiers
-//
-//------------------------------------------------
-
-inline
-void
-segments_encoded::
-clear() noexcept
-{
- erase(begin(), end());
-}
-
-//------------------------------------------------
-
-inline
-auto
-segments_encoded::
-insert(
- iterator before,
- std::initializer_list<
- string_view> init) ->
- iterator
-{
- return insert(
- before,
- init.begin(),
- init.end());
-}
-
-template
-auto
-segments_encoded::
-insert(
- iterator before,
- FwdIt first,
- FwdIt last) ->
- typename std::enable_if<
- std::is_convertible::reference,
- string_view>::value,
- iterator>::type
-{
- return insert(before, first, last,
- typename std::iterator_traits<
- FwdIt>::iterator_category{});
-}
-
-template
-auto
-segments_encoded::
-insert(
- iterator before,
- FwdIt first,
- FwdIt last,
- std::forward_iterator_tag) ->
- iterator
-{
- u_->edit_segments(
- before.impl_.i_,
- before.impl_.i_,
- detail::make_enc_segs_iter(
- first, last),
- detail::make_enc_segs_iter(
- first, last));
- return std::next(begin(), before.impl_.i_);
-}
-
-//------------------------------------------------
-
-inline
-auto
-segments_encoded::
-replace(
- iterator pos,
- string_view s) ->
- iterator
-{
- return replace(
- pos, std::next(pos),
- &s, &s + 1);
-}
-
-inline
-auto
-segments_encoded::
-replace(
- iterator from,
- iterator to,
- std::initializer_list<
- string_view> init) ->
- iterator
-{
- return replace(
- from,
- to,
- init.begin(),
- init.end());
-}
-
-template
-auto
-segments_encoded::
-replace(
- iterator from,
- iterator to,
- FwdIt first,
- FwdIt last) ->
- typename std::enable_if<
- std::is_convertible::reference,
- string_view>::value,
- iterator>::type
-{
- BOOST_ASSERT(from.impl_.begin_ >= u_->string().data());
- BOOST_ASSERT(from.impl_.end_ <= u_->string().data() +
- u_->string().size());
- BOOST_ASSERT(to.impl_.begin_ >= u_->string().data());
- BOOST_ASSERT(to.impl_.end_ >= u_->string().data() +
- u_->string().size());
- u_->edit_segments(
- from.impl_.i_,
- to.impl_.i_,
- detail::make_enc_segs_iter(first, last),
- detail::make_enc_segs_iter(first, last));
- return std::next(begin(), from.impl_.i_);
-}
-
-//------------------------------------------------
-
-inline
-auto
-segments_encoded::
-erase(
- iterator pos) noexcept ->
- iterator
-{
- return erase(pos, std::next(pos));
-}
-
-//------------------------------------------------
-
-inline
-void
-segments_encoded::
-push_back(
- string_view s)
-{
- insert(end(), s);
-}
-
-inline
-void
-segments_encoded::
-pop_back() noexcept
-{
- erase(std::prev(end()));
-}
-
-} // urls
-} // boost
-
-#endif
diff --git a/include/boost/url/impl/segments_encoded.ipp b/include/boost/url/impl/segments_encoded.ipp
deleted file mode 100644
index 7ec47a8a..00000000
--- a/include/boost/url/impl/segments_encoded.ipp
+++ /dev/null
@@ -1,104 +0,0 @@
-//
-// 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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_IMPL_SEGMENTS_ENCODED_IPP
-#define BOOST_URL_IMPL_SEGMENTS_ENCODED_IPP
-
-#include
-#include
-#include
-#include
-
-namespace boost {
-namespace urls {
-
-segments
-segments_encoded::
-decoded() const
-{
- return segments(*u_);
-}
-
-//------------------------------------------------
-//
-// Iterators
-//
-//------------------------------------------------
-
-auto
-segments_encoded::
-begin() const noexcept ->
- iterator
-{
- return {u_->encoded_path(), u_->u_.nseg_};
-}
-
-auto
-segments_encoded::
-end() const noexcept ->
- iterator
-{
- return {u_->encoded_path(), u_->u_.nseg_, 0};
-}
-
-//------------------------------------------------
-//
-// Modifiers
-//
-//------------------------------------------------
-
-auto
-segments_encoded::
-insert(
- iterator before,
- string_view s0) ->
- iterator
-{
- BOOST_ASSERT(before.impl_.pos_ >= u_->string().data());
- BOOST_ASSERT(before.impl_.pos_ <= u_->string().data() +
- u_->string().size());
- grammar::detail::copied_strings<
- BOOST_URL_STACK_BYTES> cs(u_->string());
- auto s = cs.maybe_copy(s0);
- u_->edit_segments(
- before.impl_.i_,
- before.impl_.i_,
- detail::make_enc_segs_iter(
- &s, &s + 1),
- detail::make_enc_segs_iter(
- &s, &s + 1));
- return std::next(begin(), before.impl_.i_);
-}
-
-auto
-segments_encoded::
-erase(
- iterator first,
- iterator last) noexcept ->
- iterator
-{
- BOOST_ASSERT(first.impl_.pos_ >= u_->string().data());
- BOOST_ASSERT(last.impl_.pos_ >= u_->string().data());
- BOOST_ASSERT(first.impl_.pos_ <= u_->string().data() +
- u_->string().size());
- BOOST_ASSERT(last.impl_.pos_ <= u_->string().data() +
- u_->string().size());
- string_view s;
- u_->edit_segments(
- first.impl_.i_, last.impl_.i_,
- detail::make_enc_segs_iter(&s, &s),
- detail::make_enc_segs_iter(&s, &s));
- return std::next(begin(), first.impl_.i_);
-}
-
-} // urls
-} // boost
-
-#endif
diff --git a/include/boost/url/impl/segments_encoded_base.hpp b/include/boost/url/impl/segments_encoded_base.hpp
new file mode 100644
index 00000000..b0c29133
--- /dev/null
+++ b/include/boost/url/impl/segments_encoded_base.hpp
@@ -0,0 +1,103 @@
+//
+// 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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_IMPL_SEGMENTS_ENCODED_BASE_HPP
+#define BOOST_URL_IMPL_SEGMENTS_ENCODED_BASE_HPP
+
+#include
+
+namespace boost {
+namespace urls {
+
+class segments_encoded_base::iterator
+{
+ detail::segments_iter_impl it_;
+
+ friend class url_base;
+ friend class segments_encoded_base;
+ friend class segments_encoded_ref;
+
+ iterator(detail::path_ref const&) noexcept;
+ iterator(detail::path_ref const&, int) noexcept;
+
+public:
+ using value_type = std::string;
+ using reference = pct_string_view;
+ using pointer = pct_string_view;
+ using difference_type = std::ptrdiff_t;
+ using iterator_category =
+ std::bidirectional_iterator_tag;
+
+ iterator() = default;
+ iterator(iterator const&) = default;
+ iterator& operator=(
+ iterator const&) = default;
+
+ reference
+ operator*() const noexcept
+ {
+ return it_.dereference();
+ }
+
+ pointer
+ operator->() const noexcept
+ {
+ return it_.dereference();
+ }
+
+ iterator&
+ operator++() noexcept
+ {
+ it_.increment();
+ return *this;
+ }
+
+ iterator&
+ operator--() noexcept
+ {
+ it_.decrement();
+ return *this;
+ }
+
+ iterator
+ operator++(int) noexcept
+ {
+ auto tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ iterator
+ operator--(int) noexcept
+ {
+ auto tmp = *this;
+ --*this;
+ return tmp;
+ }
+
+ bool
+ operator==(
+ iterator const& other) const noexcept
+ {
+ return it_.equal(other.it_);
+ }
+
+ bool
+ operator!=(
+ iterator const& other) const noexcept
+ {
+ return ! it_.equal(other.it_);
+ }
+};
+
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/impl/segments_encoded_base.ipp b/include/boost/url/impl/segments_encoded_base.ipp
new file mode 100644
index 00000000..bad402a0
--- /dev/null
+++ b/include/boost/url/impl/segments_encoded_base.ipp
@@ -0,0 +1,104 @@
+//
+// 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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_IMPL_SEGMENTS_ENCODED_BASE_IPP
+#define BOOST_URL_IMPL_SEGMENTS_ENCODED_BASE_IPP
+
+#include
+#include
+
+namespace boost {
+namespace urls {
+
+// begin
+segments_encoded_base::
+iterator::
+iterator(
+ detail::path_ref const& ref) noexcept
+ : it_(ref)
+{
+}
+
+// end
+segments_encoded_base::
+iterator::
+iterator(
+ detail::path_ref const& ref,
+ int) noexcept
+ : it_(ref, 0)
+{
+}
+
+//------------------------------------------------
+
+pct_string_view
+segments_encoded_base::
+buffer() const noexcept
+{
+ return ref_.string();
+}
+
+bool
+segments_encoded_base::
+is_absolute() const noexcept
+{
+ return ref_.string().starts_with('/');
+}
+
+bool
+segments_encoded_base::
+empty() const noexcept
+{
+ return ref_.nseg() == 0;
+}
+
+std::size_t
+segments_encoded_base::
+size() const noexcept
+{
+ return ref_.nseg();
+}
+
+pct_string_view
+segments_encoded_base::
+front() const noexcept
+{
+ BOOST_ASSERT(! empty());
+ return *begin();
+}
+
+pct_string_view
+segments_encoded_base::
+back() const noexcept
+{
+ BOOST_ASSERT(! empty());
+ return *--end();
+}
+
+auto
+segments_encoded_base::
+begin() const noexcept ->
+ iterator
+{
+ return iterator(ref_);
+}
+
+auto
+segments_encoded_base::
+end() const noexcept ->
+ iterator
+{
+ return iterator(ref_, 0);
+}
+
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/impl/segments_encoded_ref.hpp b/include/boost/url/impl/segments_encoded_ref.hpp
new file mode 100644
index 00000000..e93d9a69
--- /dev/null
+++ b/include/boost/url/impl/segments_encoded_ref.hpp
@@ -0,0 +1,276 @@
+//
+// 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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_IMPL_SEGMENTS_ENCODED_REF_HPP
+#define BOOST_URL_IMPL_SEGMENTS_ENCODED_REF_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace urls {
+
+//------------------------------------------------
+//
+// Special Members
+//
+//------------------------------------------------
+
+inline
+segments_encoded_ref::
+segments_encoded_ref(
+ url_base& u) noexcept
+ : segments_encoded_base(u.u_)
+ , u_(&u)
+{
+}
+
+inline
+segments_encoded_ref&
+segments_encoded_ref::
+operator=(
+ segments_encoded_ref const& other)
+{
+ assign(other.begin(), other.end());
+ return *this;
+}
+
+inline
+segments_encoded_ref&
+segments_encoded_ref::
+operator=(
+ segments_encoded_view const& other)
+{
+ assign(other.begin(), other.end());
+ return *this;
+}
+
+inline
+segments_encoded_ref&
+segments_encoded_ref::
+operator=(std::initializer_list<
+ pct_string_view> init)
+{
+ assign(init.begin(), init.end());
+ return *this;
+}
+
+inline
+segments_encoded_ref::
+operator
+segments_encoded_view() const noexcept
+{
+ return {detail::path_ref(u_->u_)};
+}
+
+//------------------------------------------------
+//
+// Modifiers
+//
+//------------------------------------------------
+
+inline
+void
+segments_encoded_ref::
+clear() noexcept
+{
+ erase(begin(), end());
+}
+
+inline
+segments_encoded_ref&
+segments_encoded_ref::
+assign(
+ std::initializer_list<
+ pct_string_view> init)
+{
+ assign(init.begin(), init.end());
+ return *this;
+}
+
+template
+auto
+segments_encoded_ref::
+assign(
+ FwdIt first, FwdIt last) ->
+ typename std::enable_if<
+ std::is_convertible::reference,
+ pct_string_view>::value>::type
+{
+ u_->edit_segments(
+ begin().it_,
+ end().it_,
+ detail::make_segments_encoded_iter(
+ first, last));
+}
+
+//------------------------------------------------
+
+inline
+auto
+segments_encoded_ref::
+insert(
+ iterator before,
+ std::initializer_list<
+ pct_string_view> init) ->
+ iterator
+{
+ return insert(
+ before,
+ init.begin(),
+ init.end());
+}
+
+template
+auto
+segments_encoded_ref::
+insert(
+ iterator before,
+ FwdIt first,
+ FwdIt last) ->
+ typename std::enable_if<
+ std::is_convertible::reference,
+ pct_string_view>::value,
+ iterator>::type
+{
+ return insert(before, first, last,
+ typename std::iterator_traits<
+ FwdIt>::iterator_category{});
+}
+
+template
+auto
+segments_encoded_ref::
+insert(
+ iterator before,
+ FwdIt first,
+ FwdIt last,
+ std::forward_iterator_tag) ->
+ iterator
+{
+ u_->edit_segments(
+ before.it_,
+ before.it_,
+ detail::make_segments_encoded_iter(
+ first, last));
+ return std::next(begin(), before.it_.index);
+}
+
+//------------------------------------------------
+
+inline
+auto
+segments_encoded_ref::
+replace(
+ iterator pos,
+ pct_string_view s) ->
+ iterator
+{
+ return replace(
+ pos, std::next(pos),
+ &s, &s + 1);
+}
+
+inline
+auto
+segments_encoded_ref::
+replace(
+ iterator from,
+ iterator to,
+ pct_string_view s) ->
+ iterator
+{
+ return replace(
+ from, to, &s, &s+1);
+}
+
+inline
+auto
+segments_encoded_ref::
+replace(
+ iterator from,
+ iterator to,
+ std::initializer_list<
+ pct_string_view> init) ->
+ iterator
+{
+ return replace(
+ from,
+ to,
+ init.begin(),
+ init.end());
+}
+
+template
+auto
+segments_encoded_ref::
+replace(
+ iterator from,
+ iterator to,
+ FwdIt first,
+ FwdIt last) ->
+ typename std::enable_if<
+ std::is_convertible::reference,
+ pct_string_view>::value,
+ iterator>::type
+{
+ u_->edit_segments(
+ from.it_,
+ to.it_,
+ detail::make_segments_encoded_iter(
+ first, last));
+ return std::next(begin(), from.it_.index);
+}
+
+//------------------------------------------------
+
+inline
+auto
+segments_encoded_ref::
+erase(
+ iterator pos) noexcept ->
+ iterator
+{
+ return erase(pos, std::next(pos));
+}
+
+//------------------------------------------------
+
+inline
+void
+segments_encoded_ref::
+push_back(
+ pct_string_view s)
+{
+ insert(end(), s);
+}
+
+inline
+void
+segments_encoded_ref::
+pop_back() noexcept
+{
+ erase(std::prev(end()));
+}
+
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/impl/segments_encoded_ref.ipp b/include/boost/url/impl/segments_encoded_ref.ipp
new file mode 100644
index 00000000..c2238beb
--- /dev/null
+++ b/include/boost/url/impl/segments_encoded_ref.ipp
@@ -0,0 +1,56 @@
+//
+// 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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_IMPL_SEGMENTS_ENCODED_REF_IPP
+#define BOOST_URL_IMPL_SEGMENTS_ENCODED_REF_IPP
+
+#include
+#include
+#include
+
+namespace boost {
+namespace urls {
+
+auto
+segments_encoded_ref::
+insert(
+ iterator before,
+ pct_string_view s0) ->
+ iterator
+{
+ string_view s = s0;
+ u_->edit_segments(
+ before.it_,
+ before.it_,
+ detail::make_segments_encoded_iter(
+ &s, &s + 1));
+ return std::next(begin(), before.it_.index);
+}
+
+auto
+segments_encoded_ref::
+erase(
+ iterator first,
+ iterator last) noexcept ->
+ iterator
+{
+ string_view s;
+ u_->edit_segments(
+ first.it_,
+ last.it_,
+ detail::make_segments_encoded_iter(
+ &s, &s));
+ return std::next(begin(), first.it_.index);
+}
+
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/impl/segments_encoded_view.hpp b/include/boost/url/impl/segments_encoded_view.hpp
deleted file mode 100644
index 9b4d2cc8..00000000
--- a/include/boost/url/impl/segments_encoded_view.hpp
+++ /dev/null
@@ -1,180 +0,0 @@
-//
-// 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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_IMPL_SEGMENTS_ENCODED_VIEW_HPP
-#define BOOST_URL_IMPL_SEGMENTS_ENCODED_VIEW_HPP
-
-#include
-#include
-#include
-#include
-
-namespace boost {
-namespace urls {
-
-class segments_encoded_view::iterator
-{
- friend segments_encoded_view;
-
- detail::segments_encoded_iterator_impl impl_;
-
- iterator(
- string_view s,
- std::size_t nseg) noexcept
- : impl_(s, nseg)
- {
- }
-
- // end ctor
- iterator(
- string_view s,
- std::size_t nseg,
- int) noexcept
- : impl_(s, nseg, 0)
- {
- }
-
-public:
- using value_type = std::string;
- using reference = string_view;
- using pointer = void const*;
- using difference_type = std::ptrdiff_t;
- using iterator_category =
- std::bidirectional_iterator_tag;
-
- iterator() = default;
-
- iterator(iterator const&) noexcept = default;
-
- iterator& operator=(iterator const&) noexcept = default;
-
- reference
- operator*() const noexcept
- {
- return impl_.s_;
- }
-
- iterator&
- operator++() noexcept
- {
- impl_.increment();
- return *this;
- }
-
- iterator&
- operator--() noexcept
- {
- impl_.decrement();
- return *this;
- }
-
- iterator
- operator++(int) noexcept
- {
- auto tmp = *this;
- ++*this;
- return tmp;
- }
-
- iterator
- operator--(int) noexcept
- {
- auto tmp = *this;
- --*this;
- return tmp;
- }
-
- bool
- operator==(
- iterator const& other) const noexcept
- {
- return impl_.equal(other.impl_);
- }
-
- bool
- operator!=(
- iterator const& other) const noexcept
- {
- return !impl_.equal(other.impl_);
- }
-};
-
-//------------------------------------------------
-//
-// Members
-//
-//------------------------------------------------
-
-inline
-segments_encoded_view::
-segments_encoded_view() noexcept
- : s_("")
- , n_(0)
-{
-}
-
-inline
-bool
-segments_encoded_view::
-is_absolute() const noexcept
-{
- return s_.starts_with('/');
-}
-
-//------------------------------------------------
-//
-// Element Access
-//
-//------------------------------------------------
-
-inline
-string_view
-segments_encoded_view::
-front() const noexcept
-{
- BOOST_ASSERT(! empty());
- return *begin();
-}
-
-inline
-string_view
-segments_encoded_view::
-back() const noexcept
-{
- BOOST_ASSERT(! empty());
- return *--end();
-}
-
-//------------------------------------------------
-//
-// Capacity
-//
-//------------------------------------------------
-
-inline
-bool
-segments_encoded_view::
-empty() const noexcept
-{
- return size() == 0;
-}
-
-inline
-std::size_t
-segments_encoded_view::
-size() const noexcept
-{
- return n_;
-}
-
-} // urls
-} // boost
-
-#endif
diff --git a/include/boost/url/impl/segments_encoded_view.ipp b/include/boost/url/impl/segments_encoded_view.ipp
index 8bf29262..6cbc4189 100644
--- a/include/boost/url/impl/segments_encoded_view.ipp
+++ b/include/boost/url/impl/segments_encoded_view.ipp
@@ -11,85 +11,16 @@
#ifndef BOOST_URL_IMPL_SEGMENTS_ENCODED_VIEW_IPP
#define BOOST_URL_IMPL_SEGMENTS_ENCODED_VIEW_IPP
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include
namespace boost {
namespace urls {
-//------------------------------------------------
-
segments_encoded_view::
-segments_encoded_view(
- string_view s,
- std::size_t nseg) noexcept
- : s_(s)
- , n_(nseg)
+operator
+segments_view() const noexcept
{
-}
-
-//------------------------------------------------
-//
-// Iterators
-//
-//------------------------------------------------
-
-auto
-segments_encoded_view::
-begin() const noexcept ->
- iterator
-{
- return iterator(s_, n_);
-}
-
-auto
-segments_encoded_view::
-end() const noexcept ->
- iterator
-{
- return iterator(s_, n_, 0);
-}
-
-//------------------------------------------------
-//
-// Friends
-//
-//------------------------------------------------
-
-result
-parse_path(string_view s) noexcept
-{
- if(s.empty())
- return segments_encoded_view();
- if(s[0] == '/')
- {
- auto rv = grammar::parse(
- s, detail::path_abempty_rule);
- if(! rv)
- return rv.error();
- return segments_encoded_view(
- rv->string(),
- detail::path_segments(
- rv->string(),
- rv->size()));
- }
- {
- auto rv = grammar::parse(
- s, detail::path_rootless_rule);
- if(! rv)
- return rv.error();
- return segments_encoded_view(
- rv->string(),
- detail::path_segments(
- rv->string(),
- rv->size()));
- }
+ return { ref_ };
}
} // urls
diff --git a/include/boost/url/impl/segments_ref.hpp b/include/boost/url/impl/segments_ref.hpp
new file mode 100644
index 00000000..717d6b84
--- /dev/null
+++ b/include/boost/url/impl/segments_ref.hpp
@@ -0,0 +1,240 @@
+//
+// 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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_IMPL_SEGMENTS_REF_HPP
+#define BOOST_URL_IMPL_SEGMENTS_REF_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace urls {
+
+inline
+segments_ref::
+segments_ref(
+ url_base& u) noexcept
+ : segments_base(
+ detail::path_ref(u.u_))
+ , u_(&u)
+{
+}
+
+inline
+segments_ref&
+segments_ref::
+operator=(segments_ref const& other)
+{
+ assign(other.begin(), other.end());
+ return *this;
+}
+
+inline
+segments_ref&
+segments_ref::
+operator=(segments_view const& other)
+{
+ assign(other.begin(), other.end());
+ return *this;
+}
+
+inline
+segments_ref&
+segments_ref::
+operator=(std::initializer_list<
+ string_view> init)
+{
+ assign(init.begin(), init.end());
+ return *this;
+}
+
+inline
+segments_ref::
+operator
+segments_view() const noexcept
+{
+ return segments_view(ref_);
+}
+
+inline
+void
+segments_ref::
+clear() noexcept
+{
+ erase(begin(), end());
+}
+
+template
+auto
+segments_ref::
+assign(FwdIt first, FwdIt last) ->
+ typename std::enable_if<
+ std::is_convertible::reference,
+ string_view>::value>::type
+{
+ u_->edit_segments(
+ begin().it_,
+ end().it_,
+ detail::make_segments_iter(
+ first, last));
+}
+
+//------------------------------------------------
+
+inline
+auto
+segments_ref::
+insert(
+ iterator before,
+ std::initializer_list<
+ string_view> init) ->
+ iterator
+{
+ return insert(
+ before,
+ init.begin(),
+ init.end());
+}
+
+template
+auto
+segments_ref::
+insert(
+ iterator before,
+ FwdIt first,
+ FwdIt last) ->
+ typename std::enable_if<
+ std::is_convertible::reference,
+ string_view>::value,
+ iterator>::type
+{
+ return insert(before, first, last,
+ typename std::iterator_traits<
+ FwdIt>::iterator_category{});
+}
+
+template
+auto
+segments_ref::
+insert(
+ iterator before,
+ FwdIt first,
+ FwdIt last,
+ std::forward_iterator_tag) ->
+ iterator
+{
+ u_->edit_segments(
+ before.it_,
+ before.it_,
+ detail::make_segments_iter(
+ first, last));
+ return std::next(begin(), before.it_.index);
+}
+
+//------------------------------------------------
+
+inline
+auto
+segments_ref::
+replace(
+ iterator pos,
+ string_view s) ->
+ iterator
+{
+ return replace(
+ pos, std::next(pos),
+ &s, &s + 1);
+}
+
+inline
+auto
+segments_ref::
+replace(
+ iterator from,
+ iterator to,
+ std::initializer_list<
+ string_view> init) ->
+ iterator
+{
+ return replace(
+ from,
+ to,
+ init.begin(),
+ init.end());
+}
+
+template
+auto
+segments_ref::
+replace(
+ iterator from,
+ iterator to,
+ FwdIt first,
+ FwdIt last) ->
+ typename std::enable_if<
+ std::is_convertible::reference,
+ string_view>::value,
+ iterator>::type
+{
+ u_->edit_segments(
+ from.it_,
+ to.it_,
+ detail::make_segments_iter(
+ first, last));
+ return std::next(begin(), from.it_.index);
+}
+
+//------------------------------------------------
+
+inline
+auto
+segments_ref::
+erase(
+ iterator pos) noexcept ->
+ iterator
+{
+ return erase(pos, std::next(pos));
+}
+
+//------------------------------------------------
+
+inline
+void
+segments_ref::
+push_back(
+ string_view s)
+{
+ insert(end(), s);
+}
+
+inline
+void
+segments_ref::
+pop_back() noexcept
+{
+ erase(std::prev(end()));
+}
+
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/impl/segments_ref.ipp b/include/boost/url/impl/segments_ref.ipp
new file mode 100644
index 00000000..3e93808e
--- /dev/null
+++ b/include/boost/url/impl/segments_ref.ipp
@@ -0,0 +1,63 @@
+//
+// 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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_IMPL_SEGMENTS_REF_IPP
+#define BOOST_URL_IMPL_SEGMENTS_REF_IPP
+
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace urls {
+
+//------------------------------------------------
+//
+// Modifiers
+//
+//------------------------------------------------
+
+auto
+segments_ref::
+insert(
+ iterator before,
+ string_view s) ->
+ iterator
+{
+ u_->edit_segments(
+ before.it_,
+ before.it_,
+ detail::make_segments_iter(
+ &s, &s + 1));
+ return std::next(begin(), before.it_.index);
+}
+
+auto
+segments_ref::
+segments_ref::
+erase(
+ iterator first,
+ iterator last) noexcept ->
+ iterator
+{
+ string_view s;
+ u_->edit_segments(
+ first.it_,
+ last.it_,
+ detail::make_segments_encoded_iter(
+ &s, &s));
+ return std::next(begin(), first.it_.index);
+}
+
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/impl/segments_view.hpp b/include/boost/url/impl/segments_view.hpp
index 42f7221a..259b1cc0 100644
--- a/include/boost/url/impl/segments_view.hpp
+++ b/include/boost/url/impl/segments_view.hpp
@@ -11,161 +11,9 @@
#ifndef BOOST_URL_IMPL_SEGMENTS_VIEW_HPP
#define BOOST_URL_IMPL_SEGMENTS_VIEW_HPP
-#include
-#include
-
namespace boost {
namespace urls {
-class segments_view::
- iterator
-{
- detail::segments_iterator_impl impl_;
-
- friend segments_view;
-
- iterator(
- string_view s,
- std::size_t nseg) noexcept
- : impl_(s, nseg)
- {
- }
-
- // end ctor
- iterator(
- string_view s,
- std::size_t nseg,
- int) noexcept
- : impl_(s, nseg, 0)
- {
- }
-
-public:
- using value_type = std::string;
- using reference = decode_view;
- using pointer = void const*;
- using difference_type = std::ptrdiff_t;
- using iterator_category =
- std::bidirectional_iterator_tag;
-
- iterator() noexcept = default;
-
- iterator(iterator const&) noexcept = default;
-
- iterator&
- operator=(iterator const&) noexcept = default;
-
- decode_view
- operator*() const noexcept
- {
- return impl_.dereference();
- }
-
- iterator&
- operator++() noexcept
- {
- impl_.increment();
- return *this;
- }
-
- iterator&
- operator--() noexcept
- {
- impl_.decrement();
- return *this;
- }
-
- iterator
- operator++(int) noexcept
- {
- auto tmp = *this;
- ++*this;
- return tmp;
- }
-
- iterator
- operator--(int) noexcept
- {
- auto tmp = *this;
- --*this;
- return tmp;
- }
-
- bool
- operator==(
- iterator const& other) const noexcept
- {
- return impl_.equal(other.impl_);
- }
-
- bool
- operator!=(
- iterator const& other) const noexcept
- {
- return !impl_.equal(other.impl_);
- }
-};
-
-//------------------------------------------------
-//
-// Members
-//
-//------------------------------------------------
-
-inline
-bool
-segments_view::
-is_absolute() const noexcept
-{
- return s_.starts_with('/');
-}
-
-//------------------------------------------------
-//
-// Element Access
-//
-//------------------------------------------------
-
-inline
-decode_view
-segments_view::
-front() const noexcept
-{
- BOOST_ASSERT(! empty());
- return *begin();
-}
-
-inline
-decode_view
-segments_view::
-back() const noexcept
-{
- BOOST_ASSERT(! empty());
- return *--end();
-}
-
-//------------------------------------------------
-//
-// Capacity
-//
-//------------------------------------------------
-
-inline
-bool
-segments_view::
-empty() const noexcept
-{
- return size() == 0;
-}
-
-inline
-std::size_t
-segments_view::
-size() const noexcept
-{
- return n_;
-}
-
} // urls
} // boost
diff --git a/include/boost/url/impl/segments_view.ipp b/include/boost/url/impl/segments_view.ipp
deleted file mode 100644
index 056d6c21..00000000
--- a/include/boost/url/impl/segments_view.ipp
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-// 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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_IMPL_SEGMENTS_VIEW_IPP
-#define BOOST_URL_IMPL_SEGMENTS_VIEW_IPP
-
-#include
-#include
-
-namespace boost {
-namespace urls {
-
-//------------------------------------------------
-//
-// Iterators
-//
-//------------------------------------------------
-
-auto
-segments_view::
-begin() const noexcept ->
- iterator
-{
- return iterator(s_, n_);
-}
-
-auto
-segments_view::
-end() const noexcept ->
- iterator
-{
- return iterator(s_, n_, 0);
-}
-
-void
-segments_view::
-write(std::ostream& os) const
-{
- auto first = begin();
- auto const last = end();
- if( first != last )
- {
- if( is_absolute() )
- os << "/";
- os << *first;
- while( ++first != last )
- os << '/' << *first;
- }
-}
-
-} // urls
-} // boost
-
-#endif
diff --git a/include/boost/url/impl/url_base.ipp b/include/boost/url/impl/url_base.ipp
index 83861fb2..7ef8679e 100644
--- a/include/boost/url/impl/url_base.ipp
+++ b/include/boost/url/impl/url_base.ipp
@@ -31,7 +31,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -67,13 +66,14 @@ op_t(
u.check_invariants();
}
-
void
url_base::
op_t::
move(char* dest, char const* src,
std::size_t n) noexcept
{
+ if(! n)
+ return;
if(s)
return detail::move_chars(
dest, src, n, *s);
@@ -148,10 +148,7 @@ remove_scheme() noexcept
BOOST_ASSERT(u_.len(id_path) > 0);
if(s_[p] == '/')
return false;
- string_view const s(
- s_ + p, segment(1) - p);
- if(s.find_first_of(':') ==
- string_view::npos)
+ if(! first_segment().contains(':'))
return false;
return true;
}();
@@ -350,10 +347,10 @@ set_encoded_userinfo(
auto const s0 = s.substr(0, pos);
auto const s1 = s.substr(pos + 1);
auto const n0 =
- detail::re_encoded_size(s0, opt,
+ detail::re_encoded_size_unchecked(s0, opt,
detail::user_chars);
auto const n1 =
- detail::re_encoded_size(s1, opt,
+ detail::re_encoded_size_unchecked(s1, opt,
detail::password_chars);
auto dest =
set_userinfo_impl(n0 + n1 + 1, op);
@@ -364,11 +361,11 @@ set_encoded_userinfo(
s0,
opt,
detail::user_chars);
- dest[n0] = ':';
+ *dest++ = ':';
u_.decoded_[id_pass] =
detail::re_encode_unchecked(
- dest + n0 + 1,
- dest + n0 + 1 + n1,
+ dest,
+ dest + n1,
s1,
opt,
detail::password_chars);
@@ -378,7 +375,7 @@ set_encoded_userinfo(
{
// user
auto const n =
- detail::re_encoded_size(
+ detail::re_encoded_size_unchecked(
s, opt, detail::user_chars);
auto dest = set_userinfo_impl(n, op);
u_.decoded_[id_user] =
@@ -423,7 +420,7 @@ set_encoded_user(
op_t op(*this, &detail::ref(s));
encode_opts opt;
auto const n =
- detail::re_encoded_size(
+ detail::re_encoded_size_unchecked(
s, opt, detail::user_chars);
auto dest = set_user_impl(n, op);
u_.decoded_[id_user] =
@@ -485,7 +482,7 @@ set_encoded_password(
op_t op(*this, &detail::ref(s));
encode_opts opt;
auto const n =
- detail::re_encoded_size(s, opt,
+ detail::re_encoded_size_unchecked(s, opt,
detail::password_chars);
auto dest = set_password_impl(n, op);
u_.decoded_[id_pass] =
@@ -625,7 +622,7 @@ set_encoded_host(
// reg-name
op_t op(*this, &detail::ref(s));
encode_opts opt;
- auto const n = detail::re_encoded_size(
+ auto const n = detail::re_encoded_size_unchecked(
s, opt, detail::host_chars);
auto dest = set_host_impl(n, op);
u_.decoded_[id_host] =
@@ -715,7 +712,7 @@ set_encoded_host_address(
// reg-name
op_t op(*this, &detail::ref(s));
encode_opts opt;
- auto const n = detail::re_encoded_size(
+ auto const n = detail::re_encoded_size_unchecked(
s, opt, detail::host_chars);
auto dest = set_host_impl(n, op);
u_.decoded_[id_host] =
@@ -849,7 +846,7 @@ set_encoded_host_name(
op_t op(*this, &detail::ref(s));
encode_opts opt;
- auto const n = detail::re_encoded_size(
+ auto const n = detail::re_encoded_size_unchecked(
s, opt, allowed);
auto dest = set_host_impl(n, op);
u_.decoded_[id_host] =
@@ -1065,20 +1062,13 @@ url_base::
set_path(
string_view s)
{
- grammar::detail::copied_strings<
- BOOST_URL_STACK_BYTES> buf(
- this->string());
- s = buf.maybe_copy(s);
- int abs_hint;
- if(s.starts_with('/'))
- abs_hint = 1;
- else
- abs_hint = 0;
edit_segments(
- 0, u_.nseg_,
- detail::plain_path_iter(s),
- detail::plain_path_iter(s),
- abs_hint);
+ detail::segments_iter_impl(
+ detail::path_ref(u_)),
+ detail::segments_iter_impl(
+ detail::path_ref(u_), 0),
+ detail::path_iter(s),
+ s.starts_with('/'));
return *this;
}
@@ -1087,21 +1077,13 @@ url_base::
set_encoded_path(
pct_string_view s)
{
- grammar::detail::copied_strings<
- BOOST_URL_STACK_BYTES> buf(
- this->string());
- s = buf.maybe_copy(s);
- int abs_hint;
- if(s.starts_with('/'))
- abs_hint = 1;
- else
- abs_hint = 0;
edit_segments(
- 0,
- u_.nseg_,
- detail::enc_path_iter(s),
- detail::enc_path_iter(s),
- abs_hint);
+ detail::segments_iter_impl(
+ detail::path_ref(u_)),
+ detail::segments_iter_impl(
+ detail::path_ref(u_), 0),
+ detail::path_encoded_iter(s),
+ s.starts_with('/'));
return *this;
}
@@ -1237,7 +1219,7 @@ set_encoded_fragment(
op_t op(*this, &detail::ref(s));
encode_opts opt;
auto const n =
- detail::re_encoded_size(s,
+ detail::re_encoded_size_unchecked(s,
opt, detail::fragment_chars);
auto dest = resize_impl(
id_frag, n + 1, op);
@@ -1620,9 +1602,7 @@ set_scheme_impl(
{
if(u_.nseg_ == 0)
return false;
- // VFALCO Should not be calling segment()
- if(segment(1) <
- u_.offset(id_path) + 2)
+ if(first_segment().size() < 2)
return false;
auto const src = s_ + p;
if(src[0] != '.')
@@ -1789,294 +1769,253 @@ set_port_impl(
//------------------------------------------------
-/* Return offset of i-th segment
-*/
-pos_t
+// return the first segment of the path.
+// this is needed for some algorithms.
+string_view
url_base::
-segment(
- std::size_t i) const noexcept
+first_segment() const noexcept
{
- if(i == 0)
- return u_.offset(id_path);
- if(i == u_.nseg_)
- return u_.offset(id_query);
- BOOST_ASSERT(i < u_.nseg_);
- auto it = s_ + u_.offset(id_path) +
- detail::path_prefix(
- u_.get(id_path));
- BOOST_ASSERT(it < s_ +
- u_.offset(id_query));
- for(;;)
- {
- while(*it != '/')
- ++it;
- BOOST_ASSERT(it < s_ +
- u_.offset(id_query));
- --i;
- if(i == 0)
- break;
- ++it;
- }
- return it - s_;
+ if(u_.nseg_ == 0)
+ return {};
+ auto const p0 = u_.cs_ +
+ u_.offset(id_path) +
+ detail::path_prefix(
+ u_.get(id_path));
+ auto const end = u_.cs_ +
+ u_.offset(id_query);
+ if(u_.nseg_ == 1)
+ return string_view(
+ p0, end - p0);
+ auto p = p0;
+ while(*p != '/')
+ ++p;
+ BOOST_ASSERT(p < end);
+ return string_view(p0, p - p0);
}
-/* Remove segments [first, last) and make
- room for nseg new segments inserted
- before first, with space for n chars
- including prefix and/or separators.
-
- Segments look like this, where ## is the
- malleable prefix and '/' is a literal slash:
-
- ##_0_ /_1_ /_2_ /_3_
-*/
-char*
-url_base::
-resize_segments(
- std::size_t i0,
- std::size_t i1,
- std::size_t n,
- std::size_t nseg,
- op_t& op)
-{
- BOOST_ASSERT(i1 >= i0);
- BOOST_ASSERT(i1 - i0 <= u_.nseg_);
-
- // new number of segments
- std::size_t const nseg1 =
- u_.nseg_ + nseg - (i1 - i0);
-
- // [p0, p1) range to replace
- auto p0 = segment(i0);
- auto p1 = segment(i1);
- if(i1 == 0)
- {
- p1 += detail::path_prefix(
- u_.get(id_path));
- }
- else if(
- i0 == 0 &&
- nseg == 0 &&
- i1 < u_.nseg_)
- {
- // Remove the slash from segment i1
- // if it is becoming the new first
- // segment.
- BOOST_ASSERT(s_[p1] == '/');
- ++p1;
- }
-
- // old size of [p0, p1)
- auto const n0 = p1 - p0;
-
- // adjust capacity
- std::size_t c = size() + n - n0;
- if (c == 0)
- return nullptr;
-
- reserve_impl(c, op);
-
- // start of output
- auto dest = s_ + p0;
-
- // move and size
- op.move(
- dest + n,
- s_ + p1,
- size() - p1);
- u_.set_size(
- id_path,
- u_.len(id_path) -
- (n0 - n));
- u_.nseg_ = nseg1;
- s_[size()] = '\0';
- return dest;
-}
-
-// insert or replace [i0, i1)
-// with [it0, it1)
void
url_base::
edit_segments(
- std::size_t i0,
- std::size_t i1,
- detail::any_path_iter&& it0,
- detail::any_path_iter&& it1,
- int abs_hint)
+ detail::segments_iter_impl const& it0,
+ detail::segments_iter_impl const& it1,
+ detail::any_segments_iter&& src,
+ // -1 = preserve
+ // 0 = make relative (can fail)
+ // 1 = make absolute
+ int absolute)
{
- op_t op(*this);
+ // Iterator doesn't belong to this url
+ BOOST_ASSERT(it0.ref.alias_of(u_));
- bool abs;
- if( has_authority() ||
- abs_hint == -1)
- abs = is_path_absolute();
- else if(abs_hint == 1)
- abs = true;
- else
- abs = false;
+ // Iterator doesn't belong to this url
+ BOOST_ASSERT(it1.ref.alias_of(u_));
-/*
- Measure the number of characters and
- the number of segments we are inserting.
- This does not include leading or trailing
- separators.
-*/
- error_code ec;
- std::size_t n = 0;
+ // Iterator is in the wrong order
+ BOOST_ASSERT(it0.index <= it1.index);
+
+ // Iterator is out of range
+ BOOST_ASSERT(it0.index <= u_.nseg_);
+
+ // Iterator is out of range
+ BOOST_ASSERT(it1.index <= u_.nseg_);
+
+ bool const is_abs = is_path_absolute();
+ if(has_authority())
+ absolute = 1; // must be absolute
+ else if(absolute < 0)
+ absolute = is_abs; // preserve
+ auto const path_pos = u_.offset(id_path);
+
+//------------------------------------------------
+//
+// Measure the number of encoded characters
+// of output, and the number of inserted
+// segments including internal separators.
+//
std::size_t nseg = 0;
- bool more = it0.measure(n, ec);
- if(ec.failed())
- detail::throw_system_error(ec);
- if(more)
+ std::size_t nchar = 0;
+ if(src.measure(nchar))
{
for(;;)
{
++nseg;
- more = it0.measure(n, ec);
- if(ec.failed())
- detail::throw_system_error(ec);
- if(! more)
+ if(! src.measure(nchar))
break;
- ++n;
+ ++nchar;
}
}
-/* Calculate prefix size for new segment range:
- 0 = ""
- 1 = "/"
- 2 = "./"
- 3 = "/./"
+//------------------------------------------------
+//
+// Calculate [pos0, pos1) to remove
+//
+ auto pos0 = it0.pos;
+ if(it0.index == 0)
+ {
+ // patch pos for prefix
+ pos0 = 0;
+ }
+ auto pos1 = it1.pos;
+ if(it1.index == 0)
+ {
+ // patch pos for prefix
+ pos1 = detail::path_prefix(
+ u_.get(id_path));
+ }
+ else if(
+ it0.index == 0 &&
+ it1.index < u_.nseg_ &&
+ nseg == 0)
+ {
+ // Remove the slash from segment it1
+ // if it is becoming the new first
+ // segment.
+ ++pos1;
+ }
- This is a malleable prefix that might need to
- change according the URL scheme and authority.
-
-*/
- int prefix;
- if(i0 > 0)
+//------------------------------------------------
+//
+// Calculate output prefix
+//
+// 0 = ""
+// 1 = "/"
+// 2 = "./"
+// 3 = "/./"
+//
+ int prefix = 0;
+ if(it0.index > 0)
{
- if(nseg > 0)
- prefix = 1;
- else
- prefix = 0;
+ // first segment unchanged
+ prefix = nseg > 0;
}
- else if(
- it0.front == "." &&
- nseg > 1)
+ else if(nseg > 0)
{
- if( abs ||
- has_authority())
+ // first segment from src
+ if(! src.front.empty())
+ {
+ if( src.front == "." &&
+ nseg > 1)
+ {
+ prefix = 2 + absolute;
+ }
+ else if( has_scheme() ||
+ ! src.front.contains(':'))
+ {
+ prefix = absolute;
+ }
+ else
+ {
+ prefix = 2 + absolute;
+ }
+ }
+ else if(absolute)
+ {
prefix = 3;
- else
- prefix = 2;
- }
- else if(has_authority())
- {
- if(nseg == 0)
- prefix = abs ? 1 : 0;
- else if(! it0.front.empty())
- prefix = 1;
- else
- prefix = 3;
- }
- else if(
- nseg > 1 &&
- it0.front.empty())
- {
- prefix = 3;
- }
- else if(
- ! abs &&
- ! has_scheme() &&
- (
- it0.front.find_first_of(
- ':') != string_view::npos ||
- it0.front.empty()))
- {
- if (nseg > 0)
- prefix = 2;
- else
+ }
+ else if(has_scheme() ||
+ src.front.contains(':'))
+ {
prefix = 0;
- }
- else if(
- abs &&
- nseg > 0 &&
- it0.front.empty())
- {
- BOOST_ASSERT(
- ! has_authority());
- prefix = 3;
+ }
+ else
+ {
+ prefix = 2;
+ }
}
else
{
- if(abs)
- prefix = 1;
- else
- prefix = 0;
+ // first segment from it1
+ auto const p =
+ u_.cs_ + path_pos + it1.pos;
+ switch(u_.cs_ +
+ u_.offset(id_query) - p)
+ {
+ case 0:
+ // points to end
+ prefix = absolute;
+ break;
+ default:
+ BOOST_ASSERT(*p == '/');
+ if(p[1] != '/')
+ {
+ prefix = absolute;
+ break;
+ }
+ // empty
+ BOOST_FALLTHROUGH;
+ case 1:
+ // empty
+ BOOST_ASSERT(*p == '/');
+ if(absolute)
+ {
+ if(has_authority())
+ prefix = 1;
+ else
+ prefix = 3;
+ }
+ else
+ {
+ if( has_scheme() ||
+ it1.dereference().contains(':'))
+ prefix = 0;
+ else
+ prefix = 2;
+ }
+ break;
+ }
}
-/* Calculate suffix size for the new segments:
- 0 = ""
- 1 = "/"
+// append '/' to new segs
+// if inserting at front.
+ int const suffix =
+ it1.index == 0 &&
+ u_.nseg_ > 0 &&
+ nseg > 0;
- This extra suffix should cover the case where
- insertion at the first indexes leaves a
- missing slash in a relative path:
-
- "file.txt"
- -> insert "etc" as first segment
- -> becomes "etc" "/" "file.txt"
-
- "file.txt"
- -> insert "path/to" as first segments
- -> becomes "path/to" "/" "file.txt"
-
- "the/file.txt"
- -> insert "path/to" as first segments
- -> becomes "path/to" "/" "the/file.txt"
-
- The extra slash is not necessary when
- insertion is not at the first position:
-
- "path/file.txt"
- -> insert "to/the" as second segment
- -> becomes "path" "/to/the" "/file.txt"
-
- The extra slash is not necessary when
- the following position already has a slash
- (i.e. other existing valid segments):
-
- "/path/to/the/file.txt"
- -> replace "etc" as first segment
- -> becomes "/etc" "/to/the/file.txt"
-
-*/
- int suffix;
- // inserting non-empty segments at the
- // beginning of non-empty segments
- if( nseg > 0 &&
- i0 == 0 &&
- i1 == 0 &&
- u_.nseg_ != 0)
+//------------------------------------------------
+//
+// Resize
+//
+ op_t op(*this, src.input());
+ char* dest;
+ char const* end;
{
- suffix = 1;
- }
- else
- {
- suffix = 0;
- }
-
- // copy
- n += prefix + suffix;
- auto dest = resize_segments(
- i0, i1, n, nseg, op);
- char const *const last = dest + n;
-
-/* Write all characters in the destination:
-
- The output proceeds as:
-
- prefix [ segment [ '/' segment ] ] suffix
+ // amount we are removing
+ auto const nremove = pos1 - pos0;
+ nchar = prefix + nchar + suffix;
+/* if( nchar > max_size() ||
+ prefix + suffix > max_size() - nchar)
+ detail::throw_length_error(
+ "url_base::max_size");
+ if(nchar > max_size() - size())
+ detail::throw_length_error(
+ "url_base::max_size");
*/
+ auto const new_size =
+ size() + nchar - nremove;
+ reserve_impl(new_size, op);
+ dest = s_ + path_pos + pos0;
+ op.move(
+ dest + nchar,
+ s_ + path_pos + pos1,
+ size() - path_pos - pos1);
+ u_.set_size(
+ id_path,
+ u_.len(id_path) + nchar - nremove);
+ BOOST_ASSERT(size() == new_size);
+ end = dest + nchar;
+ u_.nseg_ = u_.nseg_ + nseg - (
+ it1.index - it0.index);
+ if(s_)
+ s_[size()] = '\0';
+ }
+
+//------------------------------------------------
+//
+// Output segments and internal separators:
+//
+// prefix [ segment [ '/' segment ] ] suffix
+//
switch(prefix)
{
case 3:
@@ -2093,33 +2032,28 @@ edit_segments(
default:
break;
}
-/*
- Output each segment, placing a slash
- only in between new segments. Leading
- or trailing separators are handled
- outside the loop.
-*/
+ src.rewind();
if(nseg > 0)
{
for(;;)
{
- it1.copy(dest, last);
+ src.copy(dest, end);
if(--nseg == 0)
break;
*dest++ = '/';
}
+ if(suffix)
+ *dest++ = '/';
}
- if(suffix == 1)
- *dest++ = '/';
+ // VFALCO This could be better
u_.decoded_[id_path] =
detail::decode_bytes_unchecked(
- u_.get(id_path));
-}
+ u_.get(id_path));}
//------------------------------------------------
-/* The query param range [i0, i1)
+/* The query param range [first, last)
is resized to contain `n` chars
and nparam elements.
*/
diff --git a/include/boost/url/param.hpp b/include/boost/url/param.hpp
index 29c0285a..f683c3e3 100644
--- a/include/boost/url/param.hpp
+++ b/include/boost/url/param.hpp
@@ -800,7 +800,7 @@ struct param_pct_view
*/
explicit
operator
- param()
+ param() const
{
return param(
static_cast(key),
@@ -808,6 +808,13 @@ struct param_pct_view
has_value);
}
+ operator
+ param_view() const noexcept
+ {
+ return param_view(
+ key, value, has_value);
+ }
+
#ifndef BOOST_URL_DOCS
// arrow support
param_pct_view const*
diff --git a/include/boost/url/params_const_encoded_view.hpp b/include/boost/url/params_const_encoded_view.hpp
index 091ac141..91d441c4 100644
--- a/include/boost/url/params_const_encoded_view.hpp
+++ b/include/boost/url/params_const_encoded_view.hpp
@@ -76,6 +76,8 @@ public:
@par Postconditions
@code
this->buffer().data() == other.buffer().data()
+ @endcode
+
@par Complexity
Constant.
diff --git a/include/boost/url/params_const_view.hpp b/include/boost/url/params_const_view.hpp
index 49cf3117..097a6f03 100644
--- a/include/boost/url/params_const_view.hpp
+++ b/include/boost/url/params_const_view.hpp
@@ -82,6 +82,8 @@ public:
@par Postconditions
@code
this->buffer().data() == other.buffer().data()
+ @endcode
+
@par Complexity
Constant.
diff --git a/include/boost/url/params_encoded_view.hpp b/include/boost/url/params_encoded_view.hpp
index 61fa6ccd..44319f4b 100644
--- a/include/boost/url/params_encoded_view.hpp
+++ b/include/boost/url/params_encoded_view.hpp
@@ -60,13 +60,13 @@ class url_base;
character buffer:
@li @ref append : Only `end()`.
@li @ref assign, @ref clear,
- `operator=` : All elements.
- @li @ref erase : Erased elements and all
- elements after (including `end()`).
- @li @ref insert : All elements at or after
+ `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
- elements and all elements
+ params and all params
after (including `end()`).
*/
class params_encoded_view
@@ -76,7 +76,6 @@ class params_encoded_view
url_base* u_ = nullptr;
- explicit
params_encoded_view(
url_base& u) noexcept;
@@ -149,6 +148,9 @@ public:
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
@@ -166,8 +168,10 @@ public:
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
- Exception thrown when init contains
- an invalid percent-encoding.
+ Exceptions thrown on invalid input.
+
+ @throw system_error
+ `init` contains an invalid percent-encoding.
@param init The list of params to assign.
*/
@@ -176,6 +180,12 @@ public:
param_pct_view> init);
/** Conversion
+
+ @par Complexity
+ Constant.
+
+ @par Exception Safety
+ Throws nothing.
*/
operator
params_const_encoded_view() const noexcept;
@@ -241,7 +251,7 @@ public:
//--------------------------------------------
- /** Assign elements
+ /** Assign params
This function replaces the entire
contents of the view with the params
@@ -268,8 +278,10 @@ public:
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
- Exception thrown when params contain
- an invalid percent-encoding.
+ Exceptions thrown on invalid input.
+
+ @throw system_error
+ `init` contains an invalid percent-encoding.
@param init The list of params to assign.
*/
@@ -277,7 +289,7 @@ public:
assign(std::initializer_list<
param_pct_view> init);
- /** Assign elements
+ /** Assign params
This function replaces the entire
contents of the view with the params
@@ -302,8 +314,10 @@ public:
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
- Exception thrown when params contain
- an invalid percent-encoding.
+ Exceptions thrown on invalid input.
+
+ @throw system_error
+ The range contains an invalid percent-encoding.
@param first, last The range of params
to assign.
@@ -314,7 +328,7 @@ public:
//--------------------------------------------
- /** Append elements
+ /** Append params
This function appends a param to the view.
@@ -334,8 +348,10 @@ public:
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
- Exception thrown when param contains
- an invalid percent-encoding.
+ Exceptions thrown on invalid input.
+
+ @throw system_error
+ `p` contains an invalid percent-encoding.
@return An iterator to the new element.
@@ -345,7 +361,7 @@ public:
append(
param_pct_view const& p);
- /** Append elements
+ /** Append params
This function appends a range of params
to the view.
@@ -368,8 +384,10 @@ public:
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
- Exception thrown when params contain
- an invalid percent-encoding.
+ Exceptions thrown on invalid input.
+
+ @throw system_error
+ The range contains an invalid percent-encoding.
@return An iterator to the first new element.
@@ -381,7 +399,7 @@ public:
append(
FwdIt first, FwdIt last);
- /** Append elements
+ /** Append params
This function appends the params in
an initializer-list to the view.
@@ -402,8 +420,10 @@ public:
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
- Exception thrown when params contain
- an invalid percent-encoding.
+ Exceptions thrown on invalid input.
+
+ @throw system_error
+ `init` contains an invalid percent-encoding.
@return An iterator to the first new element.
@@ -415,7 +435,7 @@ public:
//--------------------------------------------
- /** Insert elements
+ /** Insert params
This function inserts a param
before the specified position.
@@ -434,8 +454,10 @@ public:
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
- Exception thrown when param contains
- an invalid percent-encoding.
+ Exceptions thrown on invalid input.
+
+ @throw system_error
+ `p` contains an invalid percent-encoding.
@return An iterator to the inserted
element.
@@ -451,7 +473,7 @@ public:
iterator before,
param_pct_view const& p);
- /** Insert elements
+ /** Insert params
This function inserts a range of
params before the specified position.
@@ -480,8 +502,10 @@ public:
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
- Exception thrown when params contain
- an invalid percent-encoding.
+ 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
@@ -501,7 +525,7 @@ public:
FwdIt first,
FwdIt last);
- /** Insert elements
+ /** Insert params
This function inserts the params in
an initializer-list before
@@ -526,8 +550,10 @@ public:
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
- Exception thrown when params contain
- an invalid percent-encoding.
+ 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
@@ -547,7 +573,7 @@ public:
//--------------------------------------------
- /** Erase elements
+ /** Erase params
This function removes an element from
the container.
@@ -579,9 +605,9 @@ public:
iterator
erase(iterator pos) noexcept;
- /** Erase elements
+ /** Erase params
- This function removes a range of elements
+ This function removes a range of params
from the container.
@@ -602,14 +628,14 @@ public:
the removed range.
@param first, last The range of
- elements to erase.
+ params to erase.
*/
iterator
erase(
iterator first,
iterator last) noexcept;
- /** Erase elements
+ /** Erase params
All iterators are invalidated.
@@ -627,10 +653,12 @@ public:
Linear in `this->url().encoded_query().size()`.
@par Exception Safety
- Exception thrown when key contain
- an invalid percent-encoding.
+ Exceptions thrown on invalid input.
- @return The number of elements removed
+ @throw system_error
+ `key` contains an invalid percent-encoding.
+
+ @return The number of params removed
from the container.
@param key The key to match.
@@ -645,12 +673,12 @@ public:
BOOST_URL_DECL
std::size_t
erase(
- string_view key,
- ignore_case_param ic = {});
+ pct_string_view key,
+ ignore_case_param ic = {}) noexcept;
//--------------------------------------------
- /** Replace elements
+ /** Replace params
This function replaces the contents
of the element at `pos` with the
@@ -675,8 +703,10 @@ public:
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
- Exception thrown when param contains
- an invalid percent-encoding.
+ Exceptions thrown on invalid input.
+
+ @throw system_error
+ `p` contains an invalid percent-encoding.
@return An iterator to the element.
@@ -689,10 +719,10 @@ public:
iterator pos,
param_pct_view const& p);
- /** Replace elements
+ /** Replace params
This function replaces a range of
- elements with the params in an
+ params with the params in an
initializer-list.
@@ -710,14 +740,16 @@ public:
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
- Exception thrown when params contain
- an invalid percent-encoding.
+ 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 elements
+ @param from,to The range of params
to replace.
@param init The list of params to assign.
@@ -729,10 +761,10 @@ public:
std::initializer_list<
param_pct_view> init);
- /** Replace elements
+ /** Replace params
This function replaces a range of
- elements with a range of params.
+ params with a range of params.
All iterators that are equal to
@@ -754,14 +786,16 @@ public:
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
- Exception thrown when params contain
- an invalid percent-encoding.
+ 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,to The range of elements to
+ @param from,to The range of params to
replace.
@param first, last The range of params
@@ -836,6 +870,10 @@ public:
@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.
@@ -859,9 +897,9 @@ public:
`this->contains( key, ic )`.
@li If key is contained in the view
- then one of the matching elements has
+ then one of the matching params has
its value changed to the specified value.
- The remaining elements with a matching
+ The remaining params with a matching
key are erased. Otherwise,
@li If `key` is not contained in the
@@ -891,6 +929,11 @@ public:
@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.
diff --git a/include/boost/url/parse_path.hpp b/include/boost/url/parse_path.hpp
new file mode 100644
index 00000000..fd629497
--- /dev/null
+++ b/include/boost/url/parse_path.hpp
@@ -0,0 +1,55 @@
+//
+// 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/CPPAlliance/url
+//
+
+#ifndef BOOST_URL_PARSE_PATH_HPP
+#define BOOST_URL_PARSE_PATH_HPP
+
+#include
+#include
+#include
+
+namespace boost {
+namespace urls {
+
+/** Parse a string and return an encoded segment view
+
+ This function parses the string and returns the
+ corresponding path object if the string is valid,
+ otherwise returns an error.
+
+ @par BNF
+ @code
+ path = [ "/" ] segment *( "/" segment )
+ @endcode
+
+ @par Exception Safety
+ No-throw guarantee.
+
+ @return A valid view on success, otherwise an
+ error code.
+
+ @param s The string to parse
+
+ @par Specification
+ @li 3.3. Path (rfc3986)
+
+ @see
+ @ref parse_path,
+ @ref segments_encoded_view.
+*/
+BOOST_URL_DECL
+result
+parse_path(string_view s) noexcept;
+
+} // urls
+} // boost
+
+#endif
diff --git a/include/boost/url/pct_string_view.hpp b/include/boost/url/pct_string_view.hpp
index a6d3f967..d2195e71 100644
--- a/include/boost/url/pct_string_view.hpp
+++ b/include/boost/url/pct_string_view.hpp
@@ -12,7 +12,7 @@
#include
#include
-#include // VFALCO rethink this
+#include
#include
#include
#include
@@ -245,6 +245,15 @@ public:
return std::string(s_);
}
+#ifndef BOOST_URL_DOCS
+ // arrow support
+ pct_string_view const*
+ operator->() const noexcept
+ {
+ return this;
+ }
+#endif
+
//--------------------------------------------
// iterator support
diff --git a/include/boost/url/segments.hpp b/include/boost/url/segments.hpp
deleted file mode 100644
index 70e1b9b4..00000000
--- a/include/boost/url/segments.hpp
+++ /dev/null
@@ -1,731 +0,0 @@
-//
-// 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/CPPAlliance/url
-//
-
-#ifndef BOOST_URL_SEGMENTS_HPP
-#define BOOST_URL_SEGMENTS_HPP
-
-#include
-#include
-#include
-#include
-#include
-
-namespace boost {
-namespace urls {
-
-#ifndef BOOST_URL_DOCS
-class url_base;
-class segments_encoded;
-#endif
-
-/** A container referencing a random-access range of modifiable, percent-decoded path segments.
-
- This class implements a RandomAccessContainer
- representing the path segments in a @ref url as
- percent-encoded strings. Ownership of the segments
- is not transferred; the container references the
- buffer in the url. Therefore, the lifetime of the
- url must remain valid until this container no
- longer exists.
-
- Objects of this type are not constructed directly;
- Instead, call the corresponding non-const member
- function of @ref url to obtain an instance of
- the container:
-
- @par Example
- @code
- url u = parse_relative_ref( "/path/to/file.txt" );
-
- segments se = u.segments();
-
- for( segments::value_type s : se )
- std::cout << s << std::endl;
- @endcode
-
- The @ref reference and @ref const_reference
- nested types are defined as publicly accessible
- nested classes. They proxy the behavior of a
- reference to a percent-encoded string in the
- underlying URL. The primary use of these
- references is to provide l-values that can be
- returned from element-accessing operations.
- Any reads or writes which happen through a
- @ref reference or @ref const_reference
- potentially read or write the underlying
- @ref url.
-
- @see
- @ref url.
-*/
-class segments
- : private detail::parts_base
-{
- url_base* u_ = nullptr;
-
- friend class url_base;
- friend class segments_encoded;
-
- segments(url_base& u)
- : u_(&u)
- {
- }
-
-public:
- /** A read-only bidirectional iterator to a decoded segment.
-
- This is a read-only bidirectional iterator to
- the decoded segments.
-
- */
-#ifdef BOOST_URL_DOCS
- using iterator = __see_below__;
-#else
- class iterator;
-#endif
-
- /// @copydoc iterator
- using const_iterator = iterator;
-
- /** A type which can represent a segment as a value
-
- This type allows for making a copy of
- a segment where ownership is retained
- in the copy.
- */
- using value_type = std::string;
-
- /** A type which can represent a segment as a reference
-
- This type does not make a copy of a segment
- and ownership is retained by the container.
- */
- using reference = decode_view;
-
- /// @copydoc reference
- using const_reference = decode_view;
-
- /** An unsigned integer type
- */
- using size_type = std::size_t;
-
- /** A signed integer type
- */
- using difference_type = std::ptrdiff_t;
-
- //--------------------------------------------
- //
- // Members
- //
- //--------------------------------------------
-
- /** Returns true if this contains an absolute path.
-
- Absolute paths always start with a
- forward slash ('/').
- */
- bool
- is_absolute() const noexcept;
-
- /** Constructor
-
- After the copy, both views will point to
- the same underlying object.
-
- Ownership is not transferred; the caller
- is responsible for ensuring the lifetime
- of the character buffer extends until
- it is no longer referenced.
-
- @par Complexity
- Constant
-
- @par Exception Safety
- Throws nothing
-
- */
- segments(segments const&) = default;
-
- /** Assignment
-
- After the assignment, both views will point to
- the same underlying object.
-
- Ownership is not transferred; the caller
- is responsible for ensuring the lifetime
- of the character buffer extends until
- it is no longer referenced.
-
- @par Complexity
- Constant
-
- @par Exception Safety
- Throws nothing
-
- */
- segments&
- operator=(segments const&) & = default;
-
- /** Replace the contents of the container
-
- This function replaces the contents with
- an initializer list of unencoded strings.
-
- The behavior is undefined if any
- string refers to the contents of `*this`.
-
- All iterators and references to elements
- of the container are invalidated,
- including the @ref end iterator.
-
- @par Example
- @code
- url u = parse_relative_uri( "/path/to/file.txt" );
- u.segments() = { "etc", "init.rc" };
- assert( u.encoded_path() == "/etc/init.rc") );
- @endcode
-
- @par Exception Safety
- Strong guarantee.
- Calls to allocate may throw.
- Exceptions thrown on invalid input.
-
- @param init An initializer list of strings.
- */
- segments&
- operator=(std::initializer_list init);
-
- /** Replace the contents of the container
-
- This function replaces the contents
- with a range of percent-encoded
- strings.
- Each string must contain a valid
- percent-encoding or else an
- exception is thrown.
- The behavior is undefined if either
- argument is an iterator into `*this`.
- All iterators and references to elements
- of the container are invalidated,
- including the @ref end iterator.
-
- @par Requires
- @code
- std::is_convertible< std::iterator_traits< FwdIt >::reference_type, string_view >::value == true
- @endcode
-
- @par Example
- @code
- url u = parse_relative_uri( "/path/to/file.txt" );
-
- segments se = u.segments();
-
- std::vector< std::string > v = { "etc", "init.rc" };
-
- se.insert( u.end() - 1, v.begin(), v.end() );
-
- assert( u.encoded_path() == "/etc/init.rc") );
- @endcode
-
- @par Exception Safety
- Strong guarantee.
- Calls to allocate may throw.
- Exceptions thrown on invalid input.
-
- @param first An iterator to the first
- element in the range
-
- @param last An iterator to one past the
- last element in the range
-
- @throw std::invalid_argument invalid percent-encoding
- */
- template
-#ifdef BOOST_URL_DOCS
- void
-#else
- typename std::enable_if<
- std::is_convertible