From ced6e9fcecb4e306e8f491f36dfa70b7413613ce Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Mon, 1 Aug 2022 13:41:07 -0700 Subject: [PATCH] Range work and rule refactoring --- doc/qbk/quickref.xml | 5 - include/boost/url.hpp | 2 +- include/boost/url/detail/empty_value.hpp | 162 +++++++ .../impl/segments_encoded_iterator_impl.ipp | 12 +- .../detail/impl/segments_iterator_impl.ipp | 14 +- include/boost/url/detail/impl/url_impl.ipp | 10 +- include/boost/url/detail/over_allocator.hpp | 12 +- include/boost/url/detail/url_impl.hpp | 7 +- include/boost/url/grammar/error.hpp | 10 +- .../boost/url/grammar/impl/not_empty_rule.hpp | 2 +- include/boost/url/grammar/impl/range_rule.hpp | 447 +++++++++++------- .../boost/url/grammar/impl/sequence_rule.hpp | 2 +- .../boost/url/grammar/impl/variant_rule.hpp | 2 +- include/boost/url/grammar/not_empty_rule.hpp | 7 +- include/boost/url/grammar/optional_rule.hpp | 9 +- include/boost/url/grammar/range_rule.hpp | 78 +-- include/boost/url/grammar/sequence_rule.hpp | 10 +- include/boost/url/grammar/variant_rule.hpp | 10 +- .../boost/url/impl/segments_encoded_view.hpp | 1 - .../boost/url/impl/segments_encoded_view.ipp | 6 +- include/boost/url/impl/segments_view.ipp | 3 - include/boost/url/impl/url.ipp | 2 +- include/boost/url/impl/url_view.ipp | 2 +- .../boost/url/rfc/detail/fragment_rule.hpp | 2 +- .../boost/url/rfc/detail/hier_part_rule.hpp | 8 +- .../url/rfc/detail/impl/hier_part_rule.ipp | 15 +- .../boost/url/rfc/detail/impl/path_rules.ipp | 45 ++ .../rfc/detail/impl/relative_part_rule.ipp | 14 +- .../url/rfc/detail/impl/userinfo_rule.ipp | 4 +- .../boost/url/rfc/detail/path_increment.hpp | 53 --- .../{segment_rule.hpp => path_rules.hpp} | 69 ++- .../url/rfc/detail/relative_part_rule.hpp | 5 +- .../boost/url/rfc/impl/absolute_uri_rule.ipp | 4 +- include/boost/url/rfc/impl/paths_rule.ipp | 122 ----- .../boost/url/rfc/impl/pct_encoded_rule.hpp | 42 +- include/boost/url/rfc/impl/query_rule.ipp | 9 +- .../boost/url/rfc/impl/relative_ref_rule.ipp | 4 +- include/boost/url/rfc/impl/uri_rule.ipp | 4 +- .../rfc/{paths_rule.hpp => path_rules.hpp} | 103 ++-- include/boost/url/rfc/pct_encoded_rule.hpp | 64 ++- include/boost/url/src.hpp | 2 +- test/unit/CMakeLists.txt | 2 +- test/unit/Jamfile | 2 +- test/unit/grammar/char_rule.cpp | 1 + test/unit/grammar/dec_octet_rule.cpp | 1 + test/unit/grammar/not_empty_rule.cpp | 1 + test/unit/grammar/range_rule.cpp | 38 +- test/unit/grammar/sequence_rule.cpp | 1 + test/unit/grammar/token_rule.cpp | 1 + test/unit/grammar/unsigned_dec_rule.cpp | 1 + test/unit/grammar/variant_rule.cpp | 1 + .../rfc/{paths_rule.cpp => path_rules.cpp} | 8 +- test/unit/test_rule.hpp | 8 +- 53 files changed, 867 insertions(+), 582 deletions(-) create mode 100644 include/boost/url/detail/empty_value.hpp create mode 100644 include/boost/url/rfc/detail/impl/path_rules.ipp delete mode 100644 include/boost/url/rfc/detail/path_increment.hpp rename include/boost/url/rfc/detail/{segment_rule.hpp => path_rules.hpp} (61%) delete mode 100644 include/boost/url/rfc/impl/paths_rule.ipp rename include/boost/url/rfc/{paths_rule.hpp => path_rules.hpp} (60%) rename test/unit/rfc/{paths_rule.cpp => path_rules.cpp} (96%) diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml index 1b2ccad7..53e7d14d 100644 --- a/doc/qbk/quickref.xml +++ b/doc/qbk/quickref.xml @@ -140,11 +140,6 @@ pct_encoded_rule - Types - - parsed_path - - CharSets gen_delim_chars diff --git a/include/boost/url.hpp b/include/boost/url.hpp index c4b84f34..c2752d60 100644 --- a/include/boost/url.hpp +++ b/include/boost/url.hpp @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/boost/url/detail/empty_value.hpp b/include/boost/url/detail/empty_value.hpp new file mode 100644 index 00000000..284bc2f0 --- /dev/null +++ b/include/boost/url/detail/empty_value.hpp @@ -0,0 +1,162 @@ +/* +Copyright 2018 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Copyright 2022 Vinnie Falco +(vinnie dot falco at gmail dot com) +* Added constexpr +* removed pre-C++11 support + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_URL_DETAIL_EMPTY_VALUE_HPP +#define BOOST_URL_DETAIL_EMPTY_VALUE_HPP + +#include +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#include +#endif + +#if defined(BOOST_GCC_VERSION) && (BOOST_GCC_VERSION >= 40700) +#define BOOST_DETAIL_EMPTY_VALUE_BASE +#elif defined(BOOST_INTEL) && defined(_MSC_VER) && (_MSC_VER >= 1800) +#define BOOST_DETAIL_EMPTY_VALUE_BASE +#elif defined(BOOST_MSVC) && (BOOST_MSVC >= 1800) +#define BOOST_DETAIL_EMPTY_VALUE_BASE +#elif defined(BOOST_CLANG) && !defined(__CUDACC__) +#if __has_feature(is_empty) && __has_feature(is_final) +#define BOOST_DETAIL_EMPTY_VALUE_BASE +#endif +#endif + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable:4510) +#endif + +namespace boost { +namespace urls { +namespace detail { + +template +struct use_empty_value_base { + enum { +#if defined(BOOST_DETAIL_EMPTY_VALUE_BASE) + value = __is_empty(T) && !__is_final(T) +#else + value = false +#endif + }; +}; + +struct empty_init_t { }; + +namespace empty_ { + +template< + class T, + unsigned N = 0, + bool E = use_empty_value_base::value> +class empty_value +{ + T value_; + +public: + typedef T type; + + constexpr + empty_value() = default; + + constexpr + empty_value( + empty_init_t) noexcept + : value_() + { + } + + template< + class U, class... Args> + constexpr + empty_value( + empty_init_t, + U&& value, + Args&&... args) noexcept + : value_( + std::forward(value), + std::forward(args)...) + { + } + + T const& + get() const noexcept + { + return value_; + } + + T& + get() noexcept + { + return value_; + } +}; + +//------------------------------------------------ + +template +class empty_value + : T +{ +public: + typedef T type; + + constexpr + empty_value() noexcept = default; + + constexpr + empty_value( + empty_init_t) noexcept + : T() + { + } + + template< + class U, class... Args> + constexpr + empty_value( + empty_init_t, + U&& value, + Args&&... args) noexcept + : T(std::forward(value), + std::forward(args)...) + { + } + + T const& + get() const noexcept + { + return *this; + } + + T& + get() noexcept + { + return *this; + } +}; + +} /* empty_ */ + +using empty_::empty_value; + +constexpr empty_init_t empty_init{}; + +} // detail +} // urls +} // boost + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#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 index 20d13d30..e7340e40 100644 --- a/include/boost/url/detail/impl/segments_encoded_iterator_impl.ipp +++ b/include/boost/url/detail/impl/segments_encoded_iterator_impl.ipp @@ -12,7 +12,7 @@ #define BOOST_URL_DETAIL_IMPL_SEGMENTS_ENCODED_ITERATOR_IMPL_IPP #include -#include +#include #include namespace boost { @@ -72,8 +72,8 @@ increment() noexcept // "/" segment auto rv = grammar::parse( next_, end_, - detail::path_increment); - if(rv == grammar::error::end) + detail::slash_segment_rule); + if(rv.has_error()) { next_ = nullptr; return; @@ -103,7 +103,7 @@ decrement() noexcept next_ = pos_; auto rv = grammar::parse( next_, end_, - detail::path_increment); + detail::slash_segment_rule); s_ = rv->encoded(); return; } @@ -113,7 +113,7 @@ decrement() noexcept // "/" segment auto rv = grammar::parse( next_, end_, - detail::path_increment); + detail::slash_segment_rule); s_ = rv->encoded(); } else @@ -121,7 +121,7 @@ decrement() noexcept // segment-nz auto rv = grammar::parse( next_, end_, - detail::path_increment); + detail::slash_segment_rule); s_ = rv->encoded(); } } diff --git a/include/boost/url/detail/impl/segments_iterator_impl.ipp b/include/boost/url/detail/impl/segments_iterator_impl.ipp index 2bff347d..311b5a84 100644 --- a/include/boost/url/detail/impl/segments_iterator_impl.ipp +++ b/include/boost/url/detail/impl/segments_iterator_impl.ipp @@ -12,7 +12,7 @@ #define BOOST_URL_DETAIL_IMPL_SEGMENTS_ITERATOR_IMPL_IPP #include -#include +#include #include namespace boost { @@ -39,7 +39,7 @@ segments_iterator_impl( pos_ += n; t_ = grammar::parse( next_, end_, - detail::segment_rule).value(); + segment_rule).value(); } segments_iterator_impl:: @@ -76,8 +76,8 @@ increment() noexcept // "/" segment auto rv = grammar::parse( next_, end_, - detail::path_increment); - if(rv == grammar::error::end) + detail::slash_segment_rule); + if(rv.has_error()) { next_ = nullptr; return; @@ -108,7 +108,7 @@ decrement() noexcept next_ = pos_; t_ = grammar::parse( next_, end_, - detail::path_increment).value(); + detail::slash_segment_rule).value(); return; } next_ = pos_; @@ -117,14 +117,14 @@ decrement() noexcept // "/" segment t_ = grammar::parse( next_, end_, - detail::path_increment).value(); + detail::slash_segment_rule).value(); } else { // segment-nz t_ = grammar::parse( next_, end_, - detail::path_increment).value(); + detail::slash_segment_rule).value(); } } diff --git a/include/boost/url/detail/impl/url_impl.ipp b/include/boost/url/detail/impl/url_impl.ipp index d69497f6..0a1588cb 100644 --- a/include/boost/url/detail/impl/url_impl.ipp +++ b/include/boost/url/detail/impl/url_impl.ipp @@ -126,14 +126,14 @@ apply_authority( void url_impl:: apply_path( - parsed_path const& t) noexcept + string_view s, + std::size_t nseg) noexcept { - auto s = t.path; set_size(id_path, s.size()); + // VFALCO we are decoding twice decoded_[id_path] = - pct_decode_bytes_unchecked(t.path); - nseg_ = detail::path_segments( - t.path, t.count); + pct_decode_bytes_unchecked(s); + nseg_ = detail::path_segments(s, nseg); } void diff --git a/include/boost/url/detail/over_allocator.hpp b/include/boost/url/detail/over_allocator.hpp index 3d144600..97cad201 100644 --- a/include/boost/url/detail/over_allocator.hpp +++ b/include/boost/url/detail/over_allocator.hpp @@ -11,8 +11,8 @@ #define BOOST_URL_DETAIL_OVER_ALLOCATOR_HPP #include +#include #include -#include #include #include #ifdef BOOST_NO_CXX11_ALLOCATOR @@ -41,7 +41,7 @@ using allocator_traits = std::allocator_traits; template class over_allocator - : private empty_value + : private detail::empty_value { template friend class over_allocator; @@ -75,16 +75,16 @@ public: over_allocator( std::size_t extra, Allocator const& alloc) - : empty_value( - boost::empty_init_t{}, alloc) + : detail::empty_value( + detail::empty_init, alloc) , extra_(extra) { } template over_allocator(over_allocator const& other) noexcept - : empty_value( - boost::empty_init_t{}, other.get()) + : detail::empty_value( + detail::empty_init, other.get()) , extra_(other.extra_) { } diff --git a/include/boost/url/detail/url_impl.hpp b/include/boost/url/detail/url_impl.hpp index 62889de2..0bc63b3e 100644 --- a/include/boost/url/detail/url_impl.hpp +++ b/include/boost/url/detail/url_impl.hpp @@ -18,11 +18,6 @@ #include #include -// VFALCO These structs used to be forward -// declared, but the parsers now use a -// nested type. -#include - namespace boost { namespace urls { @@ -93,7 +88,7 @@ struct url_impl : parts_base unsigned char const*, pct_encoded_view const&) noexcept; void apply_port(string_view, unsigned short) noexcept; void apply_authority(authority_view const&) noexcept; - void apply_path(parsed_path const&) noexcept; + void apply_path(string_view, std::size_t) noexcept; void apply_query(string_view, std::size_t) noexcept; void apply_frag(pct_encoded_view) noexcept; }; diff --git a/include/boost/url/grammar/error.hpp b/include/boost/url/grammar/error.hpp index 06e77837..936c31f1 100644 --- a/include/boost/url/grammar/error.hpp +++ b/include/boost/url/grammar/error.hpp @@ -35,7 +35,15 @@ enum class error success = 0, /** - * A list parser reached the end. + * A rule reached the end of a range + * + * This indicates that the input was consumed + * when parsing a @ref range. The @ref range_rule + * will avoid rewinding the input buffer when + * this error is returned. Thus the consumed + * characters will be considered part of the + * range without contributing additional + * elements. */ end, diff --git a/include/boost/url/grammar/impl/not_empty_rule.hpp b/include/boost/url/grammar/impl/not_empty_rule.hpp index 837c8b31..84eb2ccc 100644 --- a/include/boost/url/grammar/impl/not_empty_rule.hpp +++ b/include/boost/url/grammar/impl/not_empty_rule.hpp @@ -32,7 +32,7 @@ parse( result { auto const it0 = it; - auto rv = r_.parse(it, end); + auto rv = this->get().parse(it, end); if( rv.has_error() || it != it0) return rv; diff --git a/include/boost/url/grammar/impl/range_rule.hpp b/include/boost/url/grammar/impl/range_rule.hpp index 430ab0ce..8d20abfe 100644 --- a/include/boost/url/grammar/impl/range_rule.hpp +++ b/include/boost/url/grammar/impl/range_rule.hpp @@ -11,6 +11,7 @@ #define BOOST_URL_GRAMMAR_IMPL_RANGE_HPP #include +#include #include #include #include @@ -38,6 +39,10 @@ struct range:: void destroy() const noexcept = 0; + virtual + any_rule const* + move(void*) const noexcept = 0; + virtual any_rule const* copy(void*) const noexcept = 0; @@ -55,6 +60,153 @@ struct range:: char const*) const noexcept = 0; }; +//------------------------------------------------ + +template +template +struct range::impl1 + : any_rule + , private urls::detail::empty_value +{ + explicit + impl1(R const& next) noexcept + : urls::detail::empty_value( + urls::detail::empty_init, + next) + { + } + +private: + void + destroy() const noexcept override + { + static constexpr auto small = + sizeof(*this) <= BufferSize; + if(small) + this->~impl1(); + else + delete this; + } + + any_rule const* + move(void* dest) + const noexcept override + { + static constexpr auto small = + sizeof(*this) <= BufferSize; + if(small) + return ::new(dest) impl1(*this); + return this; + } + + any_rule const* + copy(void* dest) + const noexcept override + { + static constexpr auto small = + sizeof(*this) <= BufferSize; + if(small) + return ::new(dest) impl1(*this); + return new impl1(*this); + } + + result + first( + char const*& it, + char const* end) + const noexcept override + { + return grammar::parse( + it, end, this->get()); + } + + result + next( + char const*& it, + char const* end) + const noexcept override + { + return grammar::parse( + it, end, this->get()); + } +}; + +//------------------------------------------------ + +template +template +struct range::impl2 + : any_rule + , private urls::detail::empty_value + , private urls::detail::empty_value +{ + impl2( + R0 const& first, + R1 const& next) noexcept + : urls::detail::empty_value( + urls::detail::empty_init, first) + , urls::detail::empty_value( + urls::detail::empty_init, next) + { + } + +private: + void + destroy() const noexcept override + { + static constexpr auto small = + sizeof(*this) <= BufferSize; + if(small) + this->~impl2(); + else + delete this; + } + + any_rule const* + move(void* dest) + const noexcept override + { + static constexpr auto small = + sizeof(*this) <= BufferSize; + if(small) + return ::new(dest) impl2(*this); + return this; + } + + any_rule const* + copy(void* dest) + const noexcept override + { + static constexpr auto small = + sizeof(*this) <= BufferSize; + if(small) + return ::new(dest) impl2(*this); + return new impl2(*this); + } + + result + first( + char const*& it, + char const* end) + const noexcept override + { + return grammar::parse(it, end, + urls::detail::empty_value< + R0,0>::get()); + } + + result + next( + char const*& it, + char const* end) + const noexcept override + { + return grammar::parse(it, end, + urls::detail::empty_value< + R1,1>::get()); + } +}; + //------------------------------------------------ // // iterator @@ -114,12 +266,7 @@ public: r_->s_.size(); rv_ = r_->pr_->next(p_, end); if(rv_.has_error()) - { - BOOST_ASSERT( - rv_.error() == - error::end); p_ = nullptr; - } return *this; } @@ -148,44 +295,103 @@ private: r_->s_.size(); rv_ = r_->pr_->first(p_, end); if(rv_.has_error()) - { - BOOST_ASSERT( - rv_.error() == - error::end); p_ = nullptr; - } } constexpr iterator( range const& r, int) noexcept - : p_(nullptr) - , r_(&r) + : r_(&r) + , p_(nullptr) { } }; //------------------------------------------------ +template +template +range:: +range( + string_view s, + std::size_t n, + R const& next) + : s_(s) + , n_(n) +{ + using U = impl1; + + static constexpr auto small = + sizeof(U) <= BufferSize; + if(small) + { + pr_ = ::new(reinterpret_cast< + void*>(buf_)) U(next); + } + else + { + pr_ = new U(next); + } +} + +//------------------------------------------------ + +template +template< + class R0, class R1> +range:: +range( + string_view s, + std::size_t n, + R0 const& first, + R1 const& next) + : s_(s) + , n_(n) +{ + using U = impl2; + + static constexpr auto small = + sizeof(U) <= BufferSize; + if(small) + { + pr_ = ::new(reinterpret_cast< + void*>(buf_)) U(first, next); + } + else + { + pr_ = new U(first, next); + } +} + +//------------------------------------------------ + template range:: ~range() { if(pr_) + pr_->destroy(); +} + +template +range:: +range( + range&& other) noexcept + : s_(other.s_) + , n_(other.n_) +{ + if(other.pr_) { - if(pr_ == reinterpret_cast< - any_rule*>(buf_)) - pr_->~any_rule(); - else - pr_->destroy(); + pr_ = other.pr_->move(buf_); + other.pr_ = nullptr; } } template range:: range( - range const& other) noexcept + range const& other) : s_(other.s_) , n_(other.n_) { @@ -193,6 +399,51 @@ range( pr_ = other.pr_->copy(buf_); } +template +auto +range:: +operator=( + range&& other) noexcept -> + range& +{ + if(pr_) + pr_->destroy(); + if(other.pr_) + { + s_ = other.s_; + n_ = other.n_; + pr_ = other.pr_->move(buf_); + other.s_ = {}; + other.n_ = 0; + other.pr_ = nullptr; + } + else + { + s_ = {}; + n_ = 0; + pr_ = nullptr; + } + + return *this; +} + +template +auto +range:: +operator=( + range const& other) -> + range& +{ + range tmp(other); + if(pr_) + pr_->destroy(); + s_ = tmp.s_; + n_ = tmp.n_; + pr_ = tmp.pr_; + tmp.pr_ = nullptr; + return *this; +} + template auto range:: @@ -213,142 +464,6 @@ end() const noexcept -> //------------------------------------------------ -template -template -range:: -range( - string_view s, - std::size_t n, - R const& next) - : s_(s) - , n_(n) -{ - struct impl : any_rule - { - explicit - impl( - R const& next) noexcept - : next_(next) - { - } - - private: - R const next_; - - void - destroy() const noexcept override - { - delete this; - } - - any_rule const* - copy(void* dest) - const noexcept override - { - static constexpr auto small = - sizeof(*this) <= BufferSize; - if(small) - return ::new(dest) impl(*this); - return new impl(*this); - } - - result - first( - char const*& it, - char const* end) - const noexcept override - { - return grammar::parse( - it, end, next_); - } - - result - next( - char const*& it, - char const* end) - const noexcept override - { - return grammar::parse( - it, end, next_); - } - }; - - pr_ = ::new(reinterpret_cast< - void*>(buf_)) impl(next); -} - -//------------------------------------------------ - -template -template< - class R0, class R1> -range:: -range( - string_view s, - std::size_t n, - R0 const& first, - R1 const& next) - : s_(s) - , n_(n) -{ - struct impl : any_rule - { - impl( - R0 const& first, - R1 const& next) noexcept - : first_(first) - , next_(next) - { - } - - private: - R0 const first_; - R1 const next_; - - void - destroy() const noexcept override - { - delete this; - } - - any_rule const* - copy(void* dest) - const noexcept override - { - static constexpr auto small = - sizeof(*this) <= BufferSize; - if(small) - return ::new(dest) impl(*this); - return new impl(*this); - } - - result - first( - char const*& it, - char const* end) - const noexcept override - { - return grammar::parse( - it, end, first_); - } - - result - next( - char const*& it, - char const* end) - const noexcept override - { - return grammar::parse( - it, end, next_); - } - }; - - pr_ = ::new(reinterpret_cast< - void*>(buf_)) impl(first, next); -} - -//------------------------------------------------ - template auto range_rule_t:: @@ -361,12 +476,16 @@ parse( std::size_t n = 0; auto const it0 = it; + auto it1 = it; auto rv = (grammar::parse)( it, end, next_); if(rv.has_error()) { if(rv.error() != error::end) - return rv.error(); + { + // rewind unless error::end + it = it1; + } if(n < N_) { // too few @@ -382,12 +501,16 @@ parse( for(;;) { ++n; + it1 = it; rv = (grammar::parse)( it, end, next_); if(rv.has_error()) { if(rv.error() != error::end) - return rv.error(); + { + // rewind unless error::end + it = it1; + } break; } if(n > M_) @@ -418,12 +541,16 @@ parse( std::size_t n = 0; auto const it0 = it; + auto it1 = it; auto rv = (grammar::parse)( it, end, first_); if(rv.has_error()) { if(rv.error() != error::end) - return rv.error(); + { + // rewind unless error::end + it = it1; + } if(n < N_) { // too few @@ -439,12 +566,16 @@ parse( for(;;) { ++n; + it1 = it; rv = (grammar::parse)( it, end, next_); if(rv.has_error()) { if(rv.error() != error::end) - return rv.error(); + { + // rewind unless error::end + it = it1; + } break; } if(n > M_) diff --git a/include/boost/url/grammar/impl/sequence_rule.hpp b/include/boost/url/grammar/impl/sequence_rule.hpp index 6f932769..af08c4a6 100644 --- a/include/boost/url/grammar/impl/sequence_rule.hpp +++ b/include/boost/url/grammar/impl/sequence_rule.hpp @@ -272,7 +272,7 @@ parse( result { detail::parse_sequence< - IsList, R0, Rn...> t(rn_); + IsList, R0, Rn...> t(this->get()); t.apply(it, end); return t.make_result(); } diff --git a/include/boost/url/grammar/impl/variant_rule.hpp b/include/boost/url/grammar/impl/variant_rule.hpp index e7a2195e..0a0d9e4e 100644 --- a/include/boost/url/grammar/impl/variant_rule.hpp +++ b/include/boost/url/grammar/impl/variant_rule.hpp @@ -89,7 +89,7 @@ parse( result { return detail::parse_variant( - it, end, rn_, + it, end, this->get(), std::integral_constant< std::size_t, 0>{}, std::true_type{}); diff --git a/include/boost/url/grammar/not_empty_rule.hpp b/include/boost/url/grammar/not_empty_rule.hpp index 4d04c4cd..a6d6de97 100644 --- a/include/boost/url/grammar/not_empty_rule.hpp +++ b/include/boost/url/grammar/not_empty_rule.hpp @@ -12,6 +12,7 @@ #include #include +#include #include namespace boost { @@ -47,6 +48,7 @@ not_empty_rule( Rule r ); #else template struct not_empty_rule_t + : urls::detail::empty_value { using value_type = typename R::value_type; @@ -69,11 +71,10 @@ private: constexpr not_empty_rule_t( R const& r) noexcept - : r_(r) + : urls::detail::empty_value( + urls::detail::empty_init, r) { } - - R const r_; }; template diff --git a/include/boost/url/grammar/optional_rule.hpp b/include/boost/url/grammar/optional_rule.hpp index 11d27669..82cdad93 100644 --- a/include/boost/url/grammar/optional_rule.hpp +++ b/include/boost/url/grammar/optional_rule.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace boost { @@ -57,6 +58,7 @@ optional_rule( Rule r ) noexcept; #else template class optional_rule_t + : private urls::detail::empty_value { public: using value_type = optional< @@ -69,7 +71,7 @@ public: result { auto const it0 = it; - auto rv = r_.parse(it, end); + auto rv = this->get().parse(it, end); if(! rv.has_error()) return value_type(*rv); it = it0; @@ -88,11 +90,10 @@ private: constexpr optional_rule_t( Rule const& r) noexcept - : r_(r) + : urls::detail::empty_value( + urls::detail::empty_init, r) { } - - Rule const r_; }; template diff --git a/include/boost/url/grammar/range_rule.hpp b/include/boost/url/grammar/range_rule.hpp index 3ae7e017..0b8ee1e2 100644 --- a/include/boost/url/grammar/range_rule.hpp +++ b/include/boost/url/grammar/range_rule.hpp @@ -54,11 +54,35 @@ class range struct any_rule; + template + struct impl1; + + template + struct impl2; + string_view s_; std::size_t n_ = 0; char buf_[BufferSize]; any_rule const* pr_ = nullptr; + template< + class R0, class R1> + friend struct range_rule_t; + + template + range( + string_view s, + std::size_t n, + R const& r); + + template< + class R0, class R1> + range( + string_view s, + std::size_t n, + R0 const& first, + R1 const& next); + public: /** The type of each element of the range */ @@ -96,12 +120,19 @@ public: */ ~range(); -#ifndef BOOST_URL_DOCS -#if BOOST_WORKAROUND( BOOST_GCC_VERSION, < 50000 ) || \ - BOOST_WORKAROUND( BOOST_CLANG_VERSION, < 40000 ) + /** Constructor + + Default-constructed ranges have + zero elements. + */ range() noexcept = default; -#endif -#endif + + /** Constructor + + After construction, the moved-from + object will be the empty range. + */ + range(range&&) noexcept; /** Constructor @@ -111,7 +142,17 @@ public: for ensuring that the lifetime of the buffer extends until no longer in use. */ - range(range const&) noexcept; + range(range const&); + + /** Assignment + */ + range& + operator=(range const&); + + /** Assignment + */ + range& + operator=(range&&) noexcept; /** Return an iterator to the beginning */ @@ -144,25 +185,6 @@ public: { return n_ == 0; } - -private: - template - range( - string_view s, - std::size_t n, - R const& r); - - template< - class R0, class R1> - range( - string_view s, - std::size_t n, - R0 const& first, - R1 const& next); - - template< - class R0, class R1> - friend struct range_rule_t; }; //------------------------------------------------ @@ -185,7 +207,7 @@ struct range_rule_t; @par BNF @code - range = *rule + range = *next @endcode @par Specification @@ -276,8 +298,8 @@ range_rule( @par BNF @code - range = <1>*<1>rule1 - / rule1 *rule2 + range = <1>*<1>first + / first *next @endcode @par Specification diff --git a/include/boost/url/grammar/sequence_rule.hpp b/include/boost/url/grammar/sequence_rule.hpp index e3fd3e59..c66759f9 100644 --- a/include/boost/url/grammar/sequence_rule.hpp +++ b/include/boost/url/grammar/sequence_rule.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include namespace boost { @@ -69,6 +70,8 @@ template< class R0, class... Rn> class sequence_rule_t + : urls::detail::empty_value< + detail::tuple> { using T = mp11::mp_remove< std::tuple< @@ -104,11 +107,12 @@ private: sequence_rule_t( R0 const& r0, Rn const&... rn) noexcept - : rn_(r0, rn...) + : urls::detail::empty_value< + detail::tuple>( + urls::detail::empty_init, + r0, rn...) { } - - detail::tuple const rn_; }; template< diff --git a/include/boost/url/grammar/variant_rule.hpp b/include/boost/url/grammar/variant_rule.hpp index df54782a..9b82b479 100644 --- a/include/boost/url/grammar/variant_rule.hpp +++ b/include/boost/url/grammar/variant_rule.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace boost { @@ -69,6 +70,8 @@ variant_rule( Rules... rn ) noexcept; template< class R0, class... Rn> class variant_rule_t + : private urls::detail::empty_value< + detail::tuple> { public: using value_type = variant< @@ -97,11 +100,12 @@ private: variant_rule_t( R0 const& r0, Rn const&... rn) noexcept - : rn_(r0, rn...) + : urls::detail::empty_value< + detail::tuple>( + urls::detail::empty_init, + r0, rn...) { } - - detail::tuple rn_; }; template< diff --git a/include/boost/url/impl/segments_encoded_view.hpp b/include/boost/url/impl/segments_encoded_view.hpp index f4a1fd68..9b4d2cc8 100644 --- a/include/boost/url/impl/segments_encoded_view.hpp +++ b/include/boost/url/impl/segments_encoded_view.hpp @@ -13,7 +13,6 @@ #include #include -#include #include #include diff --git a/include/boost/url/impl/segments_encoded_view.ipp b/include/boost/url/impl/segments_encoded_view.ipp index fda7b3c1..c8b6b097 100644 --- a/include/boost/url/impl/segments_encoded_view.ipp +++ b/include/boost/url/impl/segments_encoded_view.ipp @@ -13,11 +13,11 @@ #include #include -#include -#include -#include #include #include +#include +#include +#include #include namespace boost { diff --git a/include/boost/url/impl/segments_view.ipp b/include/boost/url/impl/segments_view.ipp index d45ee9b8..056d6c21 100644 --- a/include/boost/url/impl/segments_view.ipp +++ b/include/boost/url/impl/segments_view.ipp @@ -12,9 +12,6 @@ #define BOOST_URL_IMPL_SEGMENTS_VIEW_IPP #include -#include -#include -#include #include namespace boost { diff --git a/include/boost/url/impl/url.ipp b/include/boost/url/impl/url.ipp index af31d765..235148b1 100644 --- a/include/boost/url/impl/url.ipp +++ b/include/boost/url/impl/url.ipp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/boost/url/impl/url_view.ipp b/include/boost/url/impl/url_view.ipp index e0650039..a8ead099 100644 --- a/include/boost/url/impl/url_view.ipp +++ b/include/boost/url/impl/url_view.ipp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/boost/url/rfc/detail/fragment_rule.hpp b/include/boost/url/rfc/detail/fragment_rule.hpp index ae6bd2ed..e2dba168 100644 --- a/include/boost/url/rfc/detail/fragment_rule.hpp +++ b/include/boost/url/rfc/detail/fragment_rule.hpp @@ -33,7 +33,7 @@ namespace detail { */ constexpr auto fragment_rule = pct_encoded_rule( - pchars + '/' + '?'); + &detail::fragment_chars); /** Rule for fragment-part diff --git a/include/boost/url/rfc/detail/hier_part_rule.hpp b/include/boost/url/rfc/detail/hier_part_rule.hpp index dc1c7173..e0f76601 100644 --- a/include/boost/url/rfc/detail/hier_part_rule.hpp +++ b/include/boost/url/rfc/detail/hier_part_rule.hpp @@ -11,9 +11,9 @@ #define BOOST_URL_RFC_DETAIL_HIER_PART_RULE_HPP #include -#include +#include #include -#include +#include namespace boost { namespace urls { @@ -39,7 +39,9 @@ struct hier_part_rule_t { bool has_authority = false; authority_view authority; - parsed_path path; + + // VFALCO This doesn't belong here + grammar::range path; }; BOOST_URL_DECL diff --git a/include/boost/url/rfc/detail/impl/hier_part_rule.ipp b/include/boost/url/rfc/detail/impl/hier_part_rule.ipp index f37038dd..a3121a7c 100644 --- a/include/boost/url/rfc/detail/impl/hier_part_rule.ipp +++ b/include/boost/url/rfc/detail/impl/hier_part_rule.ipp @@ -11,8 +11,8 @@ #define BOOST_URL_RFC_DETAIL_IMPL_HIER_PART_RULE_IPP #include +#include #include -#include #include namespace boost { @@ -43,9 +43,7 @@ parse( path_rootless_rule); if(rv.has_value()) { - auto const& v = *rv; - t.path.path = v.string(); - t.path.count = v.size(); + t.path = std::move(*rv); return t; } it = it0; @@ -62,9 +60,7 @@ parse( path_absolute_rule); if(! rv) return rv.error(); - auto const& p = *rv; - t.path.path = p.string(); - t.path.count = p.size(); + t.path = std::move(*rv); t.has_authority = false; return t; } @@ -86,10 +82,7 @@ parse( it, end, path_abempty_rule); if(! rv) return rv.error(); - - auto const& v = *rv; - t.path.path = v.string(); - t.path.count = v.size(); + t.path = std::move(*rv); t.has_authority = true; } diff --git a/include/boost/url/rfc/detail/impl/path_rules.ipp b/include/boost/url/rfc/detail/impl/path_rules.ipp new file mode 100644 index 00000000..f12ccca6 --- /dev/null +++ b/include/boost/url/rfc/detail/impl/path_rules.ipp @@ -0,0 +1,45 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot 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_RFC_DETAIL_IMPL_PATH_RULES_IPP +#define BOOST_URL_RFC_DETAIL_IMPL_PATH_RULES_IPP + +#include +#include +#include +#include +#include + +namespace boost { +namespace urls { +namespace detail { + +auto +segment_ns_rule_t:: +parse( + char const*& it, + char const* end) const noexcept -> + result +{ + if(it == end) + return value_type{}; + if(*it == '/') + return grammar::error::syntax; + auto rv = grammar::parse( + it, end, segment_rule); + if(rv.has_error()) + return rv.error(); + return *rv; +} + +} // detail +} // urls +} // boost + +#endif diff --git a/include/boost/url/rfc/detail/impl/relative_part_rule.ipp b/include/boost/url/rfc/detail/impl/relative_part_rule.ipp index 1f0cc859..b64352a0 100644 --- a/include/boost/url/rfc/detail/impl/relative_part_rule.ipp +++ b/include/boost/url/rfc/detail/impl/relative_part_rule.ipp @@ -11,7 +11,7 @@ #define BOOST_URL_RFC_DETAIL_IMPL_RELATIVE_PART_RULE_IPP #include -#include +#include #include namespace boost { @@ -42,9 +42,7 @@ parse( if(rv.has_value()) { // path-noscheme - auto const& v = *rv; - t.path.path = v.string(); - t.path.count = v.size(); + t.path = std::move(*rv); t.has_authority = false; return t; } @@ -60,9 +58,7 @@ parse( auto rv = grammar::parse( it, end, path_absolute_rule); - auto const& v = *rv; - t.path.path = v.string(); - t.path.count = v.size(); + t.path = std::move(*rv); t.has_authority = false; return t; } @@ -81,9 +77,7 @@ parse( it, end, path_abempty_rule); if(! rv) return rv.error(); - auto const& v = *rv; - t.path.path = v.string(); - t.path.count = v.size(); + t.path = std::move(*rv); t.has_authority = true; } return t; diff --git a/include/boost/url/rfc/detail/impl/userinfo_rule.ipp b/include/boost/url/rfc/detail/impl/userinfo_rule.ipp index 507c8b7f..2afc2dc6 100644 --- a/include/boost/url/rfc/detail/impl/userinfo_rule.ipp +++ b/include/boost/url/rfc/detail/impl/userinfo_rule.ipp @@ -38,7 +38,7 @@ parse( // user auto rv = grammar::parse( it, end, - pct_encoded_rule(uchars)); + pct_encoded_rule(&uchars)); if(! rv) return rv.error(); t.user = *rv; @@ -56,7 +56,7 @@ parse( // pass rv = grammar::parse( it, end, - pct_encoded_rule(pwchars)); + pct_encoded_rule(&pwchars)); if(! rv) return rv.error(); diff --git a/include/boost/url/rfc/detail/path_increment.hpp b/include/boost/url/rfc/detail/path_increment.hpp deleted file mode 100644 index c3bffeb3..00000000 --- a/include/boost/url/rfc/detail/path_increment.hpp +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot 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_RFC_DETAIL_PATH_INCREMENT_IPP -#define BOOST_URL_RFC_DETAIL_PATH_INCREMENT_IPP - -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace urls { -namespace detail { - -struct path_increment_t -{ - using value_type = pct_encoded_view; - - result - parse( - char const *&it, - char const* end) const noexcept - { - auto it0 = it; - auto rv = grammar::parse( - it, end, - grammar::sequence_rule( - grammar::char_rule('/'), - segment_rule)); - if(rv.has_value()) - return *rv; - it = it0; - return BOOST_URL_ERR( - grammar::error::end); - } -}; - -constexpr path_increment_t path_increment{}; - -} // detail -} // urls -} // boost - -#endif diff --git a/include/boost/url/rfc/detail/segment_rule.hpp b/include/boost/url/rfc/detail/path_rules.hpp similarity index 61% rename from include/boost/url/rfc/detail/segment_rule.hpp rename to include/boost/url/rfc/detail/path_rules.hpp index 9187c76a..d27bab51 100644 --- a/include/boost/url/rfc/detail/segment_rule.hpp +++ b/include/boost/url/rfc/detail/path_rules.hpp @@ -7,10 +7,11 @@ // Official repository: https://github.com/CPPAlliance/url // -#ifndef BOOST_URL_RFC_DETAIL_SEGMENT_RULE_HPP -#define BOOST_URL_RFC_DETAIL_SEGMENT_RULE_HPP +#ifndef BOOST_URL_RFC_DETAIL_PATH_RULES_HPP +#define BOOST_URL_RFC_DETAIL_PATH_RULES_HPP -#include +#include +#include #include #include @@ -30,16 +31,10 @@ namespace detail { >3.3. Path (rfc3986) @see - @ref path_abempty_rule, - @ref path_absolute_rule, - @ref path_noscheme_rule, - @ref path_rootless_rule, - @ref pchars, - @ref segment_nz_rule, - @ref segment_nz_nc_rule + @ref parse. */ constexpr auto segment_rule = - pct_encoded_rule(pchars); + pct_encoded_rule(&pchars); //------------------------------------------------ @@ -65,7 +60,7 @@ constexpr auto segment_rule = */ constexpr auto segment_nz_rule = grammar::not_empty_rule( - pct_encoded_rule(pchars)); + pct_encoded_rule(&pchars)); //------------------------------------------------ @@ -82,20 +77,52 @@ constexpr auto segment_nz_rule = >3.3. Path (rfc3986) @see - @ref path_abempty_rule, - @ref path_absolute_rule, - @ref path_noscheme_rule, - @ref path_rootless_rule, - @ref pchars, - @ref segment_rule, - @ref segment_nz_rule, - @ref sub_delim_chars, - @ref unreserved_chars + @ref parse. */ constexpr auto segment_nz_nc_rule = grammar::not_empty_rule( pct_encoded_rule(pchars - ':')); +//------------------------------------------------ + +/** Rule for slash-segment + + @par BNF + @code + slash-segment = "/" segment + + @endcode +*/ +constexpr auto slash_segment_rule = + grammar::sequence_rule( + grammar::char_rule('/'), + pct_encoded_rule(&pchars)); + +//------------------------------------------------ + +// VFALCO This is an alternate rule not found +// in the rfc3986, to reformulate the rfc path +// BNFs into something the range_rule can use. + +/** Rule for segment-ns +*/ +#ifdef BOOST_URL_DOCS +constexpr __implementation_defined__ segment_ns_rule; +#else +struct segment_ns_rule_t +{ + using value_type = pct_encoded_view; + + BOOST_URL_DECL + result + parse( + char const*& it, + char const* end) const noexcept; +}; + +constexpr segment_ns_rule_t segment_ns_rule{}; +#endif + } // detail } // urls } // boost diff --git a/include/boost/url/rfc/detail/relative_part_rule.hpp b/include/boost/url/rfc/detail/relative_part_rule.hpp index 6c1ab722..f43a558b 100644 --- a/include/boost/url/rfc/detail/relative_part_rule.hpp +++ b/include/boost/url/rfc/detail/relative_part_rule.hpp @@ -12,8 +12,9 @@ #include #include +#include #include -#include +#include namespace boost { namespace urls { @@ -45,7 +46,7 @@ struct relative_part_rule_t { bool has_authority = false; decltype(authority_rule)::value_type authority; - parsed_path path; + grammar::range path; }; auto diff --git a/include/boost/url/rfc/impl/absolute_uri_rule.ipp b/include/boost/url/rfc/impl/absolute_uri_rule.ipp index cd0596bb..1223f371 100644 --- a/include/boost/url/rfc/impl/absolute_uri_rule.ipp +++ b/include/boost/url/rfc/impl/absolute_uri_rule.ipp @@ -53,7 +53,9 @@ parse( return rv.error(); if(rv->has_authority) u.apply_authority(rv->authority); - u.apply_path(rv->path); + u.apply_path( + rv->path.string(), + rv->path.size()); } // [ "?" query ] diff --git a/include/boost/url/rfc/impl/paths_rule.ipp b/include/boost/url/rfc/impl/paths_rule.ipp deleted file mode 100644 index 52c1e9b1..00000000 --- a/include/boost/url/rfc/impl/paths_rule.ipp +++ /dev/null @@ -1,122 +0,0 @@ -// -// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot 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_RFC_IMPL_PATHS_RULE_IPP -#define BOOST_URL_RFC_IMPL_PATHS_RULE_IPP - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost { -namespace urls { - -auto -path_abempty_rule_t:: -parse( - char const*& it, - char const* end - ) const noexcept -> - result -{ - return grammar::parse( - it, end, grammar::range_rule( - detail::path_increment)); -} - -//------------------------------------------------ - -auto -path_absolute_rule_t:: -parse( - char const*& it, - char const* end - ) const noexcept -> - result -{ - struct begin - { - using value_type = pct_encoded_view; - - result - parse( - char const *&it, - char const* end) const noexcept - { - if(it == end) - { - // expected '/' - return error::missing_path_segment; - } - if(*it != '/') - { - // expected '/' - return error::missing_path_separator; - } - ++it; - if(it == end) - return pct_encoded_view{}; - if(*it == '/') - { - // can't begin with "//" - return error::empty_path_segment; - } - return grammar::parse( - it, end, detail::segment_rule); - } - }; - - return grammar::parse( - it, end, grammar::range_rule( - begin{}, detail::path_increment)); -} - -//------------------------------------------------ - -auto -path_noscheme_rule_t:: -parse( - char const*& it, - char const* end - ) const noexcept -> - result -{ - return grammar::parse( - it, end, - grammar::range_rule( - detail::segment_nz_nc_rule, - detail::path_increment)); -} - -//------------------------------------------------ - -auto -path_rootless_rule_t:: -parse( - char const*& it, - char const* end - ) const noexcept -> - result -{ - return grammar::parse( - it, end, - grammar::range_rule( - detail::segment_nz_rule, - detail::path_increment)); -} - -} // urls -} // boost - -#endif diff --git a/include/boost/url/rfc/impl/pct_encoded_rule.hpp b/include/boost/url/rfc/impl/pct_encoded_rule.hpp index c61995c7..efe7429c 100644 --- a/include/boost/url/rfc/impl/pct_encoded_rule.hpp +++ b/include/boost/url/rfc/impl/pct_encoded_rule.hpp @@ -16,13 +16,15 @@ namespace boost { namespace urls { +namespace detail { + template auto -pct_encoded_rule_t:: -parse( +parse_pct_encoded( char const*& it, - char const* end) const noexcept -> - result + char const* end, + CharSet const& cs) noexcept -> + result { auto const start = it; // VFALCO TODO @@ -32,7 +34,7 @@ parse( skip: it0 = it; it = grammar::find_if_not( - it0, end, cs_); + it0, end, cs); n += it - it0; if(it == end) goto finish; @@ -71,10 +73,38 @@ skip: goto skip; } finish: - return detail::access::construct( + return access::construct( string_view(start, it - start), n); } +} // detail + +//------------------------------------------------ + +template +auto +pct_encoded_rule_t:: +parse( + char const*& it, + char const* end) const noexcept -> + result +{ + return detail::parse_pct_encoded( + it, end, this->get()); +} + +template +auto +pct_encoded_ref_rule_t:: +parse( + char const*& it, + char const* end) const noexcept -> + result +{ + return detail::parse_pct_encoded( + it, end, *cs_); +} + } // urls } // boost diff --git a/include/boost/url/rfc/impl/query_rule.ipp b/include/boost/url/rfc/impl/query_rule.ipp index 94770a77..9c26ccde 100644 --- a/include/boost/url/rfc/impl/query_rule.ipp +++ b/include/boost/url/rfc/impl/query_rule.ipp @@ -56,7 +56,7 @@ struct query_param_rule_t // key { auto rv = grammar::parse(it, end, - pct_encoded_rule(detail::key_chars)); + pct_encoded_rule(&detail::key_chars)); if(! rv) return rv.error(); t.key = *rv; @@ -78,7 +78,7 @@ struct query_param_rule_t // value { auto rv = grammar::parse(it, end, - pct_encoded_rule(detail::value_chars)); + pct_encoded_rule(&detail::value_chars)); if(! rv) return rv.error(); t.value = *rv; @@ -115,10 +115,7 @@ parse( it, end, grammar::char_rule('&')); if(! rv) - { - // end of list - return grammar::error::end; - } + return rv.error(); } return grammar::parse(it, end, diff --git a/include/boost/url/rfc/impl/relative_ref_rule.ipp b/include/boost/url/rfc/impl/relative_ref_rule.ipp index 7b146153..3d66f783 100644 --- a/include/boost/url/rfc/impl/relative_ref_rule.ipp +++ b/include/boost/url/rfc/impl/relative_ref_rule.ipp @@ -42,7 +42,9 @@ parse( return rv.error(); if(rv->has_authority) u.apply_authority(rv->authority); - u.apply_path(rv->path); + u.apply_path( + rv->path.string(), + rv->path.size()); } // [ "?" query ] diff --git a/include/boost/url/rfc/impl/uri_rule.ipp b/include/boost/url/rfc/impl/uri_rule.ipp index 6e483b7e..b79aaba3 100644 --- a/include/boost/url/rfc/impl/uri_rule.ipp +++ b/include/boost/url/rfc/impl/uri_rule.ipp @@ -55,7 +55,9 @@ parse( return rv.error(); if(rv->has_authority) u.apply_authority(rv->authority); - u.apply_path(rv->path); + u.apply_path( + rv->path.string(), + rv->path.size()); } // [ "?" query ] diff --git a/include/boost/url/rfc/paths_rule.hpp b/include/boost/url/rfc/path_rules.hpp similarity index 60% rename from include/boost/url/rfc/paths_rule.hpp rename to include/boost/url/rfc/path_rules.hpp index 4a9ed55b..35dda748 100644 --- a/include/boost/url/rfc/paths_rule.hpp +++ b/include/boost/url/rfc/path_rules.hpp @@ -7,32 +7,23 @@ // Official repository: https://github.com/CPPAlliance/url // -#ifndef BOOST_URL_RFC_PATHS_RULE_HPP -#define BOOST_URL_RFC_PATHS_RULE_HPP +#ifndef BOOST_URL_RFC_PATH_RULES_HPP +#define BOOST_URL_RFC_PATH_RULES_HPP #include #include +#include #include #include +#include +#include #include +#include #include namespace boost { namespace urls { -/** Information about a parsed path -*/ -struct parsed_path -{ - /** The encoded string representing the path - */ - string_view path; - - /** The number of segments in the path - */ - std::size_t count = 0; -}; - /** Rule for path-abempty grammar @par BNF @@ -47,21 +38,11 @@ struct parsed_path #ifdef BOOST_URL_DOCS constexpr __implementation_defined__ path_abempty_rule; #else -struct path_abempty_rule_t -{ - using value_type = - grammar::range< - pct_encoded_view>; - - BOOST_URL_DECL - result - parse( - char const*& it, - char const* end - ) const noexcept; -}; - -constexpr path_abempty_rule_t path_abempty_rule{}; +constexpr auto path_abempty_rule = + grammar::range_rule( + grammar::sequence_rule( + grammar::char_rule('/'), + detail::segment_rule)); #endif //------------------------------------------------ @@ -80,21 +61,13 @@ constexpr path_abempty_rule_t path_abempty_rule{}; #ifdef BOOST_URL_DOCS constexpr __implementation_defined__ path_absolute_rule; #else -struct path_absolute_rule_t -{ - using value_type = - grammar::range< - pct_encoded_view>; - - BOOST_URL_DECL - result - parse( - char const*& it, - char const* end - ) const noexcept; -}; - -constexpr path_absolute_rule_t path_absolute_rule{}; +constexpr auto path_absolute_rule = + grammar::range_rule( + grammar::sequence_rule( + grammar::char_rule('/'), + detail::segment_ns_rule), + detail::slash_segment_rule, + 1); #endif //------------------------------------------------ @@ -113,21 +86,11 @@ constexpr path_absolute_rule_t path_absolute_rule{}; #ifdef BOOST_URL_DOCS constexpr __implementation_defined__ path_noscheme_rule; #else -struct path_noscheme_rule_t -{ - using value_type = - grammar::range< - pct_encoded_view>; - - BOOST_URL_DECL - result - parse( - char const*& it, - char const* end - ) const noexcept; -}; - -constexpr path_noscheme_rule_t path_noscheme_rule{}; +constexpr auto path_noscheme_rule = + grammar::range_rule( + detail::segment_nz_nc_rule, + detail::slash_segment_rule, + 1); #endif //------------------------------------------------ @@ -152,21 +115,11 @@ constexpr path_noscheme_rule_t path_noscheme_rule{}; #ifdef BOOST_URL_DOCS constexpr __implementation_defined__ path_rootless_rule; #else -struct path_rootless_rule_t -{ - using value_type = - grammar::range< - pct_encoded_view>; - - BOOST_URL_DECL - result - parse( - char const*& it, - char const* end - ) const noexcept; -}; - -constexpr path_rootless_rule_t path_rootless_rule{}; +constexpr auto path_rootless_rule = + grammar::range_rule( + detail::segment_nz_rule, + detail::slash_segment_rule, + 1); #endif } // urls diff --git a/include/boost/url/rfc/pct_encoded_rule.hpp b/include/boost/url/rfc/pct_encoded_rule.hpp index db2f19b7..423518b0 100644 --- a/include/boost/url/rfc/pct_encoded_rule.hpp +++ b/include/boost/url/rfc/pct_encoded_rule.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -78,13 +79,21 @@ namespace urls { @ref pct_encoded_view */ #ifdef BOOST_URL_DOCS +/**@{*/ template constexpr __implementation_defined__ -pct_encoded_rule( CharSet cs ) noexcept; +pct_encoded_rule( CharSet const& cs ) noexcept; + +template +constexpr +__implementation_defined__ +pct_encoded_rule( CharSet const* cs ) noexcept; +/**@}*/ #else template struct pct_encoded_rule_t + : private detail::empty_value { using value_type = pct_encoded_view; @@ -102,16 +111,44 @@ struct pct_encoded_rule_t char const* end) const noexcept; private: - CharSet cs_; - constexpr pct_encoded_rule_t( CharSet const& cs) noexcept - : cs_(cs) + : detail::empty_value( + detail::empty_init, cs) { } }; +template +struct pct_encoded_ref_rule_t +{ + using value_type = pct_encoded_view; + + template + friend + constexpr + auto + pct_encoded_rule( + CharSet_ const* cs) noexcept -> + pct_encoded_ref_rule_t; + + result + parse( + char const*& it, + char const* end) const noexcept; + +private: + constexpr + pct_encoded_ref_rule_t( + CharSet const& cs) noexcept + : cs_(&cs) + { + } + + CharSet const* cs_; +}; + template constexpr auto @@ -129,6 +166,25 @@ pct_encoded_rule( return pct_encoded_rule_t(cs); } + +template +constexpr +auto +pct_encoded_rule( + CharSet const* cs) noexcept -> + pct_encoded_ref_rule_t +{ + // If an error occurs here it means that + // the value of your type does not meet + // the requirements. Please check the + // documentation! + static_assert( + grammar::is_charset::value, + "CharSet requirements not met"); + + return pct_encoded_ref_rule_t(*cs); +} + #endif } // urls diff --git a/include/boost/url/src.hpp b/include/boost/url/src.hpp index 4bb97b16..a4409bd8 100644 --- a/include/boost/url/src.hpp +++ b/include/boost/url/src.hpp @@ -69,7 +69,6 @@ in a translation unit of the program. #include #include #include -#include #include #include #include @@ -80,6 +79,7 @@ in a translation unit of the program. #include #include #include +#include #include #include #include diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 5dcc11f1..d9cf883a 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -71,7 +71,7 @@ set(BOOST_URL_TESTS_FILES rfc/gen_delim_chars.cpp rfc/ipv4_address_rule.cpp rfc/ipv6_address_rule.cpp - rfc/paths_rule.cpp + rfc/path_rules.cpp rfc/pchars.cpp rfc/pct_encoded_rule.cpp rfc/query_rule.cpp diff --git a/test/unit/Jamfile b/test/unit/Jamfile index b2df44a4..1d30e610 100644 --- a/test/unit/Jamfile +++ b/test/unit/Jamfile @@ -76,7 +76,7 @@ local SOURCES = rfc/gen_delim_chars.cpp rfc/ipv4_address_rule.cpp rfc/ipv6_address_rule.cpp - rfc/paths_rule.cpp + rfc/path_rules.cpp rfc/pchars.cpp rfc/pct_encoded_rule.cpp rfc/query_rule.cpp diff --git a/test/unit/grammar/char_rule.cpp b/test/unit/grammar/char_rule.cpp index 7da56863..2f2bda2f 100644 --- a/test/unit/grammar/char_rule.cpp +++ b/test/unit/grammar/char_rule.cpp @@ -59,6 +59,7 @@ struct char_rule_test { // test constexpr constexpr auto r = char_rule('.'); + (void)r; testRule(); } diff --git a/test/unit/grammar/dec_octet_rule.cpp b/test/unit/grammar/dec_octet_rule.cpp index f291f18a..91d6ac0e 100644 --- a/test/unit/grammar/dec_octet_rule.cpp +++ b/test/unit/grammar/dec_octet_rule.cpp @@ -31,6 +31,7 @@ struct dec_octet_rule_test { // test constexpr constexpr auto r = dec_octet_rule; + (void)r; testRule(); } diff --git a/test/unit/grammar/not_empty_rule.cpp b/test/unit/grammar/not_empty_rule.cpp index eb13e6b6..040718e1 100644 --- a/test/unit/grammar/not_empty_rule.cpp +++ b/test/unit/grammar/not_empty_rule.cpp @@ -28,6 +28,7 @@ struct not_empty_rule_test // test constexpr constexpr auto r = not_empty_rule(char_rule('.')); + (void)r; ok( pct_encoded_rule( grammar::digit_chars), diff --git a/test/unit/grammar/range_rule.cpp b/test/unit/grammar/range_rule.cpp index ccb9014e..872b108f 100644 --- a/test/unit/grammar/range_rule.cpp +++ b/test/unit/grammar/range_rule.cpp @@ -10,23 +10,57 @@ // Test that header file is self-contained. #include +#include #include #include +#include +#include #include "test_suite.hpp" +#include +#include + namespace boost { namespace urls { namespace grammar { struct range_rule_test { + template + static + void + check( + string_view s, + std::initializer_list< + string_view> init, + R const& r) + { + auto rv = parse(s, r); + if(! BOOST_TEST(rv.has_value())) + return; + if(! BOOST_TEST_EQ( + rv->size(), init.size())) + return; + BOOST_TEST( + std::equal( + rv->begin(), + rv->end(), + init.begin())); + } + void run() { // test constexpr - constexpr auto r = - range_rule(char_rule('.')); + constexpr auto r = range_rule( + token_rule(alpha_chars), + sequence_rule( + char_rule('+'), + token_rule(alpha_chars))); + + check("", {}, r); + check("x", {"x"}, r); } }; diff --git a/test/unit/grammar/sequence_rule.cpp b/test/unit/grammar/sequence_rule.cpp index 448778b6..fe569f6b 100644 --- a/test/unit/grammar/sequence_rule.cpp +++ b/test/unit/grammar/sequence_rule.cpp @@ -59,6 +59,7 @@ struct sequence_rule_test sequence_rule( char_rule('.'), char_rule('.')); + (void)r; testSequence(); } diff --git a/test/unit/grammar/token_rule.cpp b/test/unit/grammar/token_rule.cpp index 55c87ced..18759aa3 100644 --- a/test/unit/grammar/token_rule.cpp +++ b/test/unit/grammar/token_rule.cpp @@ -26,6 +26,7 @@ struct token_rule_test // test constexpr constexpr auto r = token_rule(alpha_chars); + (void)r; } }; diff --git a/test/unit/grammar/unsigned_dec_rule.cpp b/test/unit/grammar/unsigned_dec_rule.cpp index 5db1253f..9209520e 100644 --- a/test/unit/grammar/unsigned_dec_rule.cpp +++ b/test/unit/grammar/unsigned_dec_rule.cpp @@ -37,6 +37,7 @@ struct unsigned_dec_rule_test // test constexpr constexpr auto r = unsigned_dec_rule{}; + (void)r; { using T = std::uint8_t; diff --git a/test/unit/grammar/variant_rule.cpp b/test/unit/grammar/variant_rule.cpp index 5b4392c0..a60295f3 100644 --- a/test/unit/grammar/variant_rule.cpp +++ b/test/unit/grammar/variant_rule.cpp @@ -29,6 +29,7 @@ struct variant_rule_test variant_rule( char_rule('('), char_rule(')')); + (void)r; } }; diff --git a/test/unit/rfc/paths_rule.cpp b/test/unit/rfc/path_rules.cpp similarity index 96% rename from test/unit/rfc/paths_rule.cpp rename to test/unit/rfc/path_rules.cpp index c28ca9aa..9d21225b 100644 --- a/test/unit/rfc/paths_rule.cpp +++ b/test/unit/rfc/path_rules.cpp @@ -8,7 +8,7 @@ // // Test that header file is self-contained. -#include +#include #include #include @@ -18,7 +18,7 @@ namespace boost { namespace urls { -class paths_rule_test +class path_rules_test { public: /* ASCII HEX @@ -168,8 +168,8 @@ public: }; TEST_SUITE( - paths_rule_test, - "boost.url.paths_rule"); + path_rules_test, + "boost.url.path_rules"); } // urls } // boost diff --git a/test/unit/test_rule.hpp b/test/unit/test_rule.hpp index 8e4e056b..b2ed7127 100644 --- a/test/unit/test_rule.hpp +++ b/test/unit/test_rule.hpp @@ -106,9 +106,7 @@ typename std::enable_if< ok( R const& r, string_view s) { - BOOST_TEST( - grammar::parse( - s, r).has_value()); + BOOST_TEST(grammar::parse(s, r).has_value()); } // rule must fail the string @@ -119,9 +117,7 @@ bad( R const& r, string_view s) { - BOOST_TEST( - grammar::parse( - s, r).has_error()); + BOOST_TEST(grammar::parse(s, r).has_error()); } } // urls