1  
//
1  
//
2  
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
2  
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/boostorg/url
7  
// Official repository: https://github.com/boostorg/url
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_URL_GRAMMAR_RANGE_RULE_HPP
10  
#ifndef BOOST_URL_GRAMMAR_RANGE_RULE_HPP
11  
#define BOOST_URL_GRAMMAR_RANGE_RULE_HPP
11  
#define BOOST_URL_GRAMMAR_RANGE_RULE_HPP
12  

12  

13  
#include <boost/url/detail/config.hpp>
13  
#include <boost/url/detail/config.hpp>
14  
#include <boost/url/error.hpp>
14  
#include <boost/url/error.hpp>
15  
#include <boost/core/detail/string_view.hpp>
15  
#include <boost/core/detail/string_view.hpp>
16  
#include <boost/url/grammar/parse.hpp>
16  
#include <boost/url/grammar/parse.hpp>
17  
#include <boost/url/grammar/type_traits.hpp>
17  
#include <boost/url/grammar/type_traits.hpp>
18  
#include <boost/url/grammar/detail/range_rule.hpp>
18  
#include <boost/url/grammar/detail/range_rule.hpp>
19  
#include <boost/core/detail/static_assert.hpp>
19  
#include <boost/core/detail/static_assert.hpp>
20  
#include <cstddef>
20  
#include <cstddef>
21  
#include <iterator>
21  
#include <iterator>
22  
#include <type_traits>
22  
#include <type_traits>
23  
#include <utility>
23  
#include <utility>
24  
#include <stddef.h> // ::max_align_t
24  
#include <stddef.h> // ::max_align_t
25  

25  

26  
namespace boost {
26  
namespace boost {
27  
namespace urls {
27  
namespace urls {
28  
namespace grammar {
28  
namespace grammar {
29  
namespace implementation_defined {
29  
namespace implementation_defined {
30  
template<class R0, class R1>
30  
template<class R0, class R1>
31  
struct range_rule_t;
31  
struct range_rule_t;
32  
} // implementation_defined
32  
} // implementation_defined
33  

33  

34  
namespace implementation_defined
34  
namespace implementation_defined
35  
{
35  
{
36  
template<class RangeRule, class = void>
36  
template<class RangeRule, class = void>
37  
struct range_value_type
37  
struct range_value_type
38  
{
38  
{
39  
    using type = void;
39  
    using type = void;
40  
};
40  
};
41  

41  

42  
template<class RangeRule>
42  
template<class RangeRule>
43  
struct range_value_type<
43  
struct range_value_type<
44  
    RangeRule,
44  
    RangeRule,
45  
    urls::void_t<typename RangeRule::value_type>>
45  
    urls::void_t<typename RangeRule::value_type>>
46  
{
46  
{
47  
    using type = typename RangeRule::value_type;
47  
    using type = typename RangeRule::value_type;
48  
};
48  
};
49  

49  

50  
template<class RangeRule, class ValueType, class = void>
50  
template<class RangeRule, class ValueType, class = void>
51  
struct is_range_rule : std::false_type
51  
struct is_range_rule : std::false_type
52  
{
52  
{
53  
};
53  
};
54  

54  

55  
template<class RangeRule, class ValueType>
55  
template<class RangeRule, class ValueType>
56  
struct is_range_rule<
56  
struct is_range_rule<
57  
    RangeRule,
57  
    RangeRule,
58  
    ValueType,
58  
    ValueType,
59  
    urls::void_t<
59  
    urls::void_t<
60  
        decltype(std::declval<RangeRule const&>().first(
60  
        decltype(std::declval<RangeRule const&>().first(
61  
            std::declval<char const*&>(),
61  
            std::declval<char const*&>(),
62  
            std::declval<char const*>())),
62  
            std::declval<char const*>())),
63  
        decltype(std::declval<RangeRule const&>().next(
63  
        decltype(std::declval<RangeRule const&>().next(
64  
            std::declval<char const*&>(),
64  
            std::declval<char const*&>(),
65  
            std::declval<char const*>()))>>
65  
            std::declval<char const*>()))>>
66  
    : std::integral_constant<bool,
66  
    : std::integral_constant<bool,
67  
        std::is_same<
67  
        std::is_same<
68  
            decltype(std::declval<RangeRule const&>().first(
68  
            decltype(std::declval<RangeRule const&>().first(
69  
                std::declval<char const*&>(),
69  
                std::declval<char const*&>(),
70  
                std::declval<char const*>())),
70  
                std::declval<char const*>())),
71  
            system::result<ValueType>>::value &&
71  
            system::result<ValueType>>::value &&
72  
        std::is_same<
72  
        std::is_same<
73  
            decltype(std::declval<RangeRule const&>().next(
73  
            decltype(std::declval<RangeRule const&>().next(
74  
                std::declval<char const*&>(),
74  
                std::declval<char const*&>(),
75  
                std::declval<char const*>())),
75  
                std::declval<char const*>())),
76  
            system::result<ValueType>>::value>
76  
            system::result<ValueType>>::value>
77  
{
77  
{
78  
};
78  
};
79  
}
79  
}
80  

80  

81  
template<class RangeRule>
81  
template<class RangeRule>
82  
using is_range_rule = implementation_defined::is_range_rule<
82  
using is_range_rule = implementation_defined::is_range_rule<
83  
    RangeRule,
83  
    RangeRule,
84  
    typename implementation_defined::range_value_type<
84  
    typename implementation_defined::range_value_type<
85  
        RangeRule>::type>;
85  
        RangeRule>::type>;
86  

86  

87  
#ifdef BOOST_URL_HAS_CONCEPTS
87  
#ifdef BOOST_URL_HAS_CONCEPTS
88  
template <class T>
88  
template <class T>
89  
concept RangeRule =
89  
concept RangeRule =
90  
    requires (T r, char const*& it, char const* end)
90  
    requires (T r, char const*& it, char const* end)
91  
    {
91  
    {
92  
        typename T::value_type;
92  
        typename T::value_type;
93  
        { r.first(it, end) } -> std::same_as<system::result<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>>;
94  
        { r.next(it, end) } -> std::same_as<system::result<typename T::value_type>>;
95  
    };
95  
    };
96  
#endif
96  
#endif
97  

97  

98  
template<class T>
98  
template<class T>
99  
class any_rule;
99  
class any_rule;
100  

100  

101  
template<class T>
101  
template<class T>
102  
class any_rule
102  
class any_rule
103  
{
103  
{
104  
public:
104  
public:
105  
    using value_type = T;
105  
    using value_type = T;
106  

106  

107  
    any_rule() noexcept;
107  
    any_rule() noexcept;
108  
    any_rule(any_rule const&) noexcept;
108  
    any_rule(any_rule const&) noexcept;
109  
    any_rule(any_rule&&) noexcept;
109  
    any_rule(any_rule&&) noexcept;
110  
    any_rule& operator=(any_rule const&) noexcept;
110  
    any_rule& operator=(any_rule const&) noexcept;
111  
    any_rule& operator=(any_rule&&) noexcept;
111  
    any_rule& operator=(any_rule&&) noexcept;
112  
    ~any_rule();
112  
    ~any_rule();
113  

113  

114  
    template<class R>
114  
    template<class R>
115  
    explicit
115  
    explicit
116  
    any_rule(R const& next);
116  
    any_rule(R const& next);
117  

117  

118  
    template<class R0, class R1>
118  
    template<class R0, class R1>
119  
    any_rule(
119  
    any_rule(
120  
        R0 const& first,
120  
        R0 const& first,
121  
        R1 const& next);
121  
        R1 const& next);
122  

122  

123  
    system::result<T>
123  
    system::result<T>
124  
    first(
124  
    first(
125  
        char const*& it,
125  
        char const*& it,
126  
        char const* end) const noexcept;
126  
        char const* end) const noexcept;
127  

127  

128  
    system::result<T>
128  
    system::result<T>
129  
    next(
129  
    next(
130  
        char const*& it,
130  
        char const*& it,
131  
        char const* end) const noexcept;
131  
        char const* end) const noexcept;
132  

132  

133  
private:
133  
private:
134  
    static constexpr
134  
    static constexpr
135  
        std::size_t BufferSize = 128;
135  
        std::size_t BufferSize = 128;
136  

136  

137  
    struct small_buffer
137  
    struct small_buffer
138  
    {
138  
    {
139  
        alignas(alignof(::max_align_t))
139  
        alignas(alignof(::max_align_t))
140  
        unsigned char buf[BufferSize];
140  
        unsigned char buf[BufferSize];
141  

141  

142  
        void const* addr() const noexcept
142  
        void const* addr() const noexcept
143  
        {
143  
        {
144  
            return buf;
144  
            return buf;
145  
        }
145  
        }
146  

146  

147  
        void* addr() noexcept
147  
        void* addr() noexcept
148  
        {
148  
        {
149  
            return buf;
149  
            return buf;
150  
        }
150  
        }
151  
    };
151  
    };
152  

152  

153  
    struct impl_base;
153  
    struct impl_base;
154  

154  

155  
    template<class R, bool>
155  
    template<class R, bool>
156  
    struct impl1;
156  
    struct impl1;
157  

157  

158  
    template<
158  
    template<
159  
        class R0, class R1, bool>
159  
        class R0, class R1, bool>
160  
    struct impl2;
160  
    struct impl2;
161  

161  

162  
    impl_base&
162  
    impl_base&
163  
    get() noexcept;
163  
    get() noexcept;
164  

164  

165  
    impl_base const&
165  
    impl_base const&
166  
    get() const noexcept;
166  
    get() const noexcept;
167  

167  

168  
    small_buffer sb_;
168  
    small_buffer sb_;
169  
};
169  
};
170  

170  

171  
/** A forward range of parsed elements
171  
/** A forward range of parsed elements
172  

172  

173  
    Objects of this type are forward ranges
173  
    Objects of this type are forward ranges
174  
    returned when parsing using the
174  
    returned when parsing using the
175  
    @ref range_rule.
175  
    @ref range_rule.
176  
    Iteration is performed by re-parsing the
176  
    Iteration is performed by re-parsing the
177  
    underlying character buffer. Ownership
177  
    underlying character buffer. Ownership
178  
    of the buffer is not transferred; the
178  
    of the buffer is not transferred; the
179  
    caller is responsible for ensuring that
179  
    caller is responsible for ensuring that
180  
    the lifetime of the buffer extends until
180  
    the lifetime of the buffer extends until
181  
    it is no longer referenced by the range.
181  
    it is no longer referenced by the range.
182  

182  

183  
    @note
183  
    @note
184  

184  

185  
    The implementation may type-erase the
185  
    The implementation may type-erase the
186  
    rule responsible for iterating the
186  
    rule responsible for iterating the
187  
    underlying character buffer. Objects
187  
    underlying character buffer. Objects
188  
    of type `range` are intended to be used
188  
    of type `range` are intended to be used
189  
    ephemerally. That is, for short durations
189  
    ephemerally. That is, for short durations
190  
    such as within a function scope. If it is
190  
    such as within a function scope. If it is
191  
    necessary to store the range for a long
191  
    necessary to store the range for a long
192  
    period of time or with static storage
192  
    period of time or with static storage
193  
    duration, it is necessary to copy the
193  
    duration, it is necessary to copy the
194  
    contents to an object of a different type.
194  
    contents to an object of a different type.
195  

195  

196  
    @tparam T The value type of the range
196  
    @tparam T The value type of the range
197  
    @tparam RangeRule The implementation used to
197  
    @tparam RangeRule The implementation used to
198  
        iterate the range. The default is a
198  
        iterate the range. The default is a
199  
        type-erased rule.
199  
        type-erased rule.
200  

200  

201  
    @see
201  
    @see
202  
        @ref parse,
202  
        @ref parse,
203  
        @ref range_rule.
203  
        @ref range_rule.
204  
*/
204  
*/
205  
template<
205  
template<
206  
    class T,
206  
    class T,
207  
    class RangeRule = any_rule<T>>
207  
    class RangeRule = any_rule<T>>
208  
class range
208  
class range
209  
    : private detail::range_base_storage<
209  
    : private detail::range_base_storage<
210  
        RangeRule>
210  
        RangeRule>
211  
{
211  
{
212  
private:
212  
private:
213  
#ifdef BOOST_URL_HAS_CONCEPTS
213  
#ifdef BOOST_URL_HAS_CONCEPTS
214  
    static_assert(
214  
    static_assert(
215  
        ::boost::urls::grammar::RangeRule<RangeRule>,
215  
        ::boost::urls::grammar::RangeRule<RangeRule>,
216  
        "RangeRule requirements not met");
216  
        "RangeRule requirements not met");
217  
#else
217  
#else
218  
    static_assert(
218  
    static_assert(
219  
        ::boost::urls::grammar::is_range_rule<RangeRule>::value,
219  
        ::boost::urls::grammar::is_range_rule<RangeRule>::value,
220  
        "RangeRule requirements not met");
220  
        "RangeRule requirements not met");
221  
#endif
221  
#endif
222  

222  

223  
    static_assert(
223  
    static_assert(
224  
        std::is_class<
224  
        std::is_class<
225  
            detail::range_base_storage<
225  
            detail::range_base_storage<
226  
                RangeRule>>::value,
226  
                RangeRule>>::value,
227  
        "range_base_storage requirements not met");
227  
        "range_base_storage requirements not met");
228  

228  

229  
    using storage_type =
229  
    using storage_type =
230  
        detail::range_base_storage<
230  
        detail::range_base_storage<
231  
            RangeRule>;
231  
            RangeRule>;
232  

232  

233  
    using storage_type::rule;
233  
    using storage_type::rule;
234  

234  

235  
    core::string_view s_;
235  
    core::string_view s_;
236  
    std::size_t n_ = 0;
236  
    std::size_t n_ = 0;
237  

237  

238  
    template<
238  
    template<
239  
        class R0, class R1>
239  
        class R0, class R1>
240  
    friend struct implementation_defined::range_rule_t;
240  
    friend struct implementation_defined::range_rule_t;
241  

241  

242  
    range(
242  
    range(
243  
        core::string_view s,
243  
        core::string_view s,
244  
        std::size_t n,
244  
        std::size_t n,
245  
        RangeRule const& rule) noexcept;
245  
        RangeRule const& rule) noexcept;
246  

246  

247  
    range(
247  
    range(
248  
        core::string_view s,
248  
        core::string_view s,
249  
        std::size_t n,
249  
        std::size_t n,
250  
        RangeRule&& rule) noexcept;
250  
        RangeRule&& rule) noexcept;
251  

251  

252  
public:
252  
public:
253  
    /** The type of each element of the range
253  
    /** The type of each element of the range
254  
    */
254  
    */
255  
    using value_type = T;
255  
    using value_type = T;
256  

256  

257  
    /** The type of each element of the range
257  
    /** The type of each element of the range
258  
    */
258  
    */
259  
    using reference = T const&;
259  
    using reference = T const&;
260  

260  

261  
    /** The type of each element of the range
261  
    /** The type of each element of the range
262  
    */
262  
    */
263  
    using const_reference = T const&;
263  
    using const_reference = T const&;
264  

264  

265  
    /** Provided for compatibility, unused
265  
    /** Provided for compatibility, unused
266  
    */
266  
    */
267  
    using pointer = void const*;
267  
    using pointer = void const*;
268  

268  

269  
    /** The type used to represent unsigned integers
269  
    /** The type used to represent unsigned integers
270  
    */
270  
    */
271  
    using size_type = std::size_t;
271  
    using size_type = std::size_t;
272  

272  

273  
    /** The type used to represent signed integers
273  
    /** The type used to represent signed integers
274  
    */
274  
    */
275  
    using difference_type = std::ptrdiff_t;
275  
    using difference_type = std::ptrdiff_t;
276  

276  

277  
    /** A constant, forward iterator to elements of the range
277  
    /** A constant, forward iterator to elements of the range
278  
    */
278  
    */
279  
    class iterator;
279  
    class iterator;
280  

280  

281  
    /** A constant, forward iterator to elements of the range
281  
    /** A constant, forward iterator to elements of the range
282  
    */
282  
    */
283  
    using const_iterator = iterator;
283  
    using const_iterator = iterator;
284  

284  

285  
    /** Destructor
285  
    /** Destructor
286  
    */
286  
    */
287  
    ~range();
287  
    ~range();
288  

288  

289  
    /** Constructor
289  
    /** Constructor
290  

290  

291  
        Default-constructed ranges have
291  
        Default-constructed ranges have
292  
        zero elements.
292  
        zero elements.
293  

293  

294  
        @par Exception Safety
294  
        @par Exception Safety
295  
        Throws nothing.
295  
        Throws nothing.
296  
    */
296  
    */
297  
    range() noexcept;
297  
    range() noexcept;
298  

298  

299  
    /** Constructor
299  
    /** Constructor
300  

300  

301  
        The new range references the
301  
        The new range references the
302  
        same underlying character buffer.
302  
        same underlying character buffer.
303  
        Ownership is not transferred; the
303  
        Ownership is not transferred; the
304  
        caller is responsible for ensuring
304  
        caller is responsible for ensuring
305  
        that the lifetime of the buffer
305  
        that the lifetime of the buffer
306  
        extends until it is no longer
306  
        extends until it is no longer
307  
        referenced. The moved-from object
307  
        referenced. The moved-from object
308  
        becomes as if default-constructed.
308  
        becomes as if default-constructed.
309  

309  

310  
        @par Exception Safety
310  
        @par Exception Safety
311  
        Throws nothing.
311  
        Throws nothing.
312  
    */
312  
    */
313  
    range(range&&) noexcept;
313  
    range(range&&) noexcept;
314  

314  

315  
    /** Constructor
315  
    /** Constructor
316  

316  

317  
        The copy references the same
317  
        The copy references the same
318  
        underlying character buffer.
318  
        underlying character buffer.
319  
        Ownership is not transferred; the
319  
        Ownership is not transferred; the
320  
        caller is responsible for ensuring
320  
        caller is responsible for ensuring
321  
        that the lifetime of the buffer
321  
        that the lifetime of the buffer
322  
        extends until it is no longer
322  
        extends until it is no longer
323  
        referenced.
323  
        referenced.
324  

324  

325  
        @par Exception Safety
325  
        @par Exception Safety
326  
        Throws nothing.
326  
        Throws nothing.
327  
    */
327  
    */
328  
    range(range const&) noexcept;
328  
    range(range const&) noexcept;
329  

329  

330  
    /** Assignment
330  
    /** Assignment
331  

331  

332  
        After the move, this references the
332  
        After the move, this references the
333  
        same underlying character buffer. Ownership
333  
        same underlying character buffer. Ownership
334  
        is not transferred; the caller is responsible
334  
        is not transferred; the caller is responsible
335  
        for ensuring that the lifetime of the buffer
335  
        for ensuring that the lifetime of the buffer
336  
        extends until it is no longer referenced.
336  
        extends until it is no longer referenced.
337  
        The moved-from object becomes as if
337  
        The moved-from object becomes as if
338  
        default-constructed.
338  
        default-constructed.
339  

339  

340  
        @par Exception Safety
340  
        @par Exception Safety
341  
        Throws nothing.
341  
        Throws nothing.
342  

342  

343  
        @return `*this`
343  
        @return `*this`
344  
    */
344  
    */
345  
    range&
345  
    range&
346  
    operator=(range&&) noexcept;
346  
    operator=(range&&) noexcept;
347  

347  

348  
    /** Assignment
348  
    /** Assignment
349  

349  

350  
        The copy references the same
350  
        The copy references the same
351  
        underlying character buffer.
351  
        underlying character buffer.
352  
        Ownership is not transferred; the
352  
        Ownership is not transferred; the
353  
        caller is responsible for ensuring
353  
        caller is responsible for ensuring
354  
        that the lifetime of the buffer
354  
        that the lifetime of the buffer
355  
        extends until it is no longer
355  
        extends until it is no longer
356  
        referenced.
356  
        referenced.
357  

357  

358  
        @par Exception Safety
358  
        @par Exception Safety
359  
        Throws nothing.
359  
        Throws nothing.
360  

360  

361  
        @return `*this`
361  
        @return `*this`
362  
    */
362  
    */
363  
    range&
363  
    range&
364  
    operator=(range const&) noexcept;
364  
    operator=(range const&) noexcept;
365  

365  

366  
    /** Return an iterator to the beginning
366  
    /** Return an iterator to the beginning
367  

367  

368  
        @return An iterator to the first element
368  
        @return An iterator to the first element
369  
    */
369  
    */
370  
    iterator begin() const noexcept;
370  
    iterator begin() const noexcept;
371  

371  

372  
    /** Return an iterator to the end
372  
    /** Return an iterator to the end
373  

373  

374  
        @return An iterator to one past the last element
374  
        @return An iterator to one past the last element
375  
    */
375  
    */
376  
    iterator end() const noexcept;
376  
    iterator end() const noexcept;
377  

377  

378  
    /** Return true if the range is empty
378  
    /** Return true if the range is empty
379  

379  

380  
        @return `true` if the range is empty
380  
        @return `true` if the range is empty
381  
    */
381  
    */
382  
    bool
382  
    bool
383  
    empty() const noexcept
383  
    empty() const noexcept
384  
    {
384  
    {
385  
        return n_ == 0;
385  
        return n_ == 0;
386  
    }
386  
    }
387  

387  

388  
    /** Return the number of elements in the range
388  
    /** Return the number of elements in the range
389  

389  

390  
        @return The number of elements
390  
        @return The number of elements
391  
    */
391  
    */
392  
    std::size_t
392  
    std::size_t
393  
    size() const noexcept
393  
    size() const noexcept
394  
    {
394  
    {
395  
        return n_;
395  
        return n_;
396  
    }
396  
    }
397  

397  

398  
    /** Return the matching part of the string
398  
    /** Return the matching part of the string
399  

399  

400  
        @return A string view representing the range
400  
        @return A string view representing the range
401  
    */
401  
    */
402  
    core::string_view
402  
    core::string_view
403  
    string() const noexcept
403  
    string() const noexcept
404  
    {
404  
    {
405  
        return s_;
405  
        return s_;
406  
    }
406  
    }
407  
};
407  
};
408  

408  

409  
//------------------------------------------------
409  
//------------------------------------------------
410  

410  

411  
namespace implementation_defined {
411  
namespace implementation_defined {
412  
template<
412  
template<
413  
    class R0,
413  
    class R0,
414  
    class R1 = void>
414  
    class R1 = void>
415  
struct range_rule_t;
415  
struct range_rule_t;
416  
}
416  
}
417  

417  

418  
//------------------------------------------------
418  
//------------------------------------------------
419  

419  

420  
namespace implementation_defined {
420  
namespace implementation_defined {
421  
template<class R>
421  
template<class R>
422  
struct range_rule_t<R>
422  
struct range_rule_t<R>
423  
{
423  
{
424  
    using value_type =
424  
    using value_type =
425  
        range<typename R::value_type>;
425  
        range<typename R::value_type>;
426  

426  

427  
    system::result<value_type>
427  
    system::result<value_type>
428  
    parse(
428  
    parse(
429  
        char const*& it,
429  
        char const*& it,
430  
        char const* end) const;
430  
        char const* end) const;
431  

431  

432  
    constexpr
432  
    constexpr
433  
    range_rule_t(
433  
    range_rule_t(
434  
        R const& next,
434  
        R const& next,
435  
        std::size_t N,
435  
        std::size_t N,
436  
        std::size_t M) noexcept
436  
        std::size_t M) noexcept
437  
        : next_(next)
437  
        : next_(next)
438  
        , N_(N)
438  
        , N_(N)
439  
        , M_(M)
439  
        , M_(M)
440  
    {
440  
    {
441  
    }
441  
    }
442  

442  

443  
private:
443  
private:
444  
    R const next_;
444  
    R const next_;
445  
    std::size_t N_;
445  
    std::size_t N_;
446  
    std::size_t M_;
446  
    std::size_t M_;
447  
};
447  
};
448  
} // implementation_defined
448  
} // implementation_defined
449  

449  

450  
/** Match a repeating number of elements
450  
/** Match a repeating number of elements
451  

451  

452  
    Elements are matched using the passed rule.
452  
    Elements are matched using the passed rule.
453  
    <br>
453  
    <br>
454  
    Normally when the rule returns an error,
454  
    Normally when the rule returns an error,
455  
    the range ends and the input is rewound to
455  
    the range ends and the input is rewound to
456  
    one past the last character that matched
456  
    one past the last character that matched
457  
    successfully. However, if the rule returns
457  
    successfully. However, if the rule returns
458  
    the special value @ref error::end_of_range, the
458  
    the special value @ref error::end_of_range, the
459  
    input is not rewound. This allows for rules
459  
    input is not rewound. This allows for rules
460  
    which consume input without producing
460  
    which consume input without producing
461  
    elements in the range. For example, to
461  
    elements in the range. For example, to
462  
    relax the grammar for a comma-delimited
462  
    relax the grammar for a comma-delimited
463  
    list by allowing extra commas in between
463  
    list by allowing extra commas in between
464  
    elements.
464  
    elements.
465  

465  

466  
    @par Value Type
466  
    @par Value Type
467  
    @code
467  
    @code
468  
    using value_type = range< typename Rule::value_type >;
468  
    using value_type = range< typename Rule::value_type >;
469  
    @endcode
469  
    @endcode
470  

470  

471  
    @par Example
471  
    @par Example
472  
    Rules are used with the function @ref parse.
472  
    Rules are used with the function @ref parse.
473  
    @code
473  
    @code
474  
    // range    = 1*( ";" token )
474  
    // range    = 1*( ";" token )
475  

475  

476  
    system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
476  
    system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
477  
        range_rule(
477  
        range_rule(
478  
            tuple_rule(
478  
            tuple_rule(
479  
                squelch( delim_rule( ';' ) ),
479  
                squelch( delim_rule( ';' ) ),
480  
                token_rule( alpha_chars ) ),
480  
                token_rule( alpha_chars ) ),
481  
            1 ) );
481  
            1 ) );
482  
    @endcode
482  
    @endcode
483  

483  

484  
    @par BNF
484  
    @par BNF
485  
    @code
485  
    @code
486  
    range        = <N>*<M>next
486  
    range        = <N>*<M>next
487  
    @endcode
487  
    @endcode
488  

488  

489  
    @par Specification
489  
    @par Specification
490  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
490  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
491  
        >3.6.  Variable Repetition (rfc5234)</a>
491  
        >3.6.  Variable Repetition (rfc5234)</a>
492  

492  

493  
    @param next The rule to use for matching
493  
    @param next The rule to use for matching
494  
    each element. The range extends until this
494  
    each element. The range extends until this
495  
    rule returns an error.
495  
    rule returns an error.
496  

496  

497  
    @param N The minimum number of elements for
497  
    @param N The minimum number of elements for
498  
    the range to be valid. If omitted, this
498  
    the range to be valid. If omitted, this
499  
    defaults to zero.
499  
    defaults to zero.
500  

500  

501  
    @param M The maximum number of elements for
501  
    @param M The maximum number of elements for
502  
    the range to be valid. If omitted, this
502  
    the range to be valid. If omitted, this
503  
    defaults to unlimited.
503  
    defaults to unlimited.
504  

504  

505  
    @return A rule that matches the range.
505  
    @return A rule that matches the range.
506  

506  

507  
    @see
507  
    @see
508  
        @ref alpha_chars,
508  
        @ref alpha_chars,
509  
        @ref delim_rule,
509  
        @ref delim_rule,
510  
        @ref error::end_of_range,
510  
        @ref error::end_of_range,
511  
        @ref parse,
511  
        @ref parse,
512  
        @ref range,
512  
        @ref range,
513  
        @ref tuple_rule,
513  
        @ref tuple_rule,
514  
        @ref squelch.
514  
        @ref squelch.
515  
*/
515  
*/
516  
template<BOOST_URL_CONSTRAINT(Rule) R>
516  
template<BOOST_URL_CONSTRAINT(Rule) R>
517  
constexpr
517  
constexpr
518  
implementation_defined::range_rule_t<R>
518  
implementation_defined::range_rule_t<R>
519  
range_rule(
519  
range_rule(
520  
    R const& next,
520  
    R const& next,
521  
    std::size_t N = 0,
521  
    std::size_t N = 0,
522  
    std::size_t M =
522  
    std::size_t M =
523  
        std::size_t(-1)) noexcept
523  
        std::size_t(-1)) noexcept
524  
{
524  
{
525  
    // If you get a compile error here it
525  
    // If you get a compile error here it
526  
    // means that your rule does not meet
526  
    // means that your rule does not meet
527  
    // the type requirements. Please check
527  
    // the type requirements. Please check
528  
    // the documentation.
528  
    // the documentation.
529  
    static_assert(
529  
    static_assert(
530  
        is_rule<R>::value,
530  
        is_rule<R>::value,
531  
        "Rule requirements not met");
531  
        "Rule requirements not met");
532  

532  

533  
    return implementation_defined::range_rule_t<R>{
533  
    return implementation_defined::range_rule_t<R>{
534  
        next, N, M};
534  
        next, N, M};
535  
}
535  
}
536  

536  

537  
//------------------------------------------------
537  
//------------------------------------------------
538  

538  

539  
namespace implementation_defined {
539  
namespace implementation_defined {
540  
template<class R0, class R1>
540  
template<class R0, class R1>
541  
struct range_rule_t
541  
struct range_rule_t
542  
{
542  
{
543  
    using value_type =
543  
    using value_type =
544  
        range<typename R0::value_type>;
544  
        range<typename R0::value_type>;
545  

545  

546  
    system::result<value_type>
546  
    system::result<value_type>
547  
    parse(
547  
    parse(
548  
        char const*& it,
548  
        char const*& it,
549  
        char const* end) const;
549  
        char const* end) const;
550  

550  

551  
    constexpr
551  
    constexpr
552  
    range_rule_t(
552  
    range_rule_t(
553  
        R0 const& first,
553  
        R0 const& first,
554  
        R1 const& next,
554  
        R1 const& next,
555  
        std::size_t N,
555  
        std::size_t N,
556  
        std::size_t M) noexcept
556  
        std::size_t M) noexcept
557  
        : first_(first)
557  
        : first_(first)
558  
        , next_(next)
558  
        , next_(next)
559  
        , N_(N)
559  
        , N_(N)
560  
        , M_(M)
560  
        , M_(M)
561  
    {
561  
    {
562  
    }
562  
    }
563  

563  

564  
private:
564  
private:
565  
    R0 const first_;
565  
    R0 const first_;
566  
    R1 const next_;
566  
    R1 const next_;
567  
    std::size_t N_;
567  
    std::size_t N_;
568  
    std::size_t M_;
568  
    std::size_t M_;
569  
};
569  
};
570  
} // implementation_defined
570  
} // implementation_defined
571  

571  

572  
/** Match a repeating number of elements
572  
/** Match a repeating number of elements
573  

573  

574  
    Two rules are used for match. The rule
574  
    Two rules are used for match. The rule
575  
    `first` is used for matching the first
575  
    `first` is used for matching the first
576  
    element, while the `next` rule is used
576  
    element, while the `next` rule is used
577  
    to match every subsequent element.
577  
    to match every subsequent element.
578  
    <br>
578  
    <br>
579  
    Normally when the rule returns an error,
579  
    Normally when the rule returns an error,
580  
    the range ends and the input is rewound to
580  
    the range ends and the input is rewound to
581  
    one past the last character that matched
581  
    one past the last character that matched
582  
    successfully. However, if the rule returns
582  
    successfully. However, if the rule returns
583  
    the special value @ref error::end_of_range, the
583  
    the special value @ref error::end_of_range, the
584  
    input is not rewound. This allows for rules
584  
    input is not rewound. This allows for rules
585  
    which consume input without producing
585  
    which consume input without producing
586  
    elements in the range. For example, to
586  
    elements in the range. For example, to
587  
    relax the grammar for a comma-delimited
587  
    relax the grammar for a comma-delimited
588  
    list by allowing extra commas in between
588  
    list by allowing extra commas in between
589  
    elements.
589  
    elements.
590  

590  

591  
    @par Value Type
591  
    @par Value Type
592  
    @code
592  
    @code
593  
    using value_type = range< typename Rule::value_type >;
593  
    using value_type = range< typename Rule::value_type >;
594  
    @endcode
594  
    @endcode
595  

595  

596  
    @par Example
596  
    @par Example
597  
    Rules are used with the function @ref parse.
597  
    Rules are used with the function @ref parse.
598  
    @code
598  
    @code
599  
    // range    = [ token ] *( "," token )
599  
    // range    = [ token ] *( "," token )
600  

600  

601  
    system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
601  
    system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
602  
        range_rule(
602  
        range_rule(
603  
            token_rule( alpha_chars ),          // first
603  
            token_rule( alpha_chars ),          // first
604  
            tuple_rule(                      // next
604  
            tuple_rule(                      // next
605  
                squelch( delim_rule(',') ),
605  
                squelch( delim_rule(',') ),
606  
                token_rule( alpha_chars ) ) ) );
606  
                token_rule( alpha_chars ) ) ) );
607  
    @endcode
607  
    @endcode
608  

608  

609  
    @par BNF
609  
    @par BNF
610  
    @code
610  
    @code
611  
    range       = <1>*<1>first
611  
    range       = <1>*<1>first
612  
                / first <N-1>*<M-1>next
612  
                / first <N-1>*<M-1>next
613  
    @endcode
613  
    @endcode
614  

614  

615  
    @par Specification
615  
    @par Specification
616  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
616  
    @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
617  
        >3.6.  Variable Repetition (rfc5234)</a>
617  
        >3.6.  Variable Repetition (rfc5234)</a>
618  

618  

619  
    @param first The rule to use for matching
619  
    @param first The rule to use for matching
620  
    the first element. If this rule returns
620  
    the first element. If this rule returns
621  
    an error, the range is empty.
621  
    an error, the range is empty.
622  

622  

623  
    @param next The rule to use for matching
623  
    @param next The rule to use for matching
624  
    each subsequent element. The range extends
624  
    each subsequent element. The range extends
625  
    until this rule returns an error.
625  
    until this rule returns an error.
626  

626  

627  
    @param N The minimum number of elements for
627  
    @param N The minimum number of elements for
628  
    the range to be valid. If omitted, this
628  
    the range to be valid. If omitted, this
629  
    defaults to zero.
629  
    defaults to zero.
630  

630  

631  
    @param M The maximum number of elements for
631  
    @param M The maximum number of elements for
632  
    the range to be valid. If omitted, this
632  
    the range to be valid. If omitted, this
633  
    defaults to unlimited.
633  
    defaults to unlimited.
634  

634  

635  
    @return A rule that matches the range.
635  
    @return A rule that matches the range.
636  

636  

637  
    @see
637  
    @see
638  
        @ref alpha_chars,
638  
        @ref alpha_chars,
639  
        @ref delim_rule,
639  
        @ref delim_rule,
640  
        @ref error::end_of_range,
640  
        @ref error::end_of_range,
641  
        @ref parse,
641  
        @ref parse,
642  
        @ref range,
642  
        @ref range,
643  
        @ref tuple_rule,
643  
        @ref tuple_rule,
644  
        @ref squelch.
644  
        @ref squelch.
645  
*/
645  
*/
646  
template<
646  
template<
647  
    BOOST_URL_CONSTRAINT(Rule) R1,
647  
    BOOST_URL_CONSTRAINT(Rule) R1,
648  
    BOOST_URL_CONSTRAINT(Rule) R2>
648  
    BOOST_URL_CONSTRAINT(Rule) R2>
649  
constexpr
649  
constexpr
650  
auto
650  
auto
651  
range_rule(
651  
range_rule(
652  
    R1 const& first,
652  
    R1 const& first,
653  
    R2 const& next,
653  
    R2 const& next,
654  
    std::size_t N = 0,
654  
    std::size_t N = 0,
655  
    std::size_t M =
655  
    std::size_t M =
656  
        std::size_t(-1)) noexcept ->
656  
        std::size_t(-1)) noexcept ->
657  
#if 1
657  
#if 1
658  
    typename std::enable_if<
658  
    typename std::enable_if<
659  
        ! std::is_integral<R2>::value,
659  
        ! std::is_integral<R2>::value,
660  
        implementation_defined::range_rule_t<R1, R2>>::type
660  
        implementation_defined::range_rule_t<R1, R2>>::type
661  
#else
661  
#else
662  
    range_rule_t<R1, R2>
662  
    range_rule_t<R1, R2>
663  
#endif
663  
#endif
664  
{
664  
{
665  
    // If you get a compile error here it
665  
    // If you get a compile error here it
666  
    // means that your rule does not meet
666  
    // means that your rule does not meet
667  
    // the type requirements. Please check
667  
    // the type requirements. Please check
668  
    // the documentation.
668  
    // the documentation.
669  
    static_assert(
669  
    static_assert(
670  
        is_rule<R1>::value,
670  
        is_rule<R1>::value,
671  
        "Rule requirements not met");
671  
        "Rule requirements not met");
672  
    static_assert(
672  
    static_assert(
673  
        is_rule<R2>::value,
673  
        is_rule<R2>::value,
674  
        "Rule requirements not met");
674  
        "Rule requirements not met");
675  

675  

676  
    // If you get a compile error here it
676  
    // If you get a compile error here it
677  
    // means that your rules do not have
677  
    // means that your rules do not have
678  
    // the exact same value_type. Please
678  
    // the exact same value_type. Please
679  
    // check the documentation.
679  
    // check the documentation.
680  
    static_assert(
680  
    static_assert(
681  
        std::is_same<
681  
        std::is_same<
682  
            typename R1::value_type,
682  
            typename R1::value_type,
683  
            typename R2::value_type>::value,
683  
            typename R2::value_type>::value,
684  
        "Rule requirements not met");
684  
        "Rule requirements not met");
685  

685  

686  
    return implementation_defined::range_rule_t<R1, R2>{
686  
    return implementation_defined::range_rule_t<R1, R2>{
687  
        first, next, N, M};
687  
        first, next, N, M};
688  
}
688  
}
689  

689  

690  
} // grammar
690  
} // grammar
691  
} // urls
691  
} // urls
692  
} // boost
692  
} // boost
693  

693  

694  
#include <boost/url/grammar/impl/range_rule.hpp>
694  
#include <boost/url/grammar/impl/range_rule.hpp>
695  

695  

696  
#endif
696  
#endif