// // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) // Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/url // #ifndef BOOST_URL_GRAMMAR_IMPL_RANGE_HPP #define BOOST_URL_GRAMMAR_IMPL_RANGE_HPP #include #include #include #include #include #include #include #include #include #include #include #include // ::max_align_t namespace boost { namespace urls { namespace grammar { //------------------------------------------------ // // any_rule // //------------------------------------------------ template struct any_rule::impl_base { virtual ~impl_base() = default; virtual void move(void* dest) noexcept { ::new(dest) impl_base( std::move(*this)); } virtual void copy(void* dest) const noexcept { ::new(dest) impl_base(*this); } virtual system::result first( char const*&, char const*) const noexcept { return system::error_code{}; } virtual system::result next( char const*&, char const*) const noexcept { return system::error_code{}; } }; //------------------------------------------------ // small template template struct any_rule::impl1 : impl_base , private empty_value { explicit impl1(R const& next) noexcept : empty_value( empty_init, next) { } private: impl1(impl1&&) noexcept = default; impl1(impl1 const&) noexcept = default; void move(void* dest ) noexcept override { ::new(dest) impl1( std::move(*this)); } void copy(void* dest ) const noexcept override { ::new(dest) impl1(*this); } system::result first( char const*& it, char const* end) const noexcept override { return grammar::parse( it, end, this->get()); } system::result next( char const*& it, char const* end) const noexcept override { return grammar::parse( it, end, this->get()); } }; //------------------------------------------------ // big template template struct any_rule::impl1 : impl_base { explicit impl1(R const& next) noexcept { ::new(p_->addr()) impl{next}; } private: struct impl { R r; }; recycled_ptr< aligned_storage> p_; impl1(impl1&&) noexcept = default; impl1(impl1 const&) noexcept = default; impl const& get() const noexcept { return *reinterpret_cast< impl const*>(p_->addr()); } ~impl1() { if(p_) get().~impl(); } void move(void* dest ) noexcept override { ::new(dest) impl1( std::move(*this)); } void copy(void* dest ) const noexcept override { ::new(dest) impl1(*this); } system::result first( char const*& it, char const* end) const noexcept override { return grammar::parse( it, end, this->get().r); } system::result next( char const*& it, char const* end) const noexcept override { return grammar::parse( it, end, this->get().r); } }; //------------------------------------------------ // small template template< class R0, class R1, bool Small> struct any_rule::impl2 : impl_base , private empty_value , private empty_value { impl2( R0 const& first, R1 const& next) noexcept : empty_value( empty_init, first) , empty_value( empty_init, next) { } private: impl2(impl2&&) noexcept = default; impl2(impl2 const&) noexcept = default; void move(void* dest ) noexcept override { ::new(dest) impl2( std::move(*this)); } void copy(void* dest ) const noexcept override { ::new(dest) impl2(*this); } system::result first( char const*& it, char const* end) const noexcept override { return grammar::parse(it, end, empty_value< R0,0>::get()); } system::result next( char const*& it, char const* end) const noexcept override { return grammar::parse(it, end, empty_value< R1,1>::get()); } }; //------------------------------------------------ // big template template< class R0, class R1> struct any_rule::impl2 : impl_base { impl2( R0 const& first, R1 const& next) noexcept { ::new(p_->addr()) impl{ first, next}; } private: struct impl { R0 first; R1 next; }; recycled_ptr< aligned_storage> p_; impl2(impl2&&) noexcept = default; impl2(impl2 const&) noexcept = default; impl const& get() const noexcept { return *reinterpret_cast< impl const*>(p_->addr()); } ~impl2() { if(p_) get().~impl(); } void move(void* dest ) noexcept override { ::new(dest) impl2( std::move(*this)); } void copy(void* dest ) const noexcept override { ::new(dest) impl2(*this); } system::result first( char const*& it, char const* end) const noexcept override { return grammar::parse( it, end, get().first); } system::result next( char const*& it, char const* end) const noexcept override { return grammar::parse( it, end, get().next); } }; //------------------------------------------------ template typename any_rule::impl_base& any_rule:: get() noexcept { return *reinterpret_cast< impl_base*>(sb_.addr()); } template typename any_rule::impl_base const& any_rule:: get() const noexcept { return *reinterpret_cast< impl_base const*>(sb_.addr()); } template any_rule:: any_rule() noexcept { ::new(sb_.addr()) impl_base{}; char const* it = nullptr; get().first(it, nullptr); get().next(it, nullptr); } template any_rule:: any_rule(any_rule&& other) noexcept { other.get().move(sb_.addr()); } template any_rule:: any_rule(any_rule const& other) noexcept { other.get().copy(sb_.addr()); } template any_rule& any_rule:: operator=(any_rule&& other) noexcept { if(this == &other) return *this; get().~impl_base(); other.get().move(sb_.addr()); return *this; } template any_rule& any_rule:: operator=(any_rule const& other) noexcept { if(this == &other) return *this; get().~impl_base(); other.get().copy(sb_.addr()); return *this; } template any_rule:: ~any_rule() { get().~impl_base(); } template template any_rule:: any_rule( R const& next) { static_assert( ::boost::urls::grammar::is_rule::value, "Rule requirements not met"); static_assert( std::is_same::value, "Rule value_type mismatch"); BOOST_CORE_STATIC_ASSERT( sizeof(impl1) <= BufferSize); ::new(sb_.addr()) impl1) <= BufferSize>(next); } //------------------------------------------------ template template< class R0, class R1> any_rule:: any_rule( R0 const& first, R1 const& next) { static_assert( ::boost::urls::grammar::is_rule::value, "Rule requirements not met"); static_assert( ::boost::urls::grammar::is_rule::value, "Rule requirements not met"); static_assert( std::is_same::value, "First rule value_type mismatch"); static_assert( std::is_same::value, "Next rule value_type mismatch"); BOOST_CORE_STATIC_ASSERT( sizeof(impl2) <= BufferSize); ::new(sb_.addr()) impl2 ) <= BufferSize>( first, next); } //------------------------------------------------ template system::result any_rule:: first( char const*& it, char const* end) const noexcept { return get().first(it, end); } //------------------------------------------------ template system::result any_rule:: next( char const*& it, char const* end) const noexcept { return get().next(it, end); } //------------------------------------------------ // // range // //------------------------------------------------ template range:: ~range() = default; template range:: range() noexcept = default; template range:: range( range&& other) noexcept : detail::range_base_storage< RangeRule>(std::move(other.rule())) , s_(other.s_) , n_(other.n_) { other.s_ = {}; other.n_ = 0; } template range:: range( range const& other) noexcept : detail::range_base_storage< RangeRule>(other.rule()) , s_(other.s_) , n_(other.n_) { } template auto range:: operator=(range&& other) noexcept -> range& { if(this == &other) return *this; static_cast< detail::range_base_storage< RangeRule>&>(*this) = std::move(static_cast< detail::range_base_storage< RangeRule>&>(other)); s_ = other.s_; n_ = other.n_; other.s_ = {}; other.n_ = 0; return *this; } template auto range:: operator=(range const& other) noexcept -> range& { if(this == &other) return *this; static_cast< detail::range_base_storage< RangeRule>&>(*this) = static_cast< detail::range_base_storage< RangeRule> const&>(other); s_ = other.s_; n_ = other.n_; return *this; } //------------------------------------------------ // // iterator // //------------------------------------------------ template class range:: iterator { public: using value_type = T; using reference = T const&; using pointer = void const*; using difference_type = std::ptrdiff_t; using iterator_category = std::forward_iterator_tag; iterator() = default; iterator( iterator const&) = default; iterator& operator=( iterator const&) = default; reference operator*() const noexcept { return *rv_; } bool operator==( iterator const& other) const noexcept { // can't compare iterators // from different containers! BOOST_ASSERT(r_ == other.r_); return p_ == other.p_; } bool operator!=( iterator const& other) const noexcept { return !(*this == other); } iterator& operator++() noexcept { BOOST_ASSERT( p_ != nullptr); auto const end = r_->s_.data() + r_->s_.size(); rv_ = r_->rule().next(p_, end); if( !rv_ ) p_ = nullptr; return *this; } iterator operator++(int) noexcept { auto tmp = *this; ++*this; return tmp; } private: friend class range; range const* r_ = nullptr; char const* p_ = nullptr; system::result rv_; iterator( range const& r) noexcept : r_(&r) , p_(r.s_.data()) { auto const end = r_->s_.data() + r_->s_.size(); rv_ = r_->rule().first(p_, end); if( !rv_ ) p_ = nullptr; } constexpr iterator( range const& r, int) noexcept : r_(&r) , p_(nullptr) { } }; //------------------------------------------------ template typename range::iterator range:: begin() const noexcept { return iterator(*this); } //------------------------------------------------ template typename range::iterator range:: end() const noexcept { return iterator(*this, 0); } //------------------------------------------------ template range:: range( core::string_view s, std::size_t n, RangeRule const& rule) noexcept : detail::range_base_storage< RangeRule>(rule) , s_(s) , n_(n) { } //------------------------------------------------ template range:: range( core::string_view s, std::size_t n, RangeRule&& rule) noexcept : detail::range_base_storage< RangeRule>(std::move(rule)) , s_(s) , n_(n) { } //------------------------------------------------ template BOOST_URL_CXX20_CONSTEXPR auto implementation_defined::range_rule_t:: parse( char const*& it, char const* end) const -> system::result { using T = typename R::value_type; std::size_t n = 0; auto const it0 = it; auto it1 = it; auto rv = (grammar::parse)( it, end, next_); if( !rv ) { if(rv.error() != error::end_of_range) { // rewind unless error::end_of_range it = it1; } if(n < N_) { // too few BOOST_URL_CONSTEXPR_RETURN_EC( error::mismatch); } // good return range( core::string_view(it0, it - it0), n, any_rule(next_)); } for(;;) { ++n; it1 = it; rv = (grammar::parse)( it, end, next_); if( !rv ) { if(rv.error() != error::end_of_range) { // rewind unless error::end_of_range it = it1; } break; } if(n >= M_) { // too many BOOST_URL_CONSTEXPR_RETURN_EC( error::mismatch); } } if(n < N_) { // too few BOOST_URL_CONSTEXPR_RETURN_EC( error::mismatch); } // good return range( core::string_view(it0, it - it0), n, any_rule(next_)); } //------------------------------------------------ template BOOST_URL_CXX20_CONSTEXPR auto implementation_defined::range_rule_t:: parse( char const*& it, char const* end) const -> system::result> { using T = typename R0::value_type; std::size_t n = 0; auto const it0 = it; auto it1 = it; auto rv = (grammar::parse)( it, end, first_); if( !rv ) { if(rv.error() != error::end_of_range) { it = it1; } if(n < N_) { BOOST_URL_CONSTEXPR_RETURN_EC( error::mismatch); } return range( core::string_view(it0, it - it0), n, any_rule(first_, next_)); } for(;;) { ++n; it1 = it; rv = (grammar::parse)( it, end, next_); if( !rv ) { if(rv.error() != error::end_of_range) { // rewind unless error::end_of_range it = it1; } break; } if(n >= M_) { // too many BOOST_URL_CONSTEXPR_RETURN_EC( error::mismatch); } } if(n < N_) { // too few BOOST_URL_CONSTEXPR_RETURN_EC( error::mismatch); } // good return range( core::string_view(it0, it - it0), n, any_rule(first_, next_)); } } // grammar } // urls } // boost #endif