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-01-10 18:07:09 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              : #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              :     range&
     225              :     operator=(range&&) noexcept;
     226              : 
     227              :     /** Assignment
     228              : 
     229              :         The copy references the same
     230              :         underlying character buffer.
     231              :         Ownership is not transferred; the
     232              :         caller is responsible for ensuring
     233              :         that the lifetime of the buffer
     234              :         extends until it is no longer
     235              :         referenced.
     236              : 
     237              :         @par Exception Safety
     238              :         Throws nothing.
     239              :     */
     240              :     range&
     241              :     operator=(range const&) noexcept;
     242              : 
     243              :     /** Return an iterator to the beginning
     244              :     */
     245              :     iterator begin() const noexcept;
     246              : 
     247              :     /** Return an iterator to the end
     248              :     */
     249              :     iterator end() const noexcept;
     250              : 
     251              :     /** Return true if the range is empty
     252              :     */
     253              :     bool
     254           11 :     empty() const noexcept
     255              :     {
     256           11 :         return n_ == 0;
     257              :     }
     258              : 
     259              :     /** Return the number of elements in the range
     260              :     */
     261              :     std::size_t
     262           34 :     size() const noexcept
     263              :     {
     264           34 :         return n_;
     265              :     }
     266              : 
     267              :     /** Return the matching part of the string
     268              :     */
     269              :     core::string_view
     270           19 :     string() const noexcept
     271              :     {
     272           19 :         return s_;
     273              :     }
     274              : };
     275              : 
     276              : //------------------------------------------------
     277              : 
     278              : namespace implementation_defined {
     279              : template<
     280              :     class R0,
     281              :     class R1 = void>
     282              : struct range_rule_t;
     283              : }
     284              : 
     285              : //------------------------------------------------
     286              : 
     287              : namespace implementation_defined {
     288              : template<class R>
     289              : struct range_rule_t<R>
     290              : {
     291              :     using value_type =
     292              :         range<typename R::value_type>;
     293              : 
     294              :     system::result<value_type>
     295              :     parse(
     296              :         char const*& it,
     297              :         char const* end) const;
     298              : 
     299              :     constexpr
     300           18 :     range_rule_t(
     301              :         R const& next,
     302              :         std::size_t N,
     303              :         std::size_t M) noexcept
     304           18 :         : next_(next)
     305           18 :         , N_(N)
     306           18 :         , M_(M)
     307              :     {
     308           18 :     }
     309              : 
     310              : private:
     311              :     R const next_;
     312              :     std::size_t N_;
     313              :     std::size_t M_;
     314              : };
     315              : } // implementation_defined
     316              : 
     317              : /** Match a repeating number of elements
     318              : 
     319              :     Elements are matched using the passed rule.
     320              :     <br>
     321              :     Normally when the rule returns an error,
     322              :     the range ends and the input is rewound to
     323              :     one past the last character that matched
     324              :     successfully. However, if the rule returns
     325              :     the special value @ref error::end_of_range, the
     326              :     input is not rewound. This allows for rules
     327              :     which consume input without producing
     328              :     elements in the range. For example, to
     329              :     relax the grammar for a comma-delimited
     330              :     list by allowing extra commas in between
     331              :     elements.
     332              : 
     333              :     @par Value Type
     334              :     @code
     335              :     using value_type = range< typename Rule::value_type >;
     336              :     @endcode
     337              : 
     338              :     @par Example
     339              :     Rules are used with the function @ref parse.
     340              :     @code
     341              :     // range    = 1*( ";" token )
     342              : 
     343              :     system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
     344              :         range_rule(
     345              :             tuple_rule(
     346              :                 squelch( delim_rule( ';' ) ),
     347              :                 token_rule( alpha_chars ) ),
     348              :             1 ) );
     349              :     @endcode
     350              : 
     351              :     @par BNF
     352              :     @code
     353              :     range        = <N>*<M>next
     354              :     @endcode
     355              : 
     356              :     @par Specification
     357              :     @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
     358              :         >3.6.  Variable Repetition (rfc5234)</a>
     359              : 
     360              :     @param next The rule to use for matching
     361              :     each element. The range extends until this
     362              :     rule returns an error.
     363              : 
     364              :     @param N The minimum number of elements for
     365              :     the range to be valid. If omitted, this
     366              :     defaults to zero.
     367              : 
     368              :     @param M The maximum number of elements for
     369              :     the range to be valid. If omitted, this
     370              :     defaults to unlimited.
     371              : 
     372              :     @see
     373              :         @ref alpha_chars,
     374              :         @ref delim_rule,
     375              :         @ref error::end_of_range,
     376              :         @ref parse,
     377              :         @ref range,
     378              :         @ref tuple_rule,
     379              :         @ref squelch.
     380              : */
     381              : template<BOOST_URL_CONSTRAINT(Rule) R>
     382              : constexpr
     383              : implementation_defined::range_rule_t<R>
     384           18 : range_rule(
     385              :     R const& next,
     386              :     std::size_t N = 0,
     387              :     std::size_t M =
     388              :         std::size_t(-1)) noexcept
     389              : {
     390              :     // If you get a compile error here it
     391              :     // means that your rule does not meet
     392              :     // the type requirements. Please check
     393              :     // the documentation.
     394              :     static_assert(
     395              :         is_rule<R>::value,
     396              :         "Rule requirements not met");
     397              : 
     398              :     return implementation_defined::range_rule_t<R>{
     399           18 :         next, N, M};
     400              : }
     401              : 
     402              : //------------------------------------------------
     403              : 
     404              : namespace implementation_defined {
     405              : template<class R0, class R1>
     406              : struct range_rule_t
     407              : {
     408              :     using value_type =
     409              :         range<typename R0::value_type>;
     410              : 
     411              :     system::result<value_type>
     412              :     parse(
     413              :         char const*& it,
     414              :         char const* end) const;
     415              : 
     416              :     constexpr
     417            1 :     range_rule_t(
     418              :         R0 const& first,
     419              :         R1 const& next,
     420              :         std::size_t N,
     421              :         std::size_t M) noexcept
     422            1 :         : first_(first)
     423            1 :         , next_(next)
     424            1 :         , N_(N)
     425            1 :         , M_(M)
     426              :     {
     427            1 :     }
     428              : 
     429              : private:
     430              :     R0 const first_;
     431              :     R1 const next_;
     432              :     std::size_t N_;
     433              :     std::size_t M_;
     434              : };
     435              : } // implementation_defined
     436              : 
     437              : /** Match a repeating number of elements
     438              : 
     439              :     Two rules are used for match. The rule
     440              :     `first` is used for matching the first
     441              :     element, while the `next` rule is used
     442              :     to match every subsequent element.
     443              :     <br>
     444              :     Normally when the rule returns an error,
     445              :     the range ends and the input is rewound to
     446              :     one past the last character that matched
     447              :     successfully. However, if the rule returns
     448              :     the special value @ref error::end_of_range, the
     449              :     input is not rewound. This allows for rules
     450              :     which consume input without producing
     451              :     elements in the range. For example, to
     452              :     relax the grammar for a comma-delimited
     453              :     list by allowing extra commas in between
     454              :     elements.
     455              : 
     456              :     @par Value Type
     457              :     @code
     458              :     using value_type = range< typename Rule::value_type >;
     459              :     @endcode
     460              : 
     461              :     @par Example
     462              :     Rules are used with the function @ref parse.
     463              :     @code
     464              :     // range    = [ token ] *( "," token )
     465              : 
     466              :     system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
     467              :         range_rule(
     468              :             token_rule( alpha_chars ),          // first
     469              :             tuple_rule(                      // next
     470              :                 squelch( delim_rule(',') ),
     471              :                 token_rule( alpha_chars ) ) ) );
     472              :     @endcode
     473              : 
     474              :     @par BNF
     475              :     @code
     476              :     range       = <1>*<1>first
     477              :                 / first <N-1>*<M-1>next
     478              :     @endcode
     479              : 
     480              :     @par Specification
     481              :     @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
     482              :         >3.6.  Variable Repetition (rfc5234)</a>
     483              : 
     484              :     @param first The rule to use for matching
     485              :     the first element. If this rule returns
     486              :     an error, the range is empty.
     487              : 
     488              :     @param next The rule to use for matching
     489              :     each subsequent element. The range extends
     490              :     until this rule returns an error.
     491              : 
     492              :     @param N The minimum number of elements for
     493              :     the range to be valid. If omitted, this
     494              :     defaults to zero.
     495              : 
     496              :     @param M The maximum number of elements for
     497              :     the range to be valid. If omitted, this
     498              :     defaults to unlimited.
     499              : 
     500              :     @see
     501              :         @ref alpha_chars,
     502              :         @ref delim_rule,
     503              :         @ref error::end_of_range,
     504              :         @ref parse,
     505              :         @ref range,
     506              :         @ref tuple_rule,
     507              :         @ref squelch.
     508              : */
     509              : template<
     510              :     BOOST_URL_CONSTRAINT(Rule) R1,
     511              :     BOOST_URL_CONSTRAINT(Rule) R2>
     512              : constexpr
     513              : auto
     514            1 : range_rule(
     515              :     R1 const& first,
     516              :     R2 const& next,
     517              :     std::size_t N = 0,
     518              :     std::size_t M =
     519              :         std::size_t(-1)) noexcept ->
     520              : #if 1
     521              :     typename std::enable_if<
     522              :         ! std::is_integral<R2>::value,
     523              :         implementation_defined::range_rule_t<R1, R2>>::type
     524              : #else
     525              :     range_rule_t<R1, R2>
     526              : #endif
     527              : {
     528              :     // If you get a compile error here it
     529              :     // means that your rule does not meet
     530              :     // the type requirements. Please check
     531              :     // the documentation.
     532              :     static_assert(
     533              :         is_rule<R1>::value,
     534              :         "Rule requirements not met");
     535              :     static_assert(
     536              :         is_rule<R2>::value,
     537              :         "Rule requirements not met");
     538              : 
     539              :     // If you get a compile error here it
     540              :     // means that your rules do not have
     541              :     // the exact same value_type. Please
     542              :     // check the documentation.
     543              :     static_assert(
     544              :         std::is_same<
     545              :             typename R1::value_type,
     546              :             typename R2::value_type>::value,
     547              :         "Rule requirements not met");
     548              : 
     549              :     return implementation_defined::range_rule_t<R1, R2>{
     550            1 :         first, next, N, M};
     551              : }
     552              : 
     553              : } // grammar
     554              : } // urls
     555              : } // boost
     556              : 
     557              : #include <boost/url/grammar/impl/range_rule.hpp>
     558              : 
     559              : #endif
        

Generated by: LCOV version 2.1