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  
    BOOST_URL_CXX20_CONSTEXPR
427  
    BOOST_URL_CXX20_CONSTEXPR
428  
    system::result<value_type>
428  
    system::result<value_type>
429  
    parse(
429  
    parse(
430  
        char const*& it,
430  
        char const*& it,
431  
        char const* end) const;
431  
        char const* end) const;
432  

432  

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

443  

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

450  

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

452  

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

466  

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

471  

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

476  

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

484  

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

489  

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

493  

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

497  

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

501  

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

505  

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

507  

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

533  

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

537  

538  
//------------------------------------------------
538  
//------------------------------------------------
539  

539  

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

546  

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

552  

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

565  

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

573  

574  
/** Match a repeating number of elements
574  
/** Match a repeating number of elements
575  

575  

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

592  

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

597  

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

602  

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

610  

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

616  

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

620  

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

624  

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

628  

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

632  

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

636  

637  
    @return A rule that matches the range.
637  
    @return A rule that matches the range.
638  

638  

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

677  

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

687  

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

691  

692  
} // grammar
692  
} // grammar
693  
} // urls
693  
} // urls
694  
} // boost
694  
} // boost
695  

695  

696  
#include <boost/url/grammar/impl/range_rule.hpp>
696  
#include <boost/url/grammar/impl/range_rule.hpp>
697  

697  

698  
#endif
698  
#endif