LCOV - code coverage report
Current view: top level - url/grammar - range_rule.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 25 25
Test Date: 2026-02-25 21:00:01 Functions: 100.0 % 11 11

           TLA  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 HIT         711 :         void const* addr() const noexcept
     143                 :         {
     144             711 :             return buf;
     145                 :         }
     146                 : 
     147            2732 :         void* addr() noexcept
     148                 :         {
     149            2732 :             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              29 :     size() const noexcept
     394                 :     {
     395              29 :         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               6 :     string() const noexcept
     404                 :     {
     405               6 :         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                 :     BOOST_URL_CXX20_CONSTEXPR
     428                 :     system::result<value_type>
     429                 :     parse(
     430                 :         char const*& it,
     431                 :         char const* end) const;
     432                 : 
     433                 :     constexpr
     434               1 :     range_rule_t(
     435                 :         R const& next,
     436                 :         std::size_t N,
     437                 :         std::size_t M) noexcept
     438               1 :         : next_(next)
     439               1 :         , N_(N)
     440               1 :         , M_(M)
     441                 :     {
     442               1 :     }
     443                 : 
     444                 : private:
     445                 :     R const next_;
     446                 :     std::size_t N_;
     447                 :     std::size_t M_;
     448                 : };
     449                 : } // implementation_defined
     450                 : 
     451                 : /** Match a repeating number of elements
     452                 : 
     453                 :     Elements are matched using the passed rule.
     454                 :     <br>
     455                 :     Normally when the rule returns an error,
     456                 :     the range ends and the input is rewound to
     457                 :     one past the last character that matched
     458                 :     successfully. However, if the rule returns
     459                 :     the special value @ref error::end_of_range, the
     460                 :     input is not rewound. This allows for rules
     461                 :     which consume input without producing
     462                 :     elements in the range. For example, to
     463                 :     relax the grammar for a comma-delimited
     464                 :     list by allowing extra commas in between
     465                 :     elements.
     466                 : 
     467                 :     @par Value Type
     468                 :     @code
     469                 :     using value_type = range< typename Rule::value_type >;
     470                 :     @endcode
     471                 : 
     472                 :     @par Example
     473                 :     Rules are used with the function @ref parse.
     474                 :     @code
     475                 :     // range    = 1*( ";" token )
     476                 : 
     477                 :     system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
     478                 :         range_rule(
     479                 :             tuple_rule(
     480                 :                 squelch( delim_rule( ';' ) ),
     481                 :                 token_rule( alpha_chars ) ),
     482                 :             1 ) );
     483                 :     @endcode
     484                 : 
     485                 :     @par BNF
     486                 :     @code
     487                 :     range        = <N>*<M>next
     488                 :     @endcode
     489                 : 
     490                 :     @par Specification
     491                 :     @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
     492                 :         >3.6.  Variable Repetition (rfc5234)</a>
     493                 : 
     494                 :     @param next The rule to use for matching
     495                 :     each element. The range extends until this
     496                 :     rule returns an error.
     497                 : 
     498                 :     @param N The minimum number of elements for
     499                 :     the range to be valid. If omitted, this
     500                 :     defaults to zero.
     501                 : 
     502                 :     @param M The maximum number of elements for
     503                 :     the range to be valid. If omitted, this
     504                 :     defaults to unlimited.
     505                 : 
     506                 :     @return A rule that matches the range.
     507                 : 
     508                 :     @see
     509                 :         @ref alpha_chars,
     510                 :         @ref delim_rule,
     511                 :         @ref error::end_of_range,
     512                 :         @ref parse,
     513                 :         @ref range,
     514                 :         @ref tuple_rule,
     515                 :         @ref squelch.
     516                 : */
     517                 : template<BOOST_URL_CONSTRAINT(Rule) R>
     518                 : constexpr
     519                 : implementation_defined::range_rule_t<R>
     520               1 : range_rule(
     521                 :     R const& next,
     522                 :     std::size_t N = 0,
     523                 :     std::size_t M =
     524                 :         std::size_t(-1)) noexcept
     525                 : {
     526                 :     // If you get a compile error here it
     527                 :     // means that your rule does not meet
     528                 :     // the type requirements. Please check
     529                 :     // the documentation.
     530                 :     static_assert(
     531                 :         is_rule<R>::value,
     532                 :         "Rule requirements not met");
     533                 : 
     534                 :     return implementation_defined::range_rule_t<R>{
     535               1 :         next, N, M};
     536                 : }
     537                 : 
     538                 : //------------------------------------------------
     539                 : 
     540                 : namespace implementation_defined {
     541                 : template<class R0, class R1>
     542                 : struct range_rule_t
     543                 : {
     544                 :     using value_type =
     545                 :         range<typename R0::value_type>;
     546                 : 
     547                 :     BOOST_URL_CXX20_CONSTEXPR
     548                 :     system::result<value_type>
     549                 :     parse(
     550                 :         char const*& it,
     551                 :         char const* end) const;
     552                 : 
     553                 :     constexpr
     554               1 :     range_rule_t(
     555                 :         R0 const& first,
     556                 :         R1 const& next,
     557                 :         std::size_t N,
     558                 :         std::size_t M) noexcept
     559               1 :         : first_(first)
     560               1 :         , next_(next)
     561               1 :         , N_(N)
     562               1 :         , M_(M)
     563                 :     {
     564               1 :     }
     565                 : 
     566                 : private:
     567                 :     R0 const first_;
     568                 :     R1 const next_;
     569                 :     std::size_t N_;
     570                 :     std::size_t M_;
     571                 : };
     572                 : } // implementation_defined
     573                 : 
     574                 : /** Match a repeating number of elements
     575                 : 
     576                 :     Two rules are used for match. The rule
     577                 :     `first` is used for matching the first
     578                 :     element, while the `next` rule is used
     579                 :     to match every subsequent element.
     580                 :     <br>
     581                 :     Normally when the rule returns an error,
     582                 :     the range ends and the input is rewound to
     583                 :     one past the last character that matched
     584                 :     successfully. However, if the rule returns
     585                 :     the special value @ref error::end_of_range, the
     586                 :     input is not rewound. This allows for rules
     587                 :     which consume input without producing
     588                 :     elements in the range. For example, to
     589                 :     relax the grammar for a comma-delimited
     590                 :     list by allowing extra commas in between
     591                 :     elements.
     592                 : 
     593                 :     @par Value Type
     594                 :     @code
     595                 :     using value_type = range< typename Rule::value_type >;
     596                 :     @endcode
     597                 : 
     598                 :     @par Example
     599                 :     Rules are used with the function @ref parse.
     600                 :     @code
     601                 :     // range    = [ token ] *( "," token )
     602                 : 
     603                 :     system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
     604                 :         range_rule(
     605                 :             token_rule( alpha_chars ),          // first
     606                 :             tuple_rule(                      // next
     607                 :                 squelch( delim_rule(',') ),
     608                 :                 token_rule( alpha_chars ) ) ) );
     609                 :     @endcode
     610                 : 
     611                 :     @par BNF
     612                 :     @code
     613                 :     range       = <1>*<1>first
     614                 :                 / first <N-1>*<M-1>next
     615                 :     @endcode
     616                 : 
     617                 :     @par Specification
     618                 :     @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
     619                 :         >3.6.  Variable Repetition (rfc5234)</a>
     620                 : 
     621                 :     @param first The rule to use for matching
     622                 :     the first element. If this rule returns
     623                 :     an error, the range is empty.
     624                 : 
     625                 :     @param next The rule to use for matching
     626                 :     each subsequent element. The range extends
     627                 :     until this rule returns an error.
     628                 : 
     629                 :     @param N The minimum number of elements for
     630                 :     the range to be valid. If omitted, this
     631                 :     defaults to zero.
     632                 : 
     633                 :     @param M The maximum number of elements for
     634                 :     the range to be valid. If omitted, this
     635                 :     defaults to unlimited.
     636                 : 
     637                 :     @return A rule that matches the range.
     638                 : 
     639                 :     @see
     640                 :         @ref alpha_chars,
     641                 :         @ref delim_rule,
     642                 :         @ref error::end_of_range,
     643                 :         @ref parse,
     644                 :         @ref range,
     645                 :         @ref tuple_rule,
     646                 :         @ref squelch.
     647                 : */
     648                 : template<
     649                 :     BOOST_URL_CONSTRAINT(Rule) R1,
     650                 :     BOOST_URL_CONSTRAINT(Rule) R2>
     651                 : constexpr
     652                 : auto
     653               1 : range_rule(
     654                 :     R1 const& first,
     655                 :     R2 const& next,
     656                 :     std::size_t N = 0,
     657                 :     std::size_t M =
     658                 :         std::size_t(-1)) noexcept ->
     659                 : #if 1
     660                 :     typename std::enable_if<
     661                 :         ! std::is_integral<R2>::value,
     662                 :         implementation_defined::range_rule_t<R1, R2>>::type
     663                 : #else
     664                 :     range_rule_t<R1, R2>
     665                 : #endif
     666                 : {
     667                 :     // If you get a compile error here it
     668                 :     // means that your rule does not meet
     669                 :     // the type requirements. Please check
     670                 :     // the documentation.
     671                 :     static_assert(
     672                 :         is_rule<R1>::value,
     673                 :         "Rule requirements not met");
     674                 :     static_assert(
     675                 :         is_rule<R2>::value,
     676                 :         "Rule requirements not met");
     677                 : 
     678                 :     // If you get a compile error here it
     679                 :     // means that your rules do not have
     680                 :     // the exact same value_type. Please
     681                 :     // check the documentation.
     682                 :     static_assert(
     683                 :         std::is_same<
     684                 :             typename R1::value_type,
     685                 :             typename R2::value_type>::value,
     686                 :         "Rule requirements not met");
     687                 : 
     688                 :     return implementation_defined::range_rule_t<R1, R2>{
     689               1 :         first, next, N, M};
     690                 : }
     691                 : 
     692                 : } // grammar
     693                 : } // urls
     694                 : } // boost
     695                 : 
     696                 : #include <boost/url/grammar/impl/range_rule.hpp>
     697                 : 
     698                 : #endif
        

Generated by: LCOV version 2.3