LCOV - code coverage report
Current view: top level - boost/url/grammar/impl - range_rule.hpp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 224 234 95.7 %
Date: 2024-04-08 19:38:36 Functions: 96 123 78.0 %

          Line data    Source code
       1             : //
       2             : // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
       3             : //
       4             : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5             : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6             : //
       7             : // Official repository: https://github.com/boostorg/url
       8             : //
       9             : 
      10             : #ifndef BOOST_URL_GRAMMAR_IMPL_RANGE_HPP
      11             : #define BOOST_URL_GRAMMAR_IMPL_RANGE_HPP
      12             : 
      13             : #include <boost/url/detail/except.hpp>
      14             : #include <boost/url/grammar/error.hpp>
      15             : #include <boost/url/grammar/recycled.hpp>
      16             : #include <boost/core/empty_value.hpp>
      17             : #include <boost/assert.hpp>
      18             : #include <boost/static_assert.hpp>
      19             : #include <exception>
      20             : #include <iterator>
      21             : #include <new>
      22             : 
      23             : #include <stddef.h> // ::max_align_t
      24             : 
      25             : namespace boost {
      26             : namespace urls {
      27             : namespace grammar {
      28             : 
      29             : // VFALCO This could be reused for
      30             : // other things that need to type-erase
      31             : 
      32             : //------------------------------------------------
      33             : //
      34             : // any_rule
      35             : //
      36             : //------------------------------------------------
      37             : 
      38             : // base class for the type-erased rule pair
      39             : template<class T>
      40             : struct range<T>::
      41             :     any_rule
      42             : {
      43             :     virtual
      44        1401 :     ~any_rule() = default;
      45             : 
      46             :     virtual
      47             :     void
      48           1 :     move(void* dest) noexcept
      49             :     {
      50           1 :         ::new(dest) any_rule(
      51           1 :             std::move(*this));
      52           1 :     }
      53             : 
      54             :     virtual
      55             :     void
      56           1 :     copy(void* dest) const noexcept
      57             :     {
      58           1 :         ::new(dest) any_rule(*this);
      59           1 :     }
      60             : 
      61             :     virtual
      62             :     system::result<T>
      63           3 :     first(
      64             :         char const*&,
      65             :         char const*) const noexcept
      66             :     {
      67           3 :         return system::error_code{};
      68             :     }
      69             : 
      70             :     virtual
      71             :     system::result<T>
      72           1 :     next(
      73             :         char const*&,
      74             :         char const*) const noexcept
      75             :     {
      76           1 :         return system::error_code{};
      77             :     }
      78             : };
      79             : 
      80             : //------------------------------------------------
      81             : 
      82             : // small
      83             : template<class T>
      84             : template<class R, bool Small>
      85             : struct range<T>::impl1
      86             :     : any_rule
      87             :     , private empty_value<R>
      88             : {
      89             :     explicit
      90          23 :     impl1(R const& next) noexcept
      91             :         : empty_value<R>(
      92             :             empty_init,
      93          23 :             next)
      94             :     {
      95          23 :     }
      96             : 
      97             : private:
      98          41 :     impl1(impl1&&) noexcept = default;
      99           2 :     impl1(impl1 const&) noexcept = default;
     100             : 
     101             :     void
     102          41 :     move(void* dest
     103             :         ) noexcept override
     104             :     {
     105          41 :         ::new(dest) impl1(
     106          41 :             std::move(*this));
     107          41 :     }
     108             : 
     109             :     void
     110           2 :     copy(void* dest
     111             :         ) const noexcept override
     112             :     {
     113           2 :         ::new(dest) impl1(*this);
     114           2 :     }
     115             : 
     116             :     system::result<T>
     117           3 :     first(
     118             :         char const*& it,
     119             :         char const* end)
     120             :             const noexcept override
     121             :     {
     122           3 :         return grammar::parse(
     123           3 :             it, end, this->get());
     124             :     }
     125             : 
     126             :     system::result<T>
     127           8 :     next(
     128             :         char const*& it,
     129             :         char const* end)
     130             :             const noexcept override
     131             :     {
     132           8 :         return grammar::parse(
     133           8 :             it, end, this->get());
     134             :     }
     135             : };
     136             : 
     137             : //------------------------------------------------
     138             : 
     139             : // big
     140             : template<class T>
     141             : template<class R>
     142             : struct range<T>::impl1<R, false>
     143             :     : any_rule
     144             : {
     145             :     explicit
     146           2 :     impl1(R const& next) noexcept
     147           2 :     {
     148           2 :         ::new(p_->addr()) impl{next};
     149           2 :     }
     150             : 
     151             : private:
     152             :     struct impl
     153             :     {
     154             :         R r;
     155             :     };
     156             : 
     157             :     recycled_ptr<
     158             :         aligned_storage<impl>> p_;
     159             : 
     160           4 :     impl1(impl1&&) noexcept = default;
     161           0 :     impl1(impl1 const&) noexcept = default;
     162             : 
     163             :     impl const&
     164           9 :     get() const noexcept
     165             :     {
     166           9 :         return *reinterpret_cast<
     167           9 :             impl const*>(p_->addr());
     168             :     }
     169             : 
     170           6 :     ~impl1()
     171             :     {
     172           6 :         if(p_)
     173           2 :             get().~impl();
     174          12 :     }
     175             : 
     176             :     void
     177           4 :     move(void* dest
     178             :         ) noexcept override
     179             :     {
     180           4 :         ::new(dest) impl1(
     181           4 :             std::move(*this));
     182           4 :     }
     183             : 
     184             :     void
     185           0 :     copy(void* dest
     186             :         ) const noexcept override
     187             :     {
     188           0 :         ::new(dest) impl1(*this);
     189           0 :     }
     190             : 
     191             :     system::result<T>
     192           2 :     first(
     193             :         char const*& it,
     194             :         char const* end)
     195             :             const noexcept override
     196             :     {
     197           2 :         return grammar::parse(
     198           2 :             it, end, this->get().r);
     199             :     }
     200             : 
     201             :     system::result<T>
     202           5 :     next(
     203             :         char const*& it,
     204             :         char const* end)
     205             :             const noexcept override
     206             :     {
     207           5 :         return grammar::parse(
     208           5 :             it, end, this->get().r);
     209             :     }
     210             : };
     211             : 
     212             : //------------------------------------------------
     213             : 
     214             : // small
     215             : template<class T>
     216             : template<
     217             :     class R0, class R1, bool Small>
     218             : struct range<T>::impl2
     219             :     : any_rule
     220             :     , private empty_value<R0, 0>
     221             :     , private empty_value<R1, 1>
     222             : {
     223         119 :     impl2(
     224             :         R0 const& first,
     225             :         R1 const& next) noexcept
     226             :         : empty_value<R0,0>(
     227             :             empty_init, first)
     228             :         , empty_value<R1,1>(
     229         119 :             empty_init, next)
     230             :     {
     231         119 :     }
     232             : 
     233             : private:
     234         463 :     impl2(impl2&&) noexcept = default;
     235         225 :     impl2(impl2 const&) noexcept = default;
     236             : 
     237             :     void
     238         463 :     move(void* dest
     239             :         ) noexcept override
     240             :     {
     241         463 :         ::new(dest) impl2(
     242         463 :             std::move(*this));
     243         463 :     }
     244             : 
     245             :     void
     246         225 :     copy(void* dest
     247             :         ) const noexcept override
     248             :     {
     249         225 :         ::new(dest) impl2(*this);
     250         225 :     }
     251             : 
     252             :     system::result<T>
     253         117 :     first(
     254             :         char const*& it,
     255             :         char const* end)
     256             :             const noexcept override
     257             :     {
     258           5 :         return grammar::parse(it, end,
     259             :             empty_value<
     260         117 :                 R0,0>::get());
     261             :     }
     262             : 
     263             :     system::result<T>
     264         335 :     next(
     265             :         char const*& it,
     266             :         char const* end)
     267             :             const noexcept override
     268             :     {
     269           9 :         return grammar::parse(it, end,
     270             :             empty_value<
     271         335 :                 R1,1>::get());
     272             :     }
     273             : };
     274             : 
     275             : //------------------------------------------------
     276             : 
     277             : // big
     278             : template<class T>
     279             : template<
     280             :     class R0, class R1>
     281             : struct range<T>::impl2<R0, R1, false>
     282             :     : any_rule
     283             : {
     284           2 :     impl2(
     285             :         R0 const& first,
     286             :         R1 const& next) noexcept
     287           2 :     {
     288           2 :         ::new(p_->addr()) impl{
     289             :             first, next};
     290           2 :     }
     291             : 
     292             : private:
     293             :     struct impl
     294             :     {
     295             :         R0 first;
     296             :         R1 next;
     297             :     };
     298             : 
     299             :     recycled_ptr<
     300             :         aligned_storage<impl>> p_;
     301             : 
     302           4 :     impl2(impl2&&) noexcept = default;
     303           0 :     impl2(impl2 const&) noexcept = default;
     304             : 
     305             :     impl const&
     306           9 :     get() const noexcept
     307             :     {
     308           9 :         return *reinterpret_cast<
     309           9 :             impl const*>(p_->addr());
     310             :     }
     311             : 
     312           6 :     ~impl2()
     313             :     {
     314           6 :         if(p_)
     315           2 :             get().~impl();
     316          12 :     }
     317             : 
     318             :     void
     319           4 :     move(void* dest
     320             :         ) noexcept override
     321             :     {
     322           4 :         ::new(dest) impl2(
     323           4 :             std::move(*this));
     324           4 :     }
     325             : 
     326             :     void
     327           0 :     copy(void* dest
     328             :         ) const noexcept override
     329             :     {
     330           0 :         ::new(dest) impl2(*this);
     331           0 :     }
     332             : 
     333             :     system::result<T>
     334           2 :     first(
     335             :         char const*& it,
     336             :         char const* end)
     337             :             const noexcept override
     338             :     {
     339           2 :         return grammar::parse(
     340           2 :             it, end, get().first);
     341             :     }
     342             : 
     343             :     system::result<T>
     344           5 :     next(
     345             :         char const*& it,
     346             :         char const* end)
     347             :             const noexcept override
     348             :     {
     349           5 :         return grammar::parse(
     350           5 :             it, end, get().next);
     351             :     }
     352             : };
     353             : 
     354             : //------------------------------------------------
     355             : //
     356             : // iterator
     357             : //
     358             : //------------------------------------------------
     359             : 
     360             : template<class T>
     361             : class range<T>::
     362             :     iterator
     363             : {
     364             : public:
     365             :     using value_type = T;
     366             :     using reference = T const&;
     367             :     using pointer = void const*;
     368             :     using difference_type =
     369             :         std::ptrdiff_t;
     370             :     using iterator_category =
     371             :         std::forward_iterator_tag;
     372             : 
     373             :     iterator() = default;
     374             :     iterator(
     375             :         iterator const&) = default;
     376             :     iterator& operator=(
     377             :         iterator const&) = default;
     378             : 
     379             :     reference
     380         734 :     operator*() const noexcept
     381             :     {
     382         734 :         return *rv_;
     383             :     }
     384             : 
     385             :     bool
     386         479 :     operator==(
     387             :         iterator const& other) const noexcept
     388             :     {
     389             :         // can't compare iterators
     390             :         // from different containers!
     391         479 :         BOOST_ASSERT(r_ == other.r_);
     392             : 
     393         479 :         return p_ == other.p_;
     394             :     }
     395             : 
     396             :     bool
     397         477 :     operator!=(
     398             :         iterator const& other) const noexcept
     399             :     {
     400         477 :         return !(*this == other);
     401             :     }
     402             : 
     403             :     iterator&
     404         353 :     operator++() noexcept
     405             :     {
     406         353 :         BOOST_ASSERT(
     407             :             p_ != nullptr);
     408         353 :         auto const end =
     409         353 :             r_->s_.data() +
     410         353 :             r_->s_.size();
     411         353 :         rv_ = r_->get().next(p_, end);
     412         353 :         if( !rv_ )
     413         123 :             p_ = nullptr;
     414         353 :         return *this;
     415             :     }
     416             : 
     417             :     iterator
     418             :     operator++(int) noexcept
     419             :     {
     420             :         auto tmp = *this;
     421             :         ++*this;
     422             :         return tmp;
     423             :     }
     424             : 
     425             : private:
     426             :     friend class range<T>;
     427             : 
     428             :     range<T> const* r_ = nullptr;
     429             :     char const* p_ = nullptr;
     430             :     system::result<T> rv_;
     431             : 
     432         126 :     iterator(
     433             :         range<T> const& r) noexcept
     434             :         : r_(&r)
     435         126 :         , p_(r.s_.data())
     436             :     {
     437         126 :         auto const end =
     438         126 :             r_->s_.data() +
     439         126 :             r_->s_.size();
     440         126 :         rv_ = r_->get().first(p_, end);
     441         126 :         if( !rv_ )
     442           3 :             p_ = nullptr;
     443         126 :     }
     444             : 
     445             :     constexpr
     446         126 :     iterator(
     447             :         range<T> const& r,
     448             :         int) noexcept
     449             :         : r_(&r)
     450         126 :         , p_(nullptr)
     451             :     {
     452         126 :     }
     453             : };
     454             : 
     455             : //------------------------------------------------
     456             : 
     457             : template<class T>
     458             : template<class R>
     459          25 : range<T>::
     460             : range(
     461             :     core::string_view s,
     462             :     std::size_t n,
     463             :     R const& next)
     464             :     : s_(s)
     465          25 :     , n_(n)
     466             : {
     467             :     BOOST_STATIC_ASSERT(
     468             :         sizeof(impl1<R, false>) <=
     469             :             BufferSize);
     470             : 
     471          25 :     ::new(&get()) impl1<R,
     472             :         sizeof(impl1<R, true>) <=
     473             :             BufferSize>(next);
     474          25 : }
     475             : 
     476             : //------------------------------------------------
     477             : 
     478             : template<class T>
     479             : template<
     480             :     class R0, class R1>
     481         121 : range<T>::
     482             : range(
     483             :     core::string_view s,
     484             :     std::size_t n,
     485             :     R0 const& first,
     486             :     R1 const& next)
     487             :     : s_(s)
     488         121 :     , n_(n)
     489             : {
     490             :     BOOST_STATIC_ASSERT(
     491             :         sizeof(impl2<R0, R1, false>) <=
     492             :             BufferSize);
     493             : 
     494         121 :     ::new(&get()) impl2<R0, R1,
     495             :         sizeof(impl2<R0, R1, true>
     496             :             ) <= BufferSize>(
     497             :                 first, next);
     498         121 : }
     499             : 
     500             : //------------------------------------------------
     501             : 
     502             : template<class T>
     503         886 : range<T>::
     504             : ~range()
     505             : {
     506         886 :     get().~any_rule();
     507         886 : }
     508             : 
     509             : template<class T>
     510           1 : range<T>::
     511           1 : range() noexcept
     512             : {
     513           1 :     ::new(&get()) any_rule{};
     514           1 :     char const* it = nullptr;
     515           1 :     get().first(it, nullptr);
     516           1 :     get().next(it, nullptr);
     517           1 : }
     518             : 
     519             : template<class T>
     520         512 : range<T>::
     521             : range(
     522             :     range&& other) noexcept
     523             :     : s_(other.s_)
     524         512 :     , n_(other.n_)
     525             : {
     526         512 :     other.s_ = {};
     527         512 :     other.n_ = {};
     528         512 :     other.get().move(&get());
     529         512 :     other.get().~any_rule();
     530         512 :     ::new(&other.get()) any_rule{};
     531         512 : }
     532             : 
     533             : template<class T>
     534         227 : range<T>::
     535             : range(
     536             :     range const& other) noexcept
     537             :     : s_(other.s_)
     538         227 :     , n_(other.n_)
     539             : {
     540         227 :     other.get().copy(&get());
     541         227 : }
     542             : 
     543             : template<class T>
     544             : auto
     545           1 : range<T>::
     546             : operator=(
     547             :     range&& other) noexcept ->
     548             :         range&
     549             : {
     550           1 :     s_ = other.s_;
     551           1 :     n_ = other.n_;
     552           1 :     other.s_ = {};
     553           1 :     other.n_ = 0;
     554             :     // VFALCO we rely on nothrow move
     555             :     // construction here, but if necessary we
     556             :     // could move to a local buffer first.
     557           1 :     get().~any_rule();
     558           1 :     other.get().move(&get());
     559           1 :     other.get().~any_rule();
     560           1 :     ::new(&other.get()) any_rule{};
     561           1 :     return *this;
     562             : }
     563             : 
     564             : template<class T>
     565             : auto
     566           1 : range<T>::
     567             : operator=(
     568             :     range const& other) noexcept ->
     569             :         range&
     570             : {
     571           1 :     s_ = other.s_;
     572           1 :     n_ = other.n_;
     573             :     // VFALCO we rely on nothrow copy
     574             :     // construction here, but if necessary we
     575             :     // could construct to a local buffer first.
     576           1 :     get().~any_rule();
     577           1 :     other.get().copy(&get());
     578           1 :     return *this;
     579             : }
     580             : 
     581             : template<class T>
     582             : auto
     583         126 : range<T>::
     584             : begin() const noexcept ->
     585             :     iterator
     586             : {
     587         126 :     return { *this };
     588             : }
     589             : 
     590             : template<class T>
     591             : auto
     592         126 : range<T>::
     593             : end() const noexcept ->
     594             :     iterator
     595             : {
     596         126 :     return { *this, 0 };
     597             : }
     598             : 
     599             : //------------------------------------------------
     600             : 
     601             : template<class R>
     602             : auto
     603          37 : range_rule_t<R>::
     604             : parse(
     605             :     char const*& it,
     606             :     char const* end) const ->
     607             :         system::result<value_type>
     608             : {
     609             :     using T = typename R::value_type;
     610             : 
     611          37 :     std::size_t n = 0;
     612          37 :     auto const it0 = it;
     613          37 :     auto it1 = it;
     614          37 :     auto rv = (grammar::parse)(
     615          37 :         it, end, next_);
     616          37 :     if( !rv )
     617             :     {
     618           6 :         if(rv.error() != error::end_of_range)
     619             :         {
     620             :             // rewind unless error::end_of_range
     621           6 :             it = it1;
     622             :         }
     623           6 :         if(n < N_)
     624             :         {
     625             :             // too few
     626           6 :             BOOST_URL_RETURN_EC(
     627             :                 error::mismatch);
     628             :         }
     629             :         // good
     630             :         return range<T>(
     631           0 :             core::string_view(it0, it - it0),
     632           0 :                 n, next_);
     633             :     }
     634          32 :     for(;;)
     635             :     {
     636          63 :         ++n;
     637          63 :         it1 = it;
     638          63 :         rv = (grammar::parse)(
     639          63 :             it, end, next_);
     640          63 :         if( !rv )
     641             :         {
     642          27 :             if(rv.error() != error::end_of_range)
     643             :             {
     644             :                 // rewind unless error::end_of_range
     645          27 :                 it = it1;
     646             :             }
     647          27 :             break;
     648             :         }
     649          36 :         if(n >= M_)
     650             :         {
     651             :             // too many
     652           4 :             BOOST_URL_RETURN_EC(
     653             :                 error::mismatch);
     654             :         }
     655             :     }
     656          27 :     if(n < N_)
     657             :     {
     658             :         // too few
     659           2 :         BOOST_URL_RETURN_EC(
     660             :             error::mismatch);
     661             :     }
     662             :     // good
     663             :     return range<T>(
     664          25 :         core::string_view(it0, it - it0),
     665          25 :             n, next_);
     666             : }
     667             : 
     668             : //------------------------------------------------
     669             : 
     670             : template<class R0, class R1>
     671             : auto
     672         129 : range_rule_t<R0, R1>::
     673             : parse(
     674             :     char const*& it,
     675             :     char const* end) const ->
     676             :         system::result<range<typename
     677             :             R0::value_type>>
     678             : {
     679             :     using T = typename R0::value_type;
     680             : 
     681         129 :     std::size_t n = 0;
     682         129 :     auto const it0 = it;
     683         129 :     auto it1 = it;
     684         129 :     auto rv = (grammar::parse)(
     685         129 :         it, end, first_);
     686         129 :     if( !rv )
     687             :     {
     688           4 :         if(rv.error() != error::end_of_range)
     689             :         {
     690             :             // rewind unless error::end_of_range
     691           4 :             it = it1;
     692             :         }
     693           4 :         if(n < N_)
     694             :         {
     695             :             // too few
     696           3 :             BOOST_URL_RETURN_EC(
     697             :                 error::mismatch);
     698             :         }
     699             :         // good
     700             :         return range<T>(
     701           1 :             core::string_view(it0, it - it0),
     702           1 :                 n, first_, next_);
     703             :     }
     704         233 :     for(;;)
     705             :     {
     706         358 :         ++n;
     707         358 :         it1 = it;
     708         358 :         rv = (grammar::parse)(
     709         358 :             it, end, next_);
     710         358 :         if( !rv )
     711             :         {
     712         121 :             if(rv.error() != error::end_of_range)
     713             :             {
     714             :                 // rewind unless error::end_of_range
     715         121 :                 it = it1;
     716             :             }
     717         121 :             break;
     718             :         }
     719         237 :         if(n >= M_)
     720             :         {
     721             :             // too many
     722           4 :             BOOST_URL_RETURN_EC(
     723             :                 error::mismatch);
     724             :         }
     725             :     }
     726         121 :     if(n < N_)
     727             :     {
     728             :         // too few
     729           1 :         BOOST_URL_RETURN_EC(
     730             :             error::mismatch);
     731             :     }
     732             :     // good
     733             :     return range<T>(
     734         120 :         core::string_view(it0, it - it0),
     735         120 :             n, first_, next_);
     736             : }
     737             : 
     738             : } // grammar
     739             : } // urls
     740             : } // boost
     741             : 
     742             : #endif

Generated by: LCOV version 1.15