LCOV - code coverage report
Current view: top level - boost/url/grammar - range_rule.hpp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 26 26 100.0 %
Date: 2023-12-15 15:31:48 Functions: 21 21 100.0 %

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

Generated by: LCOV version 1.15