Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:53:27

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/url
0008 //
0009 
0010 #ifndef BOOST_URL_GRAMMAR_RANGE_RULE_HPP
0011 #define BOOST_URL_GRAMMAR_RANGE_RULE_HPP
0012 
0013 #include <boost/url/detail/config.hpp>
0014 #include <boost/url/error.hpp>
0015 #include <boost/core/detail/string_view.hpp>
0016 #include <boost/url/grammar/parse.hpp>
0017 #include <boost/url/grammar/type_traits.hpp>
0018 #include <boost/static_assert.hpp>
0019 #include <cstddef>
0020 #include <iterator>
0021 #include <type_traits>
0022 
0023 #include <stddef.h> // ::max_align_t
0024 
0025 namespace boost {
0026 namespace urls {
0027 namespace grammar {
0028 
0029 /** A forward range of parsed elements
0030 
0031     Objects of this type are forward ranges
0032     returned when parsing using the
0033     @ref range_rule.
0034     Iteration is performed by re-parsing the
0035     underlying character buffer. Ownership
0036     of the buffer is not transferred; the
0037     caller is responsible for ensuring that
0038     the lifetime of the buffer extends until
0039     it is no longer referenced by the range.
0040 
0041     @note
0042 
0043     The implementation may use temporary,
0044     recycled storage for type-erasure. Objects
0045     of type `range` are intended to be used
0046     ephemerally. That is, for short durations
0047     such as within a function scope. If it is
0048     necessary to store the range for a long
0049     period of time or with static storage
0050     duration, it is necessary to copy the
0051     contents to an object of a different type.
0052 
0053     @tparam T The value type of the range
0054 
0055     @see
0056         @ref parse,
0057         @ref range_rule.
0058 */
0059 template<class T>
0060 class range
0061 {
0062     // buffer size for type-erased rule
0063     static constexpr
0064         std::size_t BufferSize = 128;
0065 
0066     struct small_buffer
0067     {
0068         alignas(alignof(::max_align_t))
0069         unsigned char buf[BufferSize];
0070 
0071         void const* addr() const noexcept
0072         {
0073             return buf;
0074         }
0075 
0076         void* addr() noexcept
0077         {
0078             return buf;
0079         }
0080     };
0081 
0082     small_buffer sb_;
0083     core::string_view s_;
0084     std::size_t n_ = 0;
0085 
0086     //--------------------------------------------
0087 
0088     struct any_rule;
0089 
0090     template<class R, bool>
0091     struct impl1;
0092 
0093     template<
0094         class R0, class R1, bool>
0095     struct impl2;
0096 
0097     template<
0098         class R0, class R1>
0099     friend struct range_rule_t;
0100 
0101     any_rule&
0102     get() noexcept
0103     {
0104         return *reinterpret_cast<
0105             any_rule*>(sb_.addr());
0106     }
0107 
0108     any_rule const&
0109     get() const noexcept
0110     {
0111         return *reinterpret_cast<
0112             any_rule const*>(
0113                 sb_.addr());
0114     }
0115 
0116     template<class R>
0117     range(
0118         core::string_view s,
0119         std::size_t n,
0120         R const& r);
0121 
0122     template<
0123         class R0, class R1>
0124     range(
0125         core::string_view s,
0126         std::size_t n,
0127         R0 const& first,
0128         R1 const& next);
0129 
0130 public:
0131     /** The type of each element of the range
0132     */
0133     using value_type = T;
0134 
0135     /** The type of each element of the range
0136     */
0137     using reference = T const&;
0138 
0139     /** The type of each element of the range
0140     */
0141     using const_reference = T const&;
0142 
0143     /** Provided for compatibility, unused
0144     */
0145     using pointer = void const*;
0146 
0147     /** The type used to represent unsigned integers
0148     */
0149     using size_type = std::size_t;
0150 
0151     /** The type used to represent signed integers
0152     */
0153     using difference_type = std::ptrdiff_t;
0154 
0155     /** A constant, forward iterator to elements of the range
0156     */
0157     class iterator;
0158 
0159     /** A constant, forward iterator to elements of the range
0160     */
0161     using const_iterator = iterator;
0162 
0163     /** Destructor
0164     */
0165     ~range();
0166 
0167     /** Constructor
0168 
0169         Default-constructed ranges have
0170         zero elements.
0171 
0172         @par Exception Safety
0173         Throws nothing.
0174     */
0175     range() noexcept;
0176 
0177     /** Constructor
0178 
0179         The new range references the
0180         same underlying character buffer.
0181         Ownership is not transferred; the
0182         caller is responsible for ensuring
0183         that the lifetime of the buffer
0184         extends until it is no longer
0185         referenced. The moved-from object
0186         becomes as if default-constructed.
0187 
0188         @par Exception Safety
0189         Throws nothing.
0190     */
0191     range(range&&) noexcept;
0192 
0193     /** Constructor
0194 
0195         The copy references the same
0196         underlying character buffer.
0197         Ownership is not transferred; the
0198         caller is responsible for ensuring
0199         that the lifetime of the buffer
0200         extends until it is no longer
0201         referenced.
0202 
0203         @par Exception Safety
0204         Throws nothing.
0205     */
0206     range(range const&) noexcept;
0207 
0208     /** Constructor
0209 
0210         After the move, this references the
0211         same underlying character buffer. Ownership
0212         is not transferred; the caller is responsible
0213         for ensuring that the lifetime of the buffer
0214         extends until it is no longer referenced.
0215         The moved-from object becomes as if
0216         default-constructed.
0217 
0218         @par Exception Safety
0219         Throws nothing.
0220     */
0221     range&
0222     operator=(range&&) noexcept;
0223 
0224     /** Assignment
0225 
0226         The copy references the same
0227         underlying character buffer.
0228         Ownership is not transferred; the
0229         caller is responsible for ensuring
0230         that the lifetime of the buffer
0231         extends until it is no longer
0232         referenced.
0233 
0234         @par Exception Safety
0235         Throws nothing.
0236     */
0237     range&
0238     operator=(range const&) noexcept;
0239 
0240     /** Return an iterator to the beginning
0241     */
0242     iterator begin() const noexcept;
0243 
0244     /** Return an iterator to the end
0245     */
0246     iterator end() const noexcept;
0247 
0248     /** Return true if the range is empty
0249     */
0250     bool
0251     empty() const noexcept
0252     {
0253         return n_ == 0;
0254     }
0255 
0256     /** Return the number of elements in the range
0257     */
0258     std::size_t
0259     size() const noexcept
0260     {
0261         return n_;
0262     }
0263 
0264     /** Return the matching part of the string
0265     */
0266     core::string_view
0267     string() const noexcept
0268     {
0269         return s_;
0270     }
0271 };
0272 
0273 //------------------------------------------------
0274 
0275 #ifndef BOOST_URL_DOCS
0276 template<
0277     class R0,
0278     class R1 = void>
0279 struct range_rule_t;
0280 #endif
0281 
0282 //------------------------------------------------
0283 
0284 /** Match a repeating number of elements
0285 
0286     Elements are matched using the passed rule.
0287     <br>
0288     Normally when the rule returns an error,
0289     the range ends and the input is rewound to
0290     one past the last character that matched
0291     successfully. However, if the rule returns
0292     the special value @ref error::end_of_range, the
0293     input is not rewound. This allows for rules
0294     which consume input without producing
0295     elements in the range. For example, to
0296     relax the grammar for a comma-delimited
0297     list by allowing extra commas in between
0298     elements.
0299 
0300     @par Value Type
0301     @code
0302     using value_type = range< typename Rule::value_type >;
0303     @endcode
0304 
0305     @par Example
0306     Rules are used with the function @ref parse.
0307     @code
0308     // range    = 1*( ";" token )
0309 
0310     system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
0311         range_rule(
0312             tuple_rule(
0313                 squelch( delim_rule( ';' ) ),
0314                 token_rule( alpha_chars ) ),
0315             1 ) );
0316     @endcode
0317 
0318     @par BNF
0319     @code
0320     range        = <N>*<M>next
0321     @endcode
0322 
0323     @par Specification
0324     @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
0325         >3.6.  Variable Repetition (rfc5234)</a>
0326 
0327     @param next The rule to use for matching
0328     each element. The range extends until this
0329     rule returns an error.
0330 
0331     @param N The minimum number of elements for
0332     the range to be valid. If omitted, this
0333     defaults to zero.
0334 
0335     @param M The maximum number of elements for
0336     the range to be valid. If omitted, this
0337     defaults to unlimited.
0338 
0339     @see
0340         @ref alpha_chars,
0341         @ref delim_rule,
0342         @ref error::end_of_range,
0343         @ref parse,
0344         @ref range,
0345         @ref tuple_rule,
0346         @ref squelch.
0347 */
0348 #ifdef BOOST_URL_DOCS
0349 template<class Rule>
0350 constexpr
0351 __implementation_defined__
0352 range_rule(
0353     Rule next,
0354     std::size_t N = 0,
0355     std::size_t M =
0356         std::size_t(-1)) noexcept;
0357 #else
0358 template<class R>
0359 struct range_rule_t<R>
0360 {
0361     using value_type =
0362         range<typename R::value_type>;
0363 
0364     system::result<value_type>
0365     parse(
0366         char const*& it,
0367         char const* end) const;
0368 
0369 private:
0370     constexpr
0371     range_rule_t(
0372         R const& next,
0373         std::size_t N,
0374         std::size_t M) noexcept
0375         : next_(next)
0376         , N_(N)
0377         , M_(M)
0378     {
0379     }
0380 
0381     template<class R_>
0382     friend
0383     constexpr
0384     range_rule_t<R_>
0385     range_rule(
0386         R_ const& next,
0387         std::size_t N,
0388         std::size_t M) noexcept;
0389 
0390     R const next_;
0391     std::size_t N_;
0392     std::size_t M_;
0393 };
0394 
0395 template<class Rule>
0396 constexpr
0397 range_rule_t<Rule>
0398 range_rule(
0399     Rule const& next,
0400     std::size_t N = 0,
0401     std::size_t M =
0402         std::size_t(-1)) noexcept
0403 {
0404     // If you get a compile error here it
0405     // means that your rule does not meet
0406     // the type requirements. Please check
0407     // the documentation.
0408     static_assert(
0409         is_rule<Rule>::value,
0410         "Rule requirements not met");
0411 
0412     return range_rule_t<Rule>{
0413         next, N, M};
0414 }
0415 #endif
0416 
0417 //------------------------------------------------
0418 
0419 /** Match a repeating number of elements
0420 
0421     Two rules are used for match. The rule
0422     `first` is used for matching the first
0423     element, while the `next` rule is used
0424     to match every subsequent element.
0425     <br>
0426     Normally when the rule returns an error,
0427     the range ends and the input is rewound to
0428     one past the last character that matched
0429     successfully. However, if the rule returns
0430     the special value @ref error::end_of_range, the
0431     input is not rewound. This allows for rules
0432     which consume input without producing
0433     elements in the range. For example, to
0434     relax the grammar for a comma-delimited
0435     list by allowing extra commas in between
0436     elements.
0437 
0438     @par Value Type
0439     @code
0440     using value_type = range< typename Rule::value_type >;
0441     @endcode
0442 
0443     @par Example
0444     Rules are used with the function @ref parse.
0445     @code
0446     // range    = [ token ] *( "," token )
0447 
0448     system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
0449         range_rule(
0450             token_rule( alpha_chars ),          // first
0451             tuple_rule(                      // next
0452                 squelch( delim_rule(',') ),
0453                 token_rule( alpha_chars ) ) ) );
0454     @endcode
0455 
0456     @par BNF
0457     @code
0458     range       = <1>*<1>first
0459                 / first <N-1>*<M-1>next
0460     @endcode
0461 
0462     @par Specification
0463     @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
0464         >3.6.  Variable Repetition (rfc5234)</a>
0465 
0466     @param first The rule to use for matching
0467     the first element. If this rule returns
0468     an error, the range is empty.
0469 
0470     @param next The rule to use for matching
0471     each subsequent element. The range extends
0472     until this rule returns an error.
0473 
0474     @param N The minimum number of elements for
0475     the range to be valid. If omitted, this
0476     defaults to zero.
0477 
0478     @param M The maximum number of elements for
0479     the range to be valid. If omitted, this
0480     defaults to unlimited.
0481 
0482     @see
0483         @ref alpha_chars,
0484         @ref delim_rule,
0485         @ref error::end_of_range,
0486         @ref parse,
0487         @ref range,
0488         @ref tuple_rule,
0489         @ref squelch.
0490 */
0491 #ifdef BOOST_URL_DOCS
0492 template<
0493     class Rule1, class Rule2>
0494 constexpr
0495 __implementation_defined__
0496 range_rule(
0497     Rule1 first,
0498     Rule2 next,
0499     std::size_t N = 0,
0500     std::size_t M =
0501         std::size_t(-1)) noexcept;
0502 #else
0503 template<class R0, class R1>
0504 struct range_rule_t
0505 {
0506     using value_type =
0507         range<typename R0::value_type>;
0508 
0509     system::result<value_type>
0510     parse(
0511         char const*& it,
0512         char const* end) const;
0513 
0514 private:
0515     constexpr
0516     range_rule_t(
0517         R0 const& first,
0518         R1 const& next,
0519         std::size_t N,
0520         std::size_t M) noexcept
0521         : first_(first)
0522         , next_(next)
0523         , N_(N)
0524         , M_(M)
0525     {
0526     }
0527 
0528     template<
0529         class R0_, class R1_>
0530     friend
0531     constexpr
0532     auto
0533     range_rule(
0534         R0_ const& first,
0535         R1_ const& next,
0536         std::size_t N,
0537         std::size_t M) noexcept ->
0538 #if 1
0539             typename std::enable_if<
0540                 ! std::is_integral<R1_>::value,
0541                 range_rule_t<R0_, R1_>>::type;
0542 #else
0543         range_rule_t<R0_, R1_>;
0544 #endif
0545 
0546     R0 const first_;
0547     R1 const next_;
0548     std::size_t N_;
0549     std::size_t M_;
0550 };
0551 
0552 template<
0553     class Rule1, class Rule2>
0554 constexpr
0555 auto
0556 range_rule(
0557     Rule1 const& first,
0558     Rule2 const& next,
0559     std::size_t N = 0,
0560     std::size_t M =
0561         std::size_t(-1)) noexcept ->
0562 #if 1
0563     typename std::enable_if<
0564         ! std::is_integral<Rule2>::value,
0565         range_rule_t<Rule1, Rule2>>::type
0566 #else
0567     range_rule_t<Rule1, Rule2>
0568 #endif
0569 {
0570     // If you get a compile error here it
0571     // means that your rule does not meet
0572     // the type requirements. Please check
0573     // the documentation.
0574     static_assert(
0575         is_rule<Rule1>::value,
0576         "Rule requirements not met");
0577     static_assert(
0578         is_rule<Rule2>::value,
0579         "Rule requirements not met");
0580 
0581     // If you get a compile error here it
0582     // means that your rules do not have
0583     // the exact same value_type. Please
0584     // check the documentation.
0585     static_assert(
0586         std::is_same<
0587             typename Rule1::value_type,
0588             typename Rule2::value_type>::value,
0589         "Rule requirements not met");
0590 
0591     return range_rule_t<Rule1, Rule2>{
0592         first, next, N, M};
0593 }
0594 #endif
0595 
0596 } // grammar
0597 } // urls
0598 } // boost
0599 
0600 #include <boost/url/grammar/impl/range_rule.hpp>
0601 
0602 #endif