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-09-08 09:46:47 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              : #ifndef BOOST_URL_DOCS
     279              : namespace implementation_defined {
     280              : template<
     281              :     class R0,
     282              :     class R1 = void>
     283              : struct range_rule_t;
     284              : }
     285              : #endif
     286              : 
     287              : //------------------------------------------------
     288              : 
     289              : /** Match a repeating number of elements
     290              : 
     291              :     Elements are matched using the passed rule.
     292              :     <br>
     293              :     Normally when the rule returns an error,
     294              :     the range ends and the input is rewound to
     295              :     one past the last character that matched
     296              :     successfully. However, if the rule returns
     297              :     the special value @ref error::end_of_range, the
     298              :     input is not rewound. This allows for rules
     299              :     which consume input without producing
     300              :     elements in the range. For example, to
     301              :     relax the grammar for a comma-delimited
     302              :     list by allowing extra commas in between
     303              :     elements.
     304              : 
     305              :     @par Value Type
     306              :     @code
     307              :     using value_type = range< typename Rule::value_type >;
     308              :     @endcode
     309              : 
     310              :     @par Example
     311              :     Rules are used with the function @ref parse.
     312              :     @code
     313              :     // range    = 1*( ";" token )
     314              : 
     315              :     system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
     316              :         range_rule(
     317              :             tuple_rule(
     318              :                 squelch( delim_rule( ';' ) ),
     319              :                 token_rule( alpha_chars ) ),
     320              :             1 ) );
     321              :     @endcode
     322              : 
     323              :     @par BNF
     324              :     @code
     325              :     range        = <N>*<M>next
     326              :     @endcode
     327              : 
     328              :     @par Specification
     329              :     @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
     330              :         >3.6.  Variable Repetition (rfc5234)</a>
     331              : 
     332              :     @param next The rule to use for matching
     333              :     each element. The range extends until this
     334              :     rule returns an error.
     335              : 
     336              :     @param N The minimum number of elements for
     337              :     the range to be valid. If omitted, this
     338              :     defaults to zero.
     339              : 
     340              :     @param M The maximum number of elements for
     341              :     the range to be valid. If omitted, this
     342              :     defaults to unlimited.
     343              : 
     344              :     @see
     345              :         @ref alpha_chars,
     346              :         @ref delim_rule,
     347              :         @ref error::end_of_range,
     348              :         @ref parse,
     349              :         @ref range,
     350              :         @ref tuple_rule,
     351              :         @ref squelch.
     352              : */
     353              : #ifdef BOOST_URL_DOCS
     354              : template<class Rule>
     355              : constexpr
     356              : __implementation_defined__
     357              : range_rule(
     358              :     Rule next,
     359              :     std::size_t N = 0,
     360              :     std::size_t M =
     361              :         std::size_t(-1)) noexcept;
     362              : #else
     363              : namespace implementation_defined {
     364              : template<class R>
     365              : struct range_rule_t<R>
     366              : {
     367              :     using value_type =
     368              :         range<typename R::value_type>;
     369              : 
     370              :     system::result<value_type>
     371              :     parse(
     372              :         char const*& it,
     373              :         char const* end) const;
     374              : 
     375              :     constexpr
     376           18 :     range_rule_t(
     377              :         R const& next,
     378              :         std::size_t N,
     379              :         std::size_t M) noexcept
     380           18 :         : next_(next)
     381           18 :         , N_(N)
     382           18 :         , M_(M)
     383              :     {
     384           18 :     }
     385              : 
     386              : private:
     387              :     R const next_;
     388              :     std::size_t N_;
     389              :     std::size_t M_;
     390              : };
     391              : } // implementation_defined
     392              : 
     393              : /** Match a repeating number of elements
     394              : 
     395              :     Elements are matched using the passed rule.
     396              :     <br>
     397              :     Normally when the rule returns an error,
     398              :     the range ends and the input is rewound to
     399              :     one past the last character that matched
     400              :     successfully. However, if the rule returns
     401              :     the special value @ref error::end_of_range, the
     402              :     input is not rewound. This allows for rules
     403              :     which consume input without producing
     404              :     elements in the range. For example, to
     405              :     relax the grammar for a comma-delimited
     406              :     list by allowing extra commas in between
     407              :     elements.
     408              : 
     409              :     @par Value Type
     410              :     @code
     411              :     using value_type = range< typename Rule::value_type >;
     412              :     @endcode
     413              : 
     414              :     @par Example
     415              :     Rules are used with the function @ref parse.
     416              :     @code
     417              :     // range    = 1*( ";" token )
     418              : 
     419              :     system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
     420              :         range_rule(
     421              :             tuple_rule(
     422              :                 squelch( delim_rule( ';' ) ),
     423              :                 token_rule( alpha_chars ) ),
     424              :             1 ) );
     425              :     @endcode
     426              : 
     427              :     @par BNF
     428              :     @code
     429              :     range        = <N>*<M>next
     430              :     @endcode
     431              : 
     432              :     @par Specification
     433              :     @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
     434              :         >3.6.  Variable Repetition (rfc5234)</a>
     435              : 
     436              :     @param next The rule to use for matching
     437              :     each element. The range extends until this
     438              :     rule returns an error.
     439              : 
     440              :     @param N The minimum number of elements for
     441              :     the range to be valid. If omitted, this
     442              :     defaults to zero.
     443              : 
     444              :     @param M The maximum number of elements for
     445              :     the range to be valid. If omitted, this
     446              :     defaults to unlimited.
     447              : 
     448              :     @see
     449              :         @ref alpha_chars,
     450              :         @ref delim_rule,
     451              :         @ref error::end_of_range,
     452              :         @ref parse,
     453              :         @ref range,
     454              :         @ref tuple_rule,
     455              :         @ref squelch.
     456              : */
     457              : template<class Rule>
     458              : constexpr
     459              : implementation_defined::range_rule_t<Rule>
     460           18 : range_rule(
     461              :     Rule const& next,
     462              :     std::size_t N = 0,
     463              :     std::size_t M =
     464              :         std::size_t(-1)) noexcept
     465              : {
     466              :     // If you get a compile error here it
     467              :     // means that your rule does not meet
     468              :     // the type requirements. Please check
     469              :     // the documentation.
     470              :     static_assert(
     471              :         is_rule<Rule>::value,
     472              :         "Rule requirements not met");
     473              : 
     474              :     return implementation_defined::range_rule_t<Rule>{
     475           18 :         next, N, M};
     476              : }
     477              : #endif
     478              : 
     479              : //------------------------------------------------
     480              : 
     481              : /** Match a repeating number of elements
     482              : 
     483              :     Two rules are used for match. The rule
     484              :     `first` is used for matching the first
     485              :     element, while the `next` rule is used
     486              :     to match every subsequent element.
     487              :     <br>
     488              :     Normally when the rule returns an error,
     489              :     the range ends and the input is rewound to
     490              :     one past the last character that matched
     491              :     successfully. However, if the rule returns
     492              :     the special value @ref error::end_of_range, the
     493              :     input is not rewound. This allows for rules
     494              :     which consume input without producing
     495              :     elements in the range. For example, to
     496              :     relax the grammar for a comma-delimited
     497              :     list by allowing extra commas in between
     498              :     elements.
     499              : 
     500              :     @par Value Type
     501              :     @code
     502              :     using value_type = range< typename Rule::value_type >;
     503              :     @endcode
     504              : 
     505              :     @par Example
     506              :     Rules are used with the function @ref parse.
     507              :     @code
     508              :     // range    = [ token ] *( "," token )
     509              : 
     510              :     system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
     511              :         range_rule(
     512              :             token_rule( alpha_chars ),          // first
     513              :             tuple_rule(                      // next
     514              :                 squelch( delim_rule(',') ),
     515              :                 token_rule( alpha_chars ) ) ) );
     516              :     @endcode
     517              : 
     518              :     @par BNF
     519              :     @code
     520              :     range       = <1>*<1>first
     521              :                 / first <N-1>*<M-1>next
     522              :     @endcode
     523              : 
     524              :     @par Specification
     525              :     @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
     526              :         >3.6.  Variable Repetition (rfc5234)</a>
     527              : 
     528              :     @param first The rule to use for matching
     529              :     the first element. If this rule returns
     530              :     an error, the range is empty.
     531              : 
     532              :     @param next The rule to use for matching
     533              :     each subsequent element. The range extends
     534              :     until this rule returns an error.
     535              : 
     536              :     @param N The minimum number of elements for
     537              :     the range to be valid. If omitted, this
     538              :     defaults to zero.
     539              : 
     540              :     @param M The maximum number of elements for
     541              :     the range to be valid. If omitted, this
     542              :     defaults to unlimited.
     543              : 
     544              :     @see
     545              :         @ref alpha_chars,
     546              :         @ref delim_rule,
     547              :         @ref error::end_of_range,
     548              :         @ref parse,
     549              :         @ref range,
     550              :         @ref tuple_rule,
     551              :         @ref squelch.
     552              : */
     553              : #ifdef BOOST_URL_DOCS
     554              : template<
     555              :     class Rule1, class Rule2>
     556              : constexpr
     557              : __implementation_defined__
     558              : range_rule(
     559              :     Rule1 first,
     560              :     Rule2 next,
     561              :     std::size_t N = 0,
     562              :     std::size_t M =
     563              :         std::size_t(-1)) noexcept;
     564              : #else
     565              : namespace implementation_defined {
     566              : template<class R0, class R1>
     567              : struct range_rule_t
     568              : {
     569              :     using value_type =
     570              :         range<typename R0::value_type>;
     571              : 
     572              :     system::result<value_type>
     573              :     parse(
     574              :         char const*& it,
     575              :         char const* end) const;
     576              : 
     577              :     constexpr
     578            1 :     range_rule_t(
     579              :         R0 const& first,
     580              :         R1 const& next,
     581              :         std::size_t N,
     582              :         std::size_t M) noexcept
     583            1 :         : first_(first)
     584            1 :         , next_(next)
     585            1 :         , N_(N)
     586            1 :         , M_(M)
     587              :     {
     588            1 :     }
     589              : 
     590              : private:
     591              :     R0 const first_;
     592              :     R1 const next_;
     593              :     std::size_t N_;
     594              :     std::size_t M_;
     595              : };
     596              : } // implementation_defined
     597              : 
     598              : /** Match a repeating number of elements
     599              : 
     600              :     Two rules are used for match. The rule
     601              :     `first` is used for matching the first
     602              :     element, while the `next` rule is used
     603              :     to match every subsequent element.
     604              :     <br>
     605              :     Normally when the rule returns an error,
     606              :     the range ends and the input is rewound to
     607              :     one past the last character that matched
     608              :     successfully. However, if the rule returns
     609              :     the special value @ref error::end_of_range, the
     610              :     input is not rewound. This allows for rules
     611              :     which consume input without producing
     612              :     elements in the range. For example, to
     613              :     relax the grammar for a comma-delimited
     614              :     list by allowing extra commas in between
     615              :     elements.
     616              : 
     617              :     @par Value Type
     618              :     @code
     619              :     using value_type = range< typename Rule::value_type >;
     620              :     @endcode
     621              : 
     622              :     @par Example
     623              :     Rules are used with the function @ref parse.
     624              :     @code
     625              :     // range    = [ token ] *( "," token )
     626              : 
     627              :     system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
     628              :         range_rule(
     629              :             token_rule( alpha_chars ),          // first
     630              :             tuple_rule(                      // next
     631              :                 squelch( delim_rule(',') ),
     632              :                 token_rule( alpha_chars ) ) ) );
     633              :     @endcode
     634              : 
     635              :     @par BNF
     636              :     @code
     637              :     range       = <1>*<1>first
     638              :                 / first <N-1>*<M-1>next
     639              :     @endcode
     640              : 
     641              :     @par Specification
     642              :     @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
     643              :         >3.6.  Variable Repetition (rfc5234)</a>
     644              : 
     645              :     @param first The rule to use for matching
     646              :     the first element. If this rule returns
     647              :     an error, the range is empty.
     648              : 
     649              :     @param next The rule to use for matching
     650              :     each subsequent element. The range extends
     651              :     until this rule returns an error.
     652              : 
     653              :     @param N The minimum number of elements for
     654              :     the range to be valid. If omitted, this
     655              :     defaults to zero.
     656              : 
     657              :     @param M The maximum number of elements for
     658              :     the range to be valid. If omitted, this
     659              :     defaults to unlimited.
     660              : 
     661              :     @see
     662              :         @ref alpha_chars,
     663              :         @ref delim_rule,
     664              :         @ref error::end_of_range,
     665              :         @ref parse,
     666              :         @ref range,
     667              :         @ref tuple_rule,
     668              :         @ref squelch.
     669              : */
     670              : template<
     671              :     class Rule1, class Rule2>
     672              : constexpr
     673              : auto
     674            1 : range_rule(
     675              :     Rule1 const& first,
     676              :     Rule2 const& next,
     677              :     std::size_t N = 0,
     678              :     std::size_t M =
     679              :         std::size_t(-1)) noexcept ->
     680              : #if 1
     681              :     typename std::enable_if<
     682              :         ! std::is_integral<Rule2>::value,
     683              :         implementation_defined::range_rule_t<Rule1, Rule2>>::type
     684              : #else
     685              :     range_rule_t<Rule1, Rule2>
     686              : #endif
     687              : {
     688              :     // If you get a compile error here it
     689              :     // means that your rule does not meet
     690              :     // the type requirements. Please check
     691              :     // the documentation.
     692              :     static_assert(
     693              :         is_rule<Rule1>::value,
     694              :         "Rule requirements not met");
     695              :     static_assert(
     696              :         is_rule<Rule2>::value,
     697              :         "Rule requirements not met");
     698              : 
     699              :     // If you get a compile error here it
     700              :     // means that your rules do not have
     701              :     // the exact same value_type. Please
     702              :     // check the documentation.
     703              :     static_assert(
     704              :         std::is_same<
     705              :             typename Rule1::value_type,
     706              :             typename Rule2::value_type>::value,
     707              :         "Rule requirements not met");
     708              : 
     709              :     return implementation_defined::range_rule_t<Rule1, Rule2>{
     710            1 :         first, next, N, M};
     711              : }
     712              : #endif
     713              : 
     714              : } // grammar
     715              : } // urls
     716              : } // boost
     717              : 
     718              : #include <boost/url/grammar/impl/range_rule.hpp>
     719              : 
     720              : #endif
        

Generated by: LCOV version 2.1