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

Generated by: LCOV version 2.1