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 % 25 25
Test Date: 2025-11-10 19:06:20 Functions: 100.0 % 16 16

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

Generated by: LCOV version 2.1