diff --git a/.drone.star b/.drone.star index 64799fe8e..0b9ab911e 100644 --- a/.drone.star +++ b/.drone.star @@ -14,7 +14,7 @@ def main(ctx): return generate( # Compilers [ - 'gcc >=4.8', + 'gcc >=5.0', 'clang >=3.8', 'msvc >=14.1', 'arm64-gcc latest', diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7299f91ca..41be1a587 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,7 @@ jobs: id: cpp-matrix with: compilers: | - gcc >=4.8 + gcc >=5.0 clang >=3.8 msvc >=14.20 apple-clang * diff --git a/CMakeLists.txt b/CMakeLists.txt index a2f97dd5c..875723d19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,6 @@ set(BOOST_URL_DEPENDENCIES Boost::core Boost::mp11 Boost::optional - Boost::static_assert Boost::system Boost::throw_exception Boost::type_traits @@ -76,7 +75,7 @@ if (NOT BOOST_URL_MRDOCS_BUILD) set(BOOST_URL_UNIT_TEST_LIBRARIES container filesystem unordered) endif() if (BOOST_URL_BUILD_EXAMPLES) - set(BOOST_URL_EXAMPLE_LIBRARIES json regex beast) + set(BOOST_URL_EXAMPLE_LIBRARIES json regex beast filesystem) endif() endif() # Complete dependency list diff --git a/build.jam b/build.jam index 1e3ba3db4..c0732d11c 100644 --- a/build.jam +++ b/build.jam @@ -12,7 +12,6 @@ constant boost_dependencies : /boost/core//boost_core /boost/mp11//boost_mp11 /boost/optional//boost_optional - /boost/static_assert//boost_static_assert /boost/system//boost_system /boost/type_traits//boost_type_traits /boost/variant2//boost_variant2 ; diff --git a/doc/library-detail.adoc b/doc/library-detail.adoc index a06d1e755..d13ae539b 100644 --- a/doc/library-detail.adoc +++ b/doc/library-detail.adoc @@ -138,9 +138,9 @@ work without exceptions if desired. Boost.URL is tested with the following compilers: -* clang: 3.8, 4, 5, 6, 7, 8, 9, 10, 11, 12 -* gcc: 4.8, 4.9, 5, 6, 7, 8, 9, 10, 11 -* msvc: 14.0, 14.1, 14.2, 14.3 +* clang: >=3.8 +* gcc: >=5 +* msvc: >=14 and these architectures: x86, x64, ARM64, S390x diff --git a/example/router/impl/router.hpp b/example/router/impl/router.hpp index 12f694219..1cbc6da81 100644 --- a/example/router/impl/router.hpp +++ b/example/router/impl/router.hpp @@ -21,7 +21,7 @@ void router:: insert(core::string_view pattern, U&& v) { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( std::is_same::value || std::is_convertible::value || std::is_base_of::value); diff --git a/include/boost/url/detail/any_params_iter.hpp b/include/boost/url/detail/any_params_iter.hpp index eec1e008e..d1f902733 100644 --- a/include/boost/url/detail/any_params_iter.hpp +++ b/include/boost/url/detail/any_params_iter.hpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include @@ -177,7 +177,7 @@ struct params_iter : any_params_iter , private params_iter_base { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( std::is_convertible< typename std::iterator_traits< FwdIt>::reference, @@ -288,7 +288,7 @@ struct params_encoded_iter : any_params_iter , private params_encoded_iter_base { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( std::is_convertible< typename std::iterator_traits< FwdIt>::reference, diff --git a/include/boost/url/detail/any_segments_iter.hpp b/include/boost/url/detail/any_segments_iter.hpp index 25cc808e8..b88958d71 100644 --- a/include/boost/url/detail/any_segments_iter.hpp +++ b/include/boost/url/detail/any_segments_iter.hpp @@ -11,7 +11,7 @@ #define BOOST_URL_DETAIL_ANY_SEGMENTS_ITER_HPP #include -#include +#include #include #include #include @@ -120,7 +120,7 @@ struct segments_iter : any_segments_iter , segments_iter_base { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( std::is_convertible< typename std::iterator_traits< FwdIt>::reference, @@ -234,7 +234,7 @@ struct segments_encoded_iter : public any_segments_iter , public segments_encoded_iter_base { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( std::is_convertible< typename std::iterator_traits< FwdIt>::reference, diff --git a/include/boost/url/detail/segments_range.hpp b/include/boost/url/detail/segments_range.hpp new file mode 100644 index 000000000..4bd8c11e1 --- /dev/null +++ b/include/boost/url/detail/segments_range.hpp @@ -0,0 +1,163 @@ +// +// Copyright (c) 2025 Alan de Freitas (alandefreitas@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/url +// + +#ifndef BOOST_URL_DETAIL_SEGMENTS_RANGE_HPP +#define BOOST_URL_DETAIL_SEGMENTS_RANGE_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace urls { +namespace detail { + +struct segments_iter_access +{ + static + segments_iter_impl const& + impl(segments_base::iterator const& it) noexcept + { + return it.it_; + } + + static + segments_iter_impl const& + impl(segments_encoded_base::iterator const& it) noexcept + { + return it.it_; + } +}; + +inline +path_ref +make_subref_from_impls( + segments_iter_impl const& first, + segments_iter_impl const& last) noexcept +{ + BOOST_ASSERT(first.ref.alias_of(last.ref)); + path_ref const& ref = first.ref; + + std::size_t const i0 = first.index; + std::size_t const i1 = last.index; + BOOST_ASSERT(i0 <= i1); + std::size_t const nseg = i1 - i0; + + bool const absolute = ref.buffer().starts_with('/'); + + // Empty range + if (nseg == 0) + { + std::size_t off0; + if (i0 == 0) + { + // [begin, begin): don't include the leading '/' + // for absolute, start right after the leading '/'; + if (absolute) + { + off0 = 1; + } + // for relative, start at the first segment character. + else + { + off0 = first.pos; + } + } + else + { + // [it, it) in the middle: + // skip the separator before segment i0 + off0 = first.pos + 1; + } + + core::string_view const sub(ref.data() + off0, 0); + return {sub, 0, 0}; + } + + // General case: non-empty range + // Start offset + std::size_t off0; + bool include_leading_slash = false; + if (i0 == 0) + { + if (absolute) + { + // include leading '/' + off0 = 0; + include_leading_slash = true; + } + else + { + // relative: start at first segment + off0 = first.pos; + } + } + else + { + // skip slash before segment i0 + off0 = first.pos + 1; + } + + // End offset + std::size_t off1; + if(i1 == ref.nseg()) + { + off1 = ref.size(); + } + else + { + // stop before the slash preceding i1 + off1 = last.pos; + } + + BOOST_ASSERT(off1 >= off0); + core::string_view const sub(ref.data() + off0, off1 - off0); + + // Decoded-length: + // sum per-segment decoded lengths + internal '/' + the leading '/'. + std::size_t dn_sum = 0; + { + // copy to iterate + segments_iter_impl cur = first; + for (std::size_t k = 0; k < nseg; ++k) + { + // per-segment decoded length + dn_sum += cur.dn; + cur.increment(); + } + // internal '/'s + dn_sum += (nseg - 1); + // leading '/' + if (include_leading_slash) + { + ++dn_sum; + } + } + + return {sub, dn_sum, nseg}; +} + +template +inline +path_ref +make_subref(Iter const& first, Iter const& last) noexcept +{ + auto const& f = segments_iter_access::impl(first); + auto const& l = segments_iter_access::impl(last); + return make_subref_from_impls(f, l); +} + +} // detail +} // urls +} // boost + +#endif diff --git a/include/boost/url/grammar/charset.hpp b/include/boost/url/grammar/charset.hpp index 40c4d807b..b6e69a314 100644 --- a/include/boost/url/grammar/charset.hpp +++ b/include/boost/url/grammar/charset.hpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff --git a/include/boost/url/grammar/impl/range_rule.hpp b/include/boost/url/grammar/impl/range_rule.hpp index 06513e342..bdaf1d262 100644 --- a/include/boost/url/grammar/impl/range_rule.hpp +++ b/include/boost/url/grammar/impl/range_rule.hpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include @@ -464,7 +464,7 @@ range( : s_(s) , n_(n) { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( sizeof(impl1) <= BufferSize); @@ -487,7 +487,7 @@ range( : s_(s) , n_(n) { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( sizeof(impl2) <= BufferSize); diff --git a/include/boost/url/grammar/impl/variant_rule.hpp b/include/boost/url/grammar/impl/variant_rule.hpp index e14e58b5c..a0ca9b53d 100644 --- a/include/boost/url/grammar/impl/variant_rule.hpp +++ b/include/boost/url/grammar/impl/variant_rule.hpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include @@ -107,7 +107,7 @@ variant_rule( Rn const&... rn) noexcept -> implementation_defined::variant_rule_t { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( mp11::mp_all< is_rule, is_rule...>::value); diff --git a/include/boost/url/grammar/optional_rule.hpp b/include/boost/url/grammar/optional_rule.hpp index 4e8db4010..5513411e5 100644 --- a/include/boost/url/grammar/optional_rule.hpp +++ b/include/boost/url/grammar/optional_rule.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace boost { @@ -88,7 +89,7 @@ optional_rule( R const& r) -> implementation_defined::optional_rule_t { - BOOST_STATIC_ASSERT(grammar::is_rule::value); + BOOST_CORE_STATIC_ASSERT(grammar::is_rule::value); return { r }; } diff --git a/include/boost/url/grammar/range_rule.hpp b/include/boost/url/grammar/range_rule.hpp index 2ec0d79fa..2e3dfc0a7 100644 --- a/include/boost/url/grammar/range_rule.hpp +++ b/include/boost/url/grammar/range_rule.hpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/boost/url/grammar/tuple_rule.hpp b/include/boost/url/grammar/tuple_rule.hpp index 211263785..8d5d28b47 100644 --- a/include/boost/url/grammar/tuple_rule.hpp +++ b/include/boost/url/grammar/tuple_rule.hpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include @@ -132,7 +132,7 @@ tuple_rule( implementation_defined::tuple_rule_t< R0, Rn...> { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( mp11::mp_all< is_rule, is_rule...>::value); @@ -223,7 +223,7 @@ constexpr BOOST_URL_IMPLEMENTATION_DEFINED(implementation_defined::squelch_rule_t) squelch( R const& r ) noexcept { - BOOST_STATIC_ASSERT(is_rule::value); + BOOST_CORE_STATIC_ASSERT(is_rule::value); return { r }; } diff --git a/include/boost/url/grammar/unsigned_rule.hpp b/include/boost/url/grammar/unsigned_rule.hpp index 890b2fb52..62fbe3d78 100644 --- a/include/boost/url/grammar/unsigned_rule.hpp +++ b/include/boost/url/grammar/unsigned_rule.hpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include @@ -52,7 +52,7 @@ namespace grammar { template struct unsigned_rule { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( std::numeric_limits< Unsigned>::is_integer && ! std::numeric_limits< diff --git a/include/boost/url/impl/decode_view.hpp b/include/boost/url/impl/decode_view.hpp index eda72c1d8..6445eadf9 100644 --- a/include/boost/url/impl/decode_view.hpp +++ b/include/boost/url/impl/decode_view.hpp @@ -11,7 +11,7 @@ #define BOOST_URL_IMPL_PCT_ENCODED_VIEW_HPP #include -#include +#include namespace boost { namespace urls { diff --git a/include/boost/url/impl/encode.hpp b/include/boost/url/impl/encode.hpp index 2dff15a20..1ff8d409b 100644 --- a/include/boost/url/impl/encode.hpp +++ b/include/boost/url/impl/encode.hpp @@ -12,7 +12,7 @@ #include "boost/url/grammar/token_rule.hpp" #include -#include +#include #include #include #include @@ -39,7 +39,7 @@ encoded_size( not meet the requirements stated in the documentation. */ - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( grammar::is_charset::value); std::size_t n = 0; @@ -111,7 +111,7 @@ encode( not meet the requirements stated in the documentation. */ - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( grammar::is_charset::value); // '%' must be reserved @@ -200,7 +200,7 @@ encode_unsafe( CS const& allowed, encoding_opts opt) { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( grammar::is_charset::value); // '%' must be reserved @@ -281,7 +281,7 @@ encode( encoding_opts opt, StringToken&& token) noexcept { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( grammar::is_charset::value); auto const n = encoded_size( diff --git a/include/boost/url/impl/segments_base.hpp b/include/boost/url/impl/segments_base.hpp index 9b10b5849..91ab37bd2 100644 --- a/include/boost/url/impl/segments_base.hpp +++ b/include/boost/url/impl/segments_base.hpp @@ -17,6 +17,9 @@ namespace boost { namespace urls { +namespace detail { +struct segments_iter_access; +} class segments_base::iterator { @@ -24,6 +27,7 @@ class segments_base::iterator friend class segments_base; friend class segments_ref; + friend struct detail::segments_iter_access; iterator(detail::path_ref const&) noexcept; iterator(detail::path_ref const&, int) noexcept; diff --git a/include/boost/url/impl/segments_encoded_base.hpp b/include/boost/url/impl/segments_encoded_base.hpp index 908214d95..7b57cee19 100644 --- a/include/boost/url/impl/segments_encoded_base.hpp +++ b/include/boost/url/impl/segments_encoded_base.hpp @@ -16,6 +16,9 @@ namespace boost { namespace urls { +namespace detail { +struct segments_iter_access; +} class segments_encoded_base::iterator { @@ -24,6 +27,7 @@ class segments_encoded_base::iterator friend class url_base; friend class segments_encoded_base; friend class segments_encoded_ref; + friend struct detail::segments_iter_access; iterator(detail::path_ref const&) noexcept; iterator(detail::path_ref const&, int) noexcept; diff --git a/include/boost/url/segments_encoded_view.hpp b/include/boost/url/segments_encoded_view.hpp index 63ece3df6..a9dffe50e 100644 --- a/include/boost/url/segments_encoded_view.hpp +++ b/include/boost/url/segments_encoded_view.hpp @@ -167,6 +167,53 @@ class segments_encoded_view segments_encoded_view( core::string_view s); + /** Constructor + + This function creates a new @ref segments_encoded_view + from a pair of iterators referring to + elements of another encoded segments + view. The resulting view references + the same underlying character buffer + as the original. + + The caller is responsible for ensuring + that the lifetime of the original buffer + extends until the constructed view + is no longer referenced. + + @par Example + @code + segments_encoded_view ps( "/path/to/file.txt" ); + + segments_encoded_view sub( + std::next(ps.begin()), + ps.end()); + + // sub represents "to/file.txt" + @endcode + + @par Preconditions + The iterators must be valid and belong to + the same @ref segments_encoded_view. + + @par Postconditions + `sub.buffer()` references characters in the + original `ps.buffer()`. + + @par Complexity + Linear in `sub.buffer()` + + @par Exception Safety + Throws nothing. + + @param first The beginning iterator. + @param last The ending iterator. + */ + BOOST_URL_DECL + segments_encoded_view( + iterator first, + iterator last) noexcept; + /** Assignment After assignment, both views diff --git a/include/boost/url/segments_view.hpp b/include/boost/url/segments_view.hpp index 32fd5f6b3..9f6135cfb 100644 --- a/include/boost/url/segments_view.hpp +++ b/include/boost/url/segments_view.hpp @@ -165,6 +165,53 @@ class segments_view segments_view( core::string_view s); + /** Constructor + + This function creates a new @ref segments_view + from a pair of iterators referring to + elements of another segments view. The + resulting view references the same + underlying character buffer as the + original. + + The caller is responsible for ensuring + that the lifetime of the original buffer + extends until the constructed view is no + longer referenced. + + @par Example + @code + segments_view ps( "/path/to/file.txt" ); + + segments_view sub( + std::next(ps.begin()), + ps.end()); + + // sub represents "to/file.txt" + @endcode + + @par Preconditions + The iterators must be valid and belong to + the same @ref segments_view. + + @par Postconditions + `sub.buffer()` references characters in the + original `ps.buffer()`. + + @par Complexity + Linear in `sub.buffer()` + + @par Exception Safety + Throws nothing. + + @param first The beginning iterator. + @param last The ending iterator. + */ + BOOST_URL_DECL + segments_view( + iterator first, + iterator last) noexcept; + /** Assignment After assignment, both views diff --git a/include/boost/url/static_url.hpp b/include/boost/url/static_url.hpp index 5313135d8..8ccbb6a86 100644 --- a/include/boost/url/static_url.hpp +++ b/include/boost/url/static_url.hpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include namespace boost { diff --git a/src/rfc/detail/port_rule.cpp b/src/rfc/detail/port_rule.cpp index 09304f9c1..ee9516a8b 100644 --- a/src/rfc/detail/port_rule.cpp +++ b/src/rfc/detail/port_rule.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include namespace boost { diff --git a/src/segments_encoded_view.cpp b/src/segments_encoded_view.cpp index edf5047ae..2837e8155 100644 --- a/src/segments_encoded_view.cpp +++ b/src/segments_encoded_view.cpp @@ -10,6 +10,7 @@ #include +#include #include #include @@ -32,6 +33,12 @@ segments_encoded_view( { } +segments_encoded_view:: +segments_encoded_view(iterator first, iterator last) noexcept + : segments_encoded_base(detail::make_subref(first, last)) +{ +} + segments_encoded_view:: operator segments_view() const noexcept diff --git a/src/segments_view.cpp b/src/segments_view.cpp index ebaa60d02..e36dd31cf 100644 --- a/src/segments_view.cpp +++ b/src/segments_view.cpp @@ -10,6 +10,7 @@ #include +#include #include #include @@ -32,6 +33,12 @@ segments_view( { } +segments_view:: +segments_view(iterator first, iterator last) noexcept + : segments_base(detail::make_subref(first, last)) +{ +} + } // urls } // boost diff --git a/test/unit/grammar/charset.cpp b/test/unit/grammar/charset.cpp index 442ac7b77..34507720a 100644 --- a/test/unit/grammar/charset.cpp +++ b/test/unit/grammar/charset.cpp @@ -64,18 +64,18 @@ class charset_test } }; - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( detail::has_find_if< test_chars>::value); - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( detail::has_find_if_not< test_chars>::value); void testRef() { - BOOST_STATIC_ASSERT(is_charset< + BOOST_CORE_STATIC_ASSERT(is_charset< decltype(ref(alpha_chars))>::value); BOOST_TEST(parse("abc", token_rule( ref(alpha_chars))).has_value()); diff --git a/test/unit/grammar/grammar_parse.cpp b/test/unit/grammar/grammar_parse.cpp index 3bdbd1f75..fe718b93e 100644 --- a/test/unit/grammar/grammar_parse.cpp +++ b/test/unit/grammar/grammar_parse.cpp @@ -24,7 +24,7 @@ struct parse_test void testRef() { - BOOST_STATIC_ASSERT(is_rule< + BOOST_CORE_STATIC_ASSERT(is_rule< decltype(ref(dec_octet_rule))>::value); BOOST_TEST(parse("255", ref(dec_octet_rule)).has_value()); diff --git a/test/unit/grammar/literal_rule.cpp b/test/unit/grammar/literal_rule.cpp index 565636eaa..bc1adfb1f 100644 --- a/test/unit/grammar/literal_rule.cpp +++ b/test/unit/grammar/literal_rule.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include "test_rule.hpp" @@ -19,7 +19,7 @@ namespace boost { namespace urls { namespace grammar { -BOOST_STATIC_ASSERT(is_rule::value); +BOOST_CORE_STATIC_ASSERT(is_rule::value); struct literal_rule_test { diff --git a/test/unit/param.cpp b/test/unit/param.cpp index 70052423f..493ce848e 100644 --- a/test/unit/param.cpp +++ b/test/unit/param.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include "test_suite.hpp" @@ -20,32 +21,32 @@ namespace urls { struct param_test { - BOOST_STATIC_ASSERT(std::is_copy_constructible::value); - BOOST_STATIC_ASSERT(std::is_copy_assignable::value); - BOOST_STATIC_ASSERT(std::is_move_constructible::value); - BOOST_STATIC_ASSERT(std::is_move_assignable::value); + BOOST_CORE_STATIC_ASSERT(std::is_copy_constructible::value); + BOOST_CORE_STATIC_ASSERT(std::is_copy_assignable::value); + BOOST_CORE_STATIC_ASSERT(std::is_move_constructible::value); + BOOST_CORE_STATIC_ASSERT(std::is_move_assignable::value); - BOOST_STATIC_ASSERT(std::is_copy_constructible::value); - BOOST_STATIC_ASSERT(std::is_copy_assignable::value); - BOOST_STATIC_ASSERT(std::is_move_constructible::value); - BOOST_STATIC_ASSERT(std::is_move_assignable::value); + BOOST_CORE_STATIC_ASSERT(std::is_copy_constructible::value); + BOOST_CORE_STATIC_ASSERT(std::is_copy_assignable::value); + BOOST_CORE_STATIC_ASSERT(std::is_move_constructible::value); + BOOST_CORE_STATIC_ASSERT(std::is_move_assignable::value); - BOOST_STATIC_ASSERT(std::is_copy_constructible::value); - BOOST_STATIC_ASSERT(std::is_copy_assignable::value); - BOOST_STATIC_ASSERT(std::is_move_constructible::value); - BOOST_STATIC_ASSERT(std::is_move_assignable::value); + BOOST_CORE_STATIC_ASSERT(std::is_copy_constructible::value); + BOOST_CORE_STATIC_ASSERT(std::is_copy_assignable::value); + BOOST_CORE_STATIC_ASSERT(std::is_move_constructible::value); + BOOST_CORE_STATIC_ASSERT(std::is_move_assignable::value); - BOOST_STATIC_ASSERT(std::is_constructible::value); + BOOST_CORE_STATIC_ASSERT(std::is_constructible::value); // explicit, expensive - BOOST_STATIC_ASSERT(std::is_constructible::value); + BOOST_CORE_STATIC_ASSERT(std::is_constructible::value); // cheap, loses pct-validation - BOOST_STATIC_ASSERT(std::is_constructible::value); + BOOST_CORE_STATIC_ASSERT(std::is_constructible::value); // expensive constructions - BOOST_STATIC_ASSERT(std::is_constructible::value); - BOOST_STATIC_ASSERT(std::is_constructible::value); + BOOST_CORE_STATIC_ASSERT(std::is_constructible::value); + BOOST_CORE_STATIC_ASSERT(std::is_constructible::value); void testParam() diff --git a/test/unit/params_base.cpp b/test/unit/params_base.cpp index aa5193286..4000ae4cf 100644 --- a/test/unit/params_base.cpp +++ b/test/unit/params_base.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include "test_suite.hpp" @@ -24,19 +24,19 @@ namespace boost { namespace urls { -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_default_constructible< params_base>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_copy_constructible< params_base>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_copy_assignable< params_base>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< params_base::iterator>::value); diff --git a/test/unit/params_encoded_base.cpp b/test/unit/params_encoded_base.cpp index 9553e504e..be43f01e0 100644 --- a/test/unit/params_encoded_base.cpp +++ b/test/unit/params_encoded_base.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include "test_suite.hpp" @@ -24,19 +24,19 @@ namespace boost { namespace urls { -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_default_constructible< params_encoded_base>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_copy_constructible< params_encoded_base>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_copy_assignable< params_encoded_base>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< params_encoded_base::iterator>::value); diff --git a/test/unit/params_encoded_ref.cpp b/test/unit/params_encoded_ref.cpp index 21f4af911..9949cc6e4 100644 --- a/test/unit/params_encoded_ref.cpp +++ b/test/unit/params_encoded_ref.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include "test_suite.hpp" @@ -29,15 +29,15 @@ namespace boost { namespace urls { -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_default_constructible< params_encoded_ref>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_constructible< params_encoded_ref>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_assignable< params_encoded_ref>::value); diff --git a/test/unit/params_encoded_view.cpp b/test/unit/params_encoded_view.cpp index 710ab4003..296ed00ff 100644 --- a/test/unit/params_encoded_view.cpp +++ b/test/unit/params_encoded_view.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include "test_suite.hpp" @@ -27,19 +27,19 @@ namespace urls { #endif #define assert BOOST_TEST -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< params_encoded_view>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_constructible< params_encoded_view>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_assignable< params_encoded_view>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< params_encoded_view::iterator>::value); diff --git a/test/unit/params_ref.cpp b/test/unit/params_ref.cpp index e83d0cb5c..f65ee9aed 100644 --- a/test/unit/params_ref.cpp +++ b/test/unit/params_ref.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include "test_suite.hpp" @@ -29,15 +29,15 @@ namespace boost { namespace urls { -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_default_constructible< params_ref>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_constructible< params_ref>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_assignable< params_ref>::value); diff --git a/test/unit/params_view.cpp b/test/unit/params_view.cpp index abb9bca26..065dbf56d 100644 --- a/test/unit/params_view.cpp +++ b/test/unit/params_view.cpp @@ -12,7 +12,7 @@ #include #include -#include +#include #include "test_suite.hpp" @@ -24,19 +24,19 @@ namespace urls { #endif #define assert BOOST_TEST -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< params_view>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_constructible< params_view>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_assignable< params_view>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< params_view::iterator>::value); diff --git a/test/unit/segments_base.cpp b/test/unit/segments_base.cpp index b077a1359..77f095a04 100644 --- a/test/unit/segments_base.cpp +++ b/test/unit/segments_base.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "test_suite.hpp" @@ -27,19 +27,19 @@ namespace boost { namespace urls { -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_default_constructible< segments_base>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_copy_constructible< segments_base>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_copy_assignable< segments_base>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< segments_base::iterator>::value); diff --git a/test/unit/segments_encoded_base.cpp b/test/unit/segments_encoded_base.cpp index 6c6f21fbb..4348f1554 100644 --- a/test/unit/segments_encoded_base.cpp +++ b/test/unit/segments_encoded_base.cpp @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "test_suite.hpp" @@ -27,19 +27,19 @@ namespace urls { #endif #define assert BOOST_TEST -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_default_constructible< segments_encoded_base>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_copy_constructible< segments_encoded_base>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_copy_assignable< segments_encoded_base>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< segments_encoded_base::iterator>::value); diff --git a/test/unit/segments_encoded_ref.cpp b/test/unit/segments_encoded_ref.cpp index 326a397bb..7fdd6a230 100644 --- a/test/unit/segments_encoded_ref.cpp +++ b/test/unit/segments_encoded_ref.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include "test_suite.hpp" @@ -32,19 +32,19 @@ namespace urls { #endif #define assert BOOST_TEST -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_default_constructible< segments_encoded_ref>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_constructible< segments_encoded_ref>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_assignable< segments_encoded_ref>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< segments_encoded_ref::iterator>::value); diff --git a/test/unit/segments_encoded_view.cpp b/test/unit/segments_encoded_view.cpp index 0074ded7d..a7be0e089 100644 --- a/test/unit/segments_encoded_view.cpp +++ b/test/unit/segments_encoded_view.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include "test_suite.hpp" @@ -28,19 +28,19 @@ namespace boost { namespace urls { -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< segments_encoded_view>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_constructible< segments_encoded_view>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_assignable< segments_encoded_view>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< segments_encoded_view::iterator>::value); @@ -95,6 +95,23 @@ struct segments_const_encoded_view_test BOOST_TEST_THROWS(segments_encoded_view("FA%"), system::system_error); } + // segments_encoded_view(iterator, iterator) + { + segments_encoded_view ps = parse_path("/a/b/c").value(); + auto first = std::next(ps.begin()); + auto last = ps.end(); + segments_encoded_view sub(first, last); + + BOOST_TEST_EQ(sub.size(), 2u); + BOOST_TEST(!sub.is_absolute()); + BOOST_TEST_EQ(sub.buffer(), "b/c"); + + auto it = sub.begin(); + BOOST_TEST_EQ(*it++, "b"); + BOOST_TEST_EQ(*it++, "c"); + BOOST_TEST(it == sub.end()); + } + // operator=(segments_encoded_view) { segments_encoded_view ps0("/path/to/file.txt"); diff --git a/test/unit/segments_ref.cpp b/test/unit/segments_ref.cpp index 09936fa89..ebf99ca4a 100644 --- a/test/unit/segments_ref.cpp +++ b/test/unit/segments_ref.cpp @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include "test_suite.hpp" @@ -26,19 +26,19 @@ namespace boost { namespace urls { -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( ! std::is_default_constructible< segments_ref>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_constructible< segments_ref>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_assignable< segments_ref>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< segments_ref::iterator>::value); diff --git a/test/unit/segments_view.cpp b/test/unit/segments_view.cpp index 4609ea4fb..37cdefe9c 100644 --- a/test/unit/segments_view.cpp +++ b/test/unit/segments_view.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include "test_suite.hpp" @@ -28,19 +28,19 @@ namespace boost { namespace urls { -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< segments_view>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_constructible< segments_view>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_copy_assignable< segments_view>::value); -BOOST_STATIC_ASSERT( +BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< segments_view::iterator>::value); @@ -116,6 +116,240 @@ struct segments_view_test } } + void + testRangeCtor() + { + // full slice equals original (absolute path) + { + segments_view ps = parse_path("/a/b/c").value(); + segments_view sub(ps.begin(), ps.end()); + + BOOST_TEST_EQ(sub.size(), 3u); + BOOST_TEST(sub.is_absolute()); + BOOST_TEST_EQ(sub.buffer(), "/a/b/c"); + // alias same storage + BOOST_TEST_EQ(sub.buffer().data(), ps.buffer().data()); + } + + // full slice equals original (relative path) + { + segments_view ps = parse_path("a/b/c").value(); + segments_view sub(ps.begin(), ps.end()); + + BOOST_TEST_EQ(sub.size(), 3u); + BOOST_TEST(!sub.is_absolute()); + BOOST_TEST_EQ(sub.buffer(), "a/b/c"); + // alias same storage + BOOST_TEST_EQ(sub.buffer().data(), ps.buffer().data()); + } + + // drop first segment: start at index 1 (no leading slash) + { + segments_view ps = parse_path("/a/b/c").value(); + auto first = std::next(ps.begin()); + auto last = ps.end(); + segments_view sub(first, last); + + BOOST_TEST_EQ(sub.size(), 2u); + BOOST_TEST(!sub.is_absolute()); + BOOST_TEST_EQ(sub.buffer(), "b/c"); + + auto it = sub.begin(); + BOOST_TEST_EQ(*it++, "b"); + BOOST_TEST_EQ(*it++, "c"); + BOOST_TEST(it == sub.end()); + } + + // take prefix without the last segment: + // [begin, prev(end)) -> "/a/b" + { + segments_view ps = parse_path("/a/b/c").value(); + auto first = ps.begin(); + auto last = std::prev(ps.end()); + segments_view sub(first, last); + + BOOST_TEST_EQ(sub.size(), 2u); + BOOST_TEST(sub.is_absolute()); + BOOST_TEST_EQ(sub.buffer(), "/a/b"); + + auto it = sub.begin(); + BOOST_TEST_EQ(*it++, "a"); + BOOST_TEST_EQ(*it++, "b"); + BOOST_TEST(it == sub.end()); + } + + // single segment in the middle: + // ["b", past "b") -> "b" + { + segments_view ps = parse_path("/a/b/c").value(); + auto b = std::next(ps.begin()); + auto e = std::next(b); + segments_view sub(b, e); + + BOOST_TEST_EQ(sub.size(), 1u); + BOOST_TEST(!sub.is_absolute()); + BOOST_TEST_EQ(sub.buffer(), "b"); + BOOST_TEST_EQ(*sub.begin(), "b"); + } + + // relative path: + // no leading slash preserved in any slice + { + segments_view ps = parse_path("a/b/c").value(); + + // full slice + segments_view sub1(ps.begin(), ps.end()); + BOOST_TEST_EQ(sub1.size(), 3u); + BOOST_TEST(!sub1.is_absolute()); + BOOST_TEST_EQ(sub1.buffer(), "a/b/c"); + + // prefix [begin, prev(end)) -> "a/b" + segments_view sub2(ps.begin(), std::prev(ps.end())); + BOOST_TEST_EQ(sub2.size(), 2u); + BOOST_TEST(!sub2.is_absolute()); + BOOST_TEST_EQ(sub2.buffer(), "a/b"); + + // middle one ["b", past "b") -> "b" + auto b = std::next(ps.begin()); + segments_view sub3(b, std::next(b)); + BOOST_TEST_EQ(sub3.size(), 1u); + BOOST_TEST(!sub3.is_absolute()); + BOOST_TEST_EQ(sub3.buffer(), "b"); + } + + // empty subrange [it, it): + // empty buffer, not absolute + { + segments_view ps = parse_path("/a/b").value(); + auto it = ps.begin(); + segments_view sub(it, it); + + BOOST_TEST_EQ(sub.size(), 0u); + BOOST_TEST(!sub.is_absolute()); + BOOST_TEST_EQ(sub.buffer(), ""); + BOOST_TEST(sub.begin() == sub.end()); + } + + // empty subrange from relative source + { + segments_view ps = parse_path("a/b").value(); + auto it = ps.begin(); + segments_view sub(it, it); + + BOOST_TEST_EQ(sub.size(), 0u); + BOOST_TEST(!sub.is_absolute()); + BOOST_TEST_EQ(sub.buffer(), ""); + BOOST_TEST(sub.begin() == sub.end()); + } + + // percent-encoding: + // slice of first encoded segment only, absolute start + { + segments_view ps = parse_path("/a%2Fb/c").value(); + auto first = ps.begin(); + auto last = std::next(ps.begin()); + segments_view sub(first, last); + + // encoded in buffer + BOOST_TEST(sub.is_absolute()); + BOOST_TEST_EQ(sub.size(), 1u); + BOOST_TEST_EQ(sub.buffer(), "/a%2Fb"); + + // decoded on deref + auto it = sub.begin(); + BOOST_TEST_EQ(*it++, "a/b"); + BOOST_TEST(it == sub.end()); + } + + // aliasing: url_view -> segments_view -> subrange + { + url_view u("/x/y"); + segments_view ps = u.segments(); + segments_view sub(ps.begin(), ps.end()); + + BOOST_TEST_EQ(sub.buffer().data(), u.buffer().data()); + BOOST_TEST_EQ(sub.buffer(), "/x/y"); + BOOST_TEST(sub.is_absolute()); + BOOST_TEST_EQ(sub.size(), 2u); + } + + // empty prefix of absolute path: + // [begin, begin) -> empty + { + segments_view ps = parse_path("/a/b/c").value(); + segments_view sub(ps.begin(), ps.begin()); + BOOST_TEST_EQ(sub.size(), 0u); + BOOST_TEST_EQ(sub.buffer(), ""); + BOOST_TEST(!sub.is_absolute()); + } + + // empty subrange in the middle (absolute): + // ["b","b") -> "", not absolute + { + segments_view ps = parse_path("/a/b/c").value(); + auto b = std::next(ps.begin()); + segments_view sub(b, b); + + BOOST_TEST_EQ(sub.size(), 0u); + BOOST_TEST_EQ(sub.buffer(), ""); + BOOST_TEST(!sub.is_absolute()); + BOOST_TEST(sub.begin() == sub.end()); + } + + // empty subrange in the middle (relative): + // ["b","b") -> "", not absolute + { + segments_view ps = parse_path("a/b/c").value(); + auto b = std::next(ps.begin()); // "b" + segments_view sub(b, b); + + BOOST_TEST_EQ(sub.size(), 0u); + BOOST_TEST_EQ(sub.buffer(), ""); + BOOST_TEST(!sub.is_absolute()); + BOOST_TEST(sub.begin() == sub.end()); + } + + // empty subrange at end: + // [end,end) -> "", not absolute + { + segments_view ps = parse_path("/a/b/c").value(); + auto e = ps.end(); + segments_view sub(e, e); + + BOOST_TEST_EQ(sub.size(), 0u); + BOOST_TEST_EQ(sub.buffer(), ""); + BOOST_TEST(!sub.is_absolute()); + } + + // single-segment absolute path full slice: "/a" + { + segments_view ps = parse_path("/a").value(); + segments_view sub(ps.begin(), ps.end()); + + BOOST_TEST_EQ(sub.size(), 1u); + BOOST_TEST(sub.is_absolute()); + BOOST_TEST_EQ(sub.buffer(), "/a"); + + auto it = sub.begin(); + BOOST_TEST_EQ(*it++, "a"); + BOOST_TEST(it == sub.end()); + } + + // middle slice using last.pos path: + // ["b", prev(end)) on "/a/b/c" -> "b" + { + segments_view ps = parse_path("/a/b/c").value(); + auto b = std::next(ps.begin()); + auto last = std::prev(ps.end()); + segments_view sub(b, last); + + BOOST_TEST_EQ(sub.size(), 1u); + BOOST_TEST(!sub.is_absolute()); + BOOST_TEST_EQ(sub.buffer(), "b"); + BOOST_TEST_EQ(*sub.begin(), "b"); + } + } + void testJavadocs() { @@ -135,6 +369,7 @@ struct segments_view_test run() { testSpecialMembers(); + testRangeCtor(); testJavadocs(); } }; diff --git a/test/unit/static_url.cpp b/test/unit/static_url.cpp index 327b75b16..79c39bbea 100644 --- a/test/unit/static_url.cpp +++ b/test/unit/static_url.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include "test_suite.hpp" @@ -26,23 +26,23 @@ namespace urls { struct static_url_test { - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( std::is_default_constructible< static_url<10>>::value); - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( std::is_copy_constructible< static_url<10>>::value); - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( std::is_copy_assignable< static_url<10>>::value); - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( std::is_convertible< static_url<10>, url_view>::value); - BOOST_STATIC_ASSERT( + BOOST_CORE_STATIC_ASSERT( std::is_convertible< static_url<10>, url>::value);