LCOV - code coverage report
Current view: top level - boost/url/grammar/range_rule.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 29 29
Test Date: 2024-07-10 02:48:26 Functions: 100.0 % 21 21

            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_RANGE_RULE_HPP
      11              : #define BOOST_URL_GRAMMAR_RANGE_RULE_HPP
      12              : 
      13              : #include <boost/url/detail/config.hpp>
      14              : #include <boost/url/error.hpp>
      15              : #include <boost/core/detail/string_view.hpp>
      16              : #include <boost/url/grammar/parse.hpp>
      17              : #include <boost/url/grammar/type_traits.hpp>
      18              : #include <boost/static_assert.hpp>
      19              : #include <cstddef>
      20              : #include <iterator>
      21              : #include <type_traits>
      22              : 
      23              : #include <stddef.h> // ::max_align_t
      24              : 
      25              : namespace boost {
      26              : namespace urls {
      27              : namespace grammar {
      28              : 
      29              : /** A forward range of parsed elements
      30              : 
      31              :     Objects of this type are forward ranges
      32              :     returned when parsing using the
      33              :     @ref range_rule.
      34              :     Iteration is performed by re-parsing the
      35              :     underlying character buffer. Ownership
      36              :     of the buffer is not transferred; the
      37              :     caller is responsible for ensuring that
      38              :     the lifetime of the buffer extends until
      39              :     it is no longer referenced by the range.
      40              : 
      41              :     @note
      42              : 
      43              :     The implementation may use temporary,
      44              :     recycled storage for type-erasure. Objects
      45              :     of type `range` are intended to be used
      46              :     ephemerally. That is, for short durations
      47              :     such as within a function scope. If it is
      48              :     necessary to store the range for a long
      49              :     period of time or with static storage
      50              :     duration, it is necessary to copy the
      51              :     contents to an object of a different type.
      52              : 
      53              :     @tparam T The value type of the range
      54              : 
      55              :     @see
      56              :         @ref parse,
      57              :         @ref range_rule.
      58              : */
      59              : template<class T>
      60              : class range
      61              : {
      62              :     // buffer size for type-erased rule
      63              :     static constexpr
      64              :         std::size_t BufferSize = 128;
      65              : 
      66              :     struct small_buffer
      67              :     {
      68              :         alignas(alignof(::max_align_t))
      69              :         unsigned char buf[BufferSize];
      70              : 
      71          707 :         void const* addr() const noexcept
      72              :         {
      73          707 :             return buf;
      74              :         }
      75              : 
      76         3317 :         void* addr() noexcept
      77              :         {
      78         3317 :             return buf;
      79              :         }
      80              :     };
      81              : 
      82              :     small_buffer sb_;
      83              :     core::string_view s_;
      84              :     std::size_t n_ = 0;
      85              : 
      86              :     //--------------------------------------------
      87              : 
      88              :     struct any_rule;
      89              : 
      90              :     template<class R, bool>
      91              :     struct impl1;
      92              : 
      93              :     template<
      94              :         class R0, class R1, bool>
      95              :     struct impl2;
      96              : 
      97              :     template<
      98              :         class R0, class R1>
      99              :     friend struct range_rule_t;
     100              : 
     101              :     any_rule&
     102         3317 :     get() noexcept
     103              :     {
     104              :         return *reinterpret_cast<
     105         3317 :             any_rule*>(sb_.addr());
     106              :     }
     107              : 
     108              :     any_rule const&
     109          707 :     get() const noexcept
     110              :     {
     111              :         return *reinterpret_cast<
     112              :             any_rule const*>(
     113          707 :                 sb_.addr());
     114              :     }
     115              : 
     116              :     template<class R>
     117              :     range(
     118              :         core::string_view s,
     119              :         std::size_t n,
     120              :         R const& r);
     121              : 
     122              :     template<
     123              :         class R0, class R1>
     124              :     range(
     125              :         core::string_view s,
     126              :         std::size_t n,
     127              :         R0 const& first,
     128              :         R1 const& next);
     129              : 
     130              : public:
     131              :     /** The type of each element of the range
     132              :     */
     133              :     using value_type = T;
     134              : 
     135              :     /** The type of each element of the range
     136              :     */
     137              :     using reference = T const&;
     138              : 
     139              :     /** The type of each element of the range
     140              :     */
     141              :     using const_reference = T const&;
     142              : 
     143              :     /** Provided for compatibility, unused
     144              :     */
     145              :     using pointer = void const*;
     146              : 
     147              :     /** The type used to represent unsigned integers
     148              :     */
     149              :     using size_type = std::size_t;
     150              : 
     151              :     /** The type used to represent signed integers
     152              :     */
     153              :     using difference_type = std::ptrdiff_t;
     154              : 
     155              :     /** A constant, forward iterator to elements of the range
     156              :     */
     157              :     class iterator;
     158              : 
     159              :     /** A constant, forward iterator to elements of the range
     160              :     */
     161              :     using const_iterator = iterator;
     162              : 
     163              :     /** Destructor
     164              :     */
     165              :     ~range();
     166              : 
     167              :     /** Constructor
     168              : 
     169              :         Default-constructed ranges have
     170              :         zero elements.
     171              : 
     172              :         @par Exception Safety
     173              :         Throws nothing.
     174              :     */
     175              :     range() noexcept;
     176              : 
     177              :     /** Constructor
     178              : 
     179              :         The new range references the
     180              :         same underlying character buffer.
     181              :         Ownership is not transferred; the
     182              :         caller is responsible for ensuring
     183              :         that the lifetime of the buffer
     184              :         extends until it is no longer
     185              :         referenced. The moved-from object
     186              :         becomes as if default-constructed.
     187              : 
     188              :         @par Exception Safety
     189              :         Throws nothing.
     190              :     */
     191              :     range(range&&) noexcept;
     192              : 
     193              :     /** Constructor
     194              : 
     195              :         The copy references the same
     196              :         underlying character buffer.
     197              :         Ownership is not transferred; the
     198              :         caller is responsible for ensuring
     199              :         that the lifetime of the buffer
     200              :         extends until it is no longer
     201              :         referenced.
     202              : 
     203              :         @par Exception Safety
     204              :         Throws nothing.
     205              :     */
     206              :     range(range const&) noexcept;
     207              : 
     208              :     /** Assignment
     209              : 
     210              :         After the move, this references the
     211              :         same underlying character buffer. Ownership
     212              :         is not transferred; the caller is responsible
     213              :         for ensuring that the lifetime of the buffer
     214              :         extends until it is no longer referenced.
     215              :         The moved-from object becomes as if
     216              :         default-constructed.
     217              : 
     218              :         @par Exception Safety
     219              :         Throws nothing.
     220              :     */
     221              :     range&
     222              :     operator=(range&&) noexcept;
     223              : 
     224              :     /** Assignment
     225              : 
     226              :         The copy references the same
     227              :         underlying character buffer.
     228              :         Ownership is not transferred; the
     229              :         caller is responsible for ensuring
     230              :         that the lifetime of the buffer
     231              :         extends until it is no longer
     232              :         referenced.
     233              : 
     234              :         @par Exception Safety
     235              :         Throws nothing.
     236              :     */
     237              :     range&
     238              :     operator=(range const&) noexcept;
     239              : 
     240              :     /** Return an iterator to the beginning
     241              :     */
     242              :     iterator begin() const noexcept;
     243              : 
     244              :     /** Return an iterator to the end
     245              :     */
     246              :     iterator end() const noexcept;
     247              : 
     248              :     /** Return true if the range is empty
     249              :     */
     250              :     bool
     251           11 :     empty() const noexcept
     252              :     {
     253           11 :         return n_ == 0;
     254              :     }
     255              : 
     256              :     /** Return the number of elements in the range
     257              :     */
     258              :     std::size_t
     259           34 :     size() const noexcept
     260              :     {
     261           34 :         return n_;
     262              :     }
     263              : 
     264              :     /** Return the matching part of the string
     265              :     */
     266              :     core::string_view
     267           19 :     string() const noexcept
     268              :     {
     269           19 :         return s_;
     270              :     }
     271              : };
     272              : 
     273              : //------------------------------------------------
     274              : 
     275              : #ifndef BOOST_URL_DOCS
     276              : template<
     277              :     class R0,
     278              :     class R1 = void>
     279              : struct range_rule_t;
     280              : #endif
     281              : 
     282              : //------------------------------------------------
     283              : 
     284              : /** Match a repeating number of elements
     285              : 
     286              :     Elements are matched using the passed rule.
     287              :     <br>
     288              :     Normally when the rule returns an error,
     289              :     the range ends and the input is rewound to
     290              :     one past the last character that matched
     291              :     successfully. However, if the rule returns
     292              :     the special value @ref error::end_of_range, the
     293              :     input is not rewound. This allows for rules
     294              :     which consume input without producing
     295              :     elements in the range. For example, to
     296              :     relax the grammar for a comma-delimited
     297              :     list by allowing extra commas in between
     298              :     elements.
     299              : 
     300              :     @par Value Type
     301              :     @code
     302              :     using value_type = range< typename Rule::value_type >;
     303              :     @endcode
     304              : 
     305              :     @par Example
     306              :     Rules are used with the function @ref parse.
     307              :     @code
     308              :     // range    = 1*( ";" token )
     309              : 
     310              :     system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
     311              :         range_rule(
     312              :             tuple_rule(
     313              :                 squelch( delim_rule( ';' ) ),
     314              :                 token_rule( alpha_chars ) ),
     315              :             1 ) );
     316              :     @endcode
     317              : 
     318              :     @par BNF
     319              :     @code
     320              :     range        = <N>*<M>next
     321              :     @endcode
     322              : 
     323              :     @par Specification
     324              :     @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
     325              :         >3.6.  Variable Repetition (rfc5234)</a>
     326              : 
     327              :     @param next The rule to use for matching
     328              :     each element. The range extends until this
     329              :     rule returns an error.
     330              : 
     331              :     @param N The minimum number of elements for
     332              :     the range to be valid. If omitted, this
     333              :     defaults to zero.
     334              : 
     335              :     @param M The maximum number of elements for
     336              :     the range to be valid. If omitted, this
     337              :     defaults to unlimited.
     338              : 
     339              :     @see
     340              :         @ref alpha_chars,
     341              :         @ref delim_rule,
     342              :         @ref error::end_of_range,
     343              :         @ref parse,
     344              :         @ref range,
     345              :         @ref tuple_rule,
     346              :         @ref squelch.
     347              : */
     348              : #ifdef BOOST_URL_DOCS
     349              : template<class Rule>
     350              : constexpr
     351              : __implementation_defined__
     352              : range_rule(
     353              :     Rule next,
     354              :     std::size_t N = 0,
     355              :     std::size_t M =
     356              :         std::size_t(-1)) noexcept;
     357              : #else
     358              : template<class R>
     359              : struct range_rule_t<R>
     360              : {
     361              :     using value_type =
     362              :         range<typename R::value_type>;
     363              : 
     364              :     system::result<value_type>
     365              :     parse(
     366              :         char const*& it,
     367              :         char const* end) const;
     368              : 
     369              : private:
     370              :     constexpr
     371           18 :     range_rule_t(
     372              :         R const& next,
     373              :         std::size_t N,
     374              :         std::size_t M) noexcept
     375           18 :         : next_(next)
     376           18 :         , N_(N)
     377           18 :         , M_(M)
     378              :     {
     379           18 :     }
     380              : 
     381              :     template<class R_>
     382              :     friend
     383              :     constexpr
     384              :     range_rule_t<R_>
     385              :     range_rule(
     386              :         R_ const& next,
     387              :         std::size_t N,
     388              :         std::size_t M) noexcept;
     389              : 
     390              :     R const next_;
     391              :     std::size_t N_;
     392              :     std::size_t M_;
     393              : };
     394              : 
     395              : template<class Rule>
     396              : constexpr
     397              : range_rule_t<Rule>
     398           18 : range_rule(
     399              :     Rule const& next,
     400              :     std::size_t N = 0,
     401              :     std::size_t M =
     402              :         std::size_t(-1)) noexcept
     403              : {
     404              :     // If you get a compile error here it
     405              :     // means that your rule does not meet
     406              :     // the type requirements. Please check
     407              :     // the documentation.
     408              :     static_assert(
     409              :         is_rule<Rule>::value,
     410              :         "Rule requirements not met");
     411              : 
     412              :     return range_rule_t<Rule>{
     413           18 :         next, N, M};
     414              : }
     415              : #endif
     416              : 
     417              : //------------------------------------------------
     418              : 
     419              : /** Match a repeating number of elements
     420              : 
     421              :     Two rules are used for match. The rule
     422              :     `first` is used for matching the first
     423              :     element, while the `next` rule is used
     424              :     to match every subsequent element.
     425              :     <br>
     426              :     Normally when the rule returns an error,
     427              :     the range ends and the input is rewound to
     428              :     one past the last character that matched
     429              :     successfully. However, if the rule returns
     430              :     the special value @ref error::end_of_range, the
     431              :     input is not rewound. This allows for rules
     432              :     which consume input without producing
     433              :     elements in the range. For example, to
     434              :     relax the grammar for a comma-delimited
     435              :     list by allowing extra commas in between
     436              :     elements.
     437              : 
     438              :     @par Value Type
     439              :     @code
     440              :     using value_type = range< typename Rule::value_type >;
     441              :     @endcode
     442              : 
     443              :     @par Example
     444              :     Rules are used with the function @ref parse.
     445              :     @code
     446              :     // range    = [ token ] *( "," token )
     447              : 
     448              :     system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
     449              :         range_rule(
     450              :             token_rule( alpha_chars ),          // first
     451              :             tuple_rule(                      // next
     452              :                 squelch( delim_rule(',') ),
     453              :                 token_rule( alpha_chars ) ) ) );
     454              :     @endcode
     455              : 
     456              :     @par BNF
     457              :     @code
     458              :     range       = <1>*<1>first
     459              :                 / first <N-1>*<M-1>next
     460              :     @endcode
     461              : 
     462              :     @par Specification
     463              :     @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
     464              :         >3.6.  Variable Repetition (rfc5234)</a>
     465              : 
     466              :     @param first The rule to use for matching
     467              :     the first element. If this rule returns
     468              :     an error, the range is empty.
     469              : 
     470              :     @param next The rule to use for matching
     471              :     each subsequent element. The range extends
     472              :     until this rule returns an error.
     473              : 
     474              :     @param N The minimum number of elements for
     475              :     the range to be valid. If omitted, this
     476              :     defaults to zero.
     477              : 
     478              :     @param M The maximum number of elements for
     479              :     the range to be valid. If omitted, this
     480              :     defaults to unlimited.
     481              : 
     482              :     @see
     483              :         @ref alpha_chars,
     484              :         @ref delim_rule,
     485              :         @ref error::end_of_range,
     486              :         @ref parse,
     487              :         @ref range,
     488              :         @ref tuple_rule,
     489              :         @ref squelch.
     490              : */
     491              : #ifdef BOOST_URL_DOCS
     492              : template<
     493              :     class Rule1, class Rule2>
     494              : constexpr
     495              : __implementation_defined__
     496              : range_rule(
     497              :     Rule1 first,
     498              :     Rule2 next,
     499              :     std::size_t N = 0,
     500              :     std::size_t M =
     501              :         std::size_t(-1)) noexcept;
     502              : #else
     503              : template<class R0, class R1>
     504              : struct range_rule_t
     505              : {
     506              :     using value_type =
     507              :         range<typename R0::value_type>;
     508              : 
     509              :     system::result<value_type>
     510              :     parse(
     511              :         char const*& it,
     512              :         char const* end) const;
     513              : 
     514              : private:
     515              :     constexpr
     516            1 :     range_rule_t(
     517              :         R0 const& first,
     518              :         R1 const& next,
     519              :         std::size_t N,
     520              :         std::size_t M) noexcept
     521            1 :         : first_(first)
     522            1 :         , next_(next)
     523            1 :         , N_(N)
     524            1 :         , M_(M)
     525              :     {
     526            1 :     }
     527              : 
     528              :     template<
     529              :         class R0_, class R1_>
     530              :     friend
     531              :     constexpr
     532              :     auto
     533              :     range_rule(
     534              :         R0_ const& first,
     535              :         R1_ const& next,
     536              :         std::size_t N,
     537              :         std::size_t M) noexcept ->
     538              : #if 1
     539              :             typename std::enable_if<
     540              :                 ! std::is_integral<R1_>::value,
     541              :                 range_rule_t<R0_, R1_>>::type;
     542              : #else
     543              :         range_rule_t<R0_, R1_>;
     544              : #endif
     545              : 
     546              :     R0 const first_;
     547              :     R1 const next_;
     548              :     std::size_t N_;
     549              :     std::size_t M_;
     550              : };
     551              : 
     552              : template<
     553              :     class Rule1, class Rule2>
     554              : constexpr
     555              : auto
     556            1 : range_rule(
     557              :     Rule1 const& first,
     558              :     Rule2 const& next,
     559              :     std::size_t N = 0,
     560              :     std::size_t M =
     561              :         std::size_t(-1)) noexcept ->
     562              : #if 1
     563              :     typename std::enable_if<
     564              :         ! std::is_integral<Rule2>::value,
     565              :         range_rule_t<Rule1, Rule2>>::type
     566              : #else
     567              :     range_rule_t<Rule1, Rule2>
     568              : #endif
     569              : {
     570              :     // If you get a compile error here it
     571              :     // means that your rule does not meet
     572              :     // the type requirements. Please check
     573              :     // the documentation.
     574              :     static_assert(
     575              :         is_rule<Rule1>::value,
     576              :         "Rule requirements not met");
     577              :     static_assert(
     578              :         is_rule<Rule2>::value,
     579              :         "Rule requirements not met");
     580              : 
     581              :     // If you get a compile error here it
     582              :     // means that your rules do not have
     583              :     // the exact same value_type. Please
     584              :     // check the documentation.
     585              :     static_assert(
     586              :         std::is_same<
     587              :             typename Rule1::value_type,
     588              :             typename Rule2::value_type>::value,
     589              :         "Rule requirements not met");
     590              : 
     591              :     return range_rule_t<Rule1, Rule2>{
     592            1 :         first, next, N, M};
     593              : }
     594              : #endif
     595              : 
     596              : } // grammar
     597              : } // urls
     598              : } // boost
     599              : 
     600              : #include <boost/url/grammar/impl/range_rule.hpp>
     601              : 
     602              : #endif
        

Generated by: LCOV version 2.1