123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602 |
- //
- // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // Official repository: https://github.com/boostorg/url
- //
- #ifndef BOOST_URL_GRAMMAR_RANGE_RULE_HPP
- #define BOOST_URL_GRAMMAR_RANGE_RULE_HPP
- #include <boost/url/detail/config.hpp>
- #include <boost/url/error.hpp>
- #include <boost/core/detail/string_view.hpp>
- #include <boost/url/grammar/parse.hpp>
- #include <boost/url/grammar/type_traits.hpp>
- #include <boost/static_assert.hpp>
- #include <cstddef>
- #include <iterator>
- #include <type_traits>
- #include <stddef.h> // ::max_align_t
- namespace boost {
- namespace urls {
- namespace grammar {
- /** A forward range of parsed elements
- Objects of this type are forward ranges
- returned when parsing using the
- @ref range_rule.
- Iteration is performed by re-parsing the
- underlying character buffer. Ownership
- of the buffer is not transferred; the
- caller is responsible for ensuring that
- the lifetime of the buffer extends until
- it is no longer referenced by the range.
- @note
- The implementation may use temporary,
- recycled storage for type-erasure. Objects
- of type `range` are intended to be used
- ephemerally. That is, for short durations
- such as within a function scope. If it is
- necessary to store the range for a long
- period of time or with static storage
- duration, it is necessary to copy the
- contents to an object of a different type.
- @tparam T The value type of the range
- @see
- @ref parse,
- @ref range_rule.
- */
- template<class T>
- class range
- {
- // buffer size for type-erased rule
- static constexpr
- std::size_t BufferSize = 128;
- struct small_buffer
- {
- alignas(alignof(::max_align_t))
- unsigned char buf[BufferSize];
- void const* addr() const noexcept
- {
- return buf;
- }
- void* addr() noexcept
- {
- return buf;
- }
- };
- small_buffer sb_;
- core::string_view s_;
- std::size_t n_ = 0;
- //--------------------------------------------
- struct any_rule;
- template<class R, bool>
- struct impl1;
- template<
- class R0, class R1, bool>
- struct impl2;
- template<
- class R0, class R1>
- friend struct range_rule_t;
- any_rule&
- get() noexcept
- {
- return *reinterpret_cast<
- any_rule*>(sb_.addr());
- }
- any_rule const&
- get() const noexcept
- {
- return *reinterpret_cast<
- any_rule const*>(
- sb_.addr());
- }
- template<class R>
- range(
- core::string_view s,
- std::size_t n,
- R const& r);
- template<
- class R0, class R1>
- range(
- core::string_view s,
- std::size_t n,
- R0 const& first,
- R1 const& next);
- public:
- /** The type of each element of the range
- */
- using value_type = T;
- /** The type of each element of the range
- */
- using reference = T const&;
- /** The type of each element of the range
- */
- using const_reference = T const&;
- /** Provided for compatibility, unused
- */
- using pointer = void const*;
- /** The type used to represent unsigned integers
- */
- using size_type = std::size_t;
- /** The type used to represent signed integers
- */
- using difference_type = std::ptrdiff_t;
- /** A constant, forward iterator to elements of the range
- */
- class iterator;
- /** A constant, forward iterator to elements of the range
- */
- using const_iterator = iterator;
- /** Destructor
- */
- ~range();
- /** Constructor
- Default-constructed ranges have
- zero elements.
- @par Exception Safety
- Throws nothing.
- */
- range() noexcept;
- /** Constructor
- The new range references the
- same underlying character buffer.
- Ownership is not transferred; the
- caller is responsible for ensuring
- that the lifetime of the buffer
- extends until it is no longer
- referenced. The moved-from object
- becomes as if default-constructed.
- @par Exception Safety
- Throws nothing.
- */
- range(range&&) noexcept;
- /** Constructor
- The copy references the same
- underlying character buffer.
- Ownership is not transferred; the
- caller is responsible for ensuring
- that the lifetime of the buffer
- extends until it is no longer
- referenced.
- @par Exception Safety
- Throws nothing.
- */
- range(range const&) noexcept;
- /** Assignment
- After the move, this references the
- same underlying character buffer. Ownership
- is not transferred; the caller is responsible
- for ensuring that the lifetime of the buffer
- extends until it is no longer referenced.
- The moved-from object becomes as if
- default-constructed.
- @par Exception Safety
- Throws nothing.
- */
- range&
- operator=(range&&) noexcept;
- /** Assignment
- The copy references the same
- underlying character buffer.
- Ownership is not transferred; the
- caller is responsible for ensuring
- that the lifetime of the buffer
- extends until it is no longer
- referenced.
- @par Exception Safety
- Throws nothing.
- */
- range&
- operator=(range const&) noexcept;
- /** Return an iterator to the beginning
- */
- iterator begin() const noexcept;
- /** Return an iterator to the end
- */
- iterator end() const noexcept;
- /** Return true if the range is empty
- */
- bool
- empty() const noexcept
- {
- return n_ == 0;
- }
- /** Return the number of elements in the range
- */
- std::size_t
- size() const noexcept
- {
- return n_;
- }
- /** Return the matching part of the string
- */
- core::string_view
- string() const noexcept
- {
- return s_;
- }
- };
- //------------------------------------------------
- #ifndef BOOST_URL_DOCS
- template<
- class R0,
- class R1 = void>
- struct range_rule_t;
- #endif
- //------------------------------------------------
- /** Match a repeating number of elements
- Elements are matched using the passed rule.
- <br>
- Normally when the rule returns an error,
- the range ends and the input is rewound to
- one past the last character that matched
- successfully. However, if the rule returns
- the special value @ref error::end_of_range, the
- input is not rewound. This allows for rules
- which consume input without producing
- elements in the range. For example, to
- relax the grammar for a comma-delimited
- list by allowing extra commas in between
- elements.
- @par Value Type
- @code
- using value_type = range< typename Rule::value_type >;
- @endcode
- @par Example
- Rules are used with the function @ref parse.
- @code
- // range = 1*( ";" token )
- system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
- range_rule(
- tuple_rule(
- squelch( delim_rule( ';' ) ),
- token_rule( alpha_chars ) ),
- 1 ) );
- @endcode
- @par BNF
- @code
- range = <N>*<M>next
- @endcode
- @par Specification
- @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
- >3.6. Variable Repetition (rfc5234)</a>
- @param next The rule to use for matching
- each element. The range extends until this
- rule returns an error.
- @param N The minimum number of elements for
- the range to be valid. If omitted, this
- defaults to zero.
- @param M The maximum number of elements for
- the range to be valid. If omitted, this
- defaults to unlimited.
- @see
- @ref alpha_chars,
- @ref delim_rule,
- @ref error::end_of_range,
- @ref parse,
- @ref range,
- @ref tuple_rule,
- @ref squelch.
- */
- #ifdef BOOST_URL_DOCS
- template<class Rule>
- constexpr
- __implementation_defined__
- range_rule(
- Rule next,
- std::size_t N = 0,
- std::size_t M =
- std::size_t(-1)) noexcept;
- #else
- template<class R>
- struct range_rule_t<R>
- {
- using value_type =
- range<typename R::value_type>;
- system::result<value_type>
- parse(
- char const*& it,
- char const* end) const;
- private:
- constexpr
- range_rule_t(
- R const& next,
- std::size_t N,
- std::size_t M) noexcept
- : next_(next)
- , N_(N)
- , M_(M)
- {
- }
- template<class R_>
- friend
- constexpr
- range_rule_t<R_>
- range_rule(
- R_ const& next,
- std::size_t N,
- std::size_t M) noexcept;
- R const next_;
- std::size_t N_;
- std::size_t M_;
- };
- template<class Rule>
- constexpr
- range_rule_t<Rule>
- range_rule(
- Rule const& next,
- std::size_t N = 0,
- std::size_t M =
- std::size_t(-1)) noexcept
- {
- // If you get a compile error here it
- // means that your rule does not meet
- // the type requirements. Please check
- // the documentation.
- static_assert(
- is_rule<Rule>::value,
- "Rule requirements not met");
- return range_rule_t<Rule>{
- next, N, M};
- }
- #endif
- //------------------------------------------------
- /** Match a repeating number of elements
- Two rules are used for match. The rule
- `first` is used for matching the first
- element, while the `next` rule is used
- to match every subsequent element.
- <br>
- Normally when the rule returns an error,
- the range ends and the input is rewound to
- one past the last character that matched
- successfully. However, if the rule returns
- the special value @ref error::end_of_range, the
- input is not rewound. This allows for rules
- which consume input without producing
- elements in the range. For example, to
- relax the grammar for a comma-delimited
- list by allowing extra commas in between
- elements.
- @par Value Type
- @code
- using value_type = range< typename Rule::value_type >;
- @endcode
- @par Example
- Rules are used with the function @ref parse.
- @code
- // range = [ token ] *( "," token )
- system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
- range_rule(
- token_rule( alpha_chars ), // first
- tuple_rule( // next
- squelch( delim_rule(',') ),
- token_rule( alpha_chars ) ) ) );
- @endcode
- @par BNF
- @code
- range = <1>*<1>first
- / first <N-1>*<M-1>next
- @endcode
- @par Specification
- @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
- >3.6. Variable Repetition (rfc5234)</a>
- @param first The rule to use for matching
- the first element. If this rule returns
- an error, the range is empty.
- @param next The rule to use for matching
- each subsequent element. The range extends
- until this rule returns an error.
- @param N The minimum number of elements for
- the range to be valid. If omitted, this
- defaults to zero.
- @param M The maximum number of elements for
- the range to be valid. If omitted, this
- defaults to unlimited.
- @see
- @ref alpha_chars,
- @ref delim_rule,
- @ref error::end_of_range,
- @ref parse,
- @ref range,
- @ref tuple_rule,
- @ref squelch.
- */
- #ifdef BOOST_URL_DOCS
- template<
- class Rule1, class Rule2>
- constexpr
- __implementation_defined__
- range_rule(
- Rule1 first,
- Rule2 next,
- std::size_t N = 0,
- std::size_t M =
- std::size_t(-1)) noexcept;
- #else
- template<class R0, class R1>
- struct range_rule_t
- {
- using value_type =
- range<typename R0::value_type>;
- system::result<value_type>
- parse(
- char const*& it,
- char const* end) const;
- private:
- constexpr
- range_rule_t(
- R0 const& first,
- R1 const& next,
- std::size_t N,
- std::size_t M) noexcept
- : first_(first)
- , next_(next)
- , N_(N)
- , M_(M)
- {
- }
- template<
- class R0_, class R1_>
- friend
- constexpr
- auto
- range_rule(
- R0_ const& first,
- R1_ const& next,
- std::size_t N,
- std::size_t M) noexcept ->
- #if 1
- typename std::enable_if<
- ! std::is_integral<R1_>::value,
- range_rule_t<R0_, R1_>>::type;
- #else
- range_rule_t<R0_, R1_>;
- #endif
- R0 const first_;
- R1 const next_;
- std::size_t N_;
- std::size_t M_;
- };
- template<
- class Rule1, class Rule2>
- constexpr
- auto
- range_rule(
- Rule1 const& first,
- Rule2 const& next,
- std::size_t N = 0,
- std::size_t M =
- std::size_t(-1)) noexcept ->
- #if 1
- typename std::enable_if<
- ! std::is_integral<Rule2>::value,
- range_rule_t<Rule1, Rule2>>::type
- #else
- range_rule_t<Rule1, Rule2>
- #endif
- {
- // If you get a compile error here it
- // means that your rule does not meet
- // the type requirements. Please check
- // the documentation.
- static_assert(
- is_rule<Rule1>::value,
- "Rule requirements not met");
- static_assert(
- is_rule<Rule2>::value,
- "Rule requirements not met");
- // If you get a compile error here it
- // means that your rules do not have
- // the exact same value_type. Please
- // check the documentation.
- static_assert(
- std::is_same<
- typename Rule1::value_type,
- typename Rule2::value_type>::value,
- "Rule requirements not met");
- return range_rule_t<Rule1, Rule2>{
- first, next, N, M};
- }
- #endif
- } // grammar
- } // urls
- } // boost
- #include <boost/url/grammar/impl/range_rule.hpp>
- #endif
|