LCOV - code coverage report
Current view: top level - boost/url/grammar/impl/range_rule.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 95.5 % 243 232
Test Date: 2024-08-19 20:08:54 Functions: 78.0 % 123 96

            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              :         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              :         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          126 :         : 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          126 :         : 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           25 :     : 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          121 :     : 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          512 :     : 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          227 :     : 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 : implementation_defined::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            0 :         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           50 :     return range<T>(
     664           25 :         core::string_view(it0, it - it0),
     665           50 :             n, next_);
     666              : }
     667              : 
     668              : //------------------------------------------------
     669              : 
     670              : template<class R0, class R1>
     671              : auto
     672          129 : implementation_defined::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            2 :         return range<T>(
     701            1 :             core::string_view(it0, it - it0),
     702            2 :                 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          240 :     return range<T>(
     734          120 :         core::string_view(it0, it - it0),
     735          240 :             n, first_, next_);
     736          113 : }
     737              : 
     738              : } // grammar
     739              : } // urls
     740              : } // boost
     741              : 
     742              : #endif
        

Generated by: LCOV version 2.1