-
Notifications
You must be signed in to change notification settings - Fork 50
/
range_rule.hpp
720 lines (607 loc) · 17.4 KB
/
range_rule.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
//
// 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 {
namespace implementation_defined {
template<class R0, class R1>
struct range_rule_t;
} // implementation_defined
/** 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 implementation_defined::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
namespace implementation_defined {
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
namespace implementation_defined {
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;
constexpr
range_rule_t(
R const& next,
std::size_t N,
std::size_t M) noexcept
: next_(next)
, N_(N)
, M_(M)
{
}
private:
R const next_;
std::size_t N_;
std::size_t M_;
};
} // implementation_defined
/** 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.
*/
template<class Rule>
constexpr
implementation_defined::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 implementation_defined::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
namespace implementation_defined {
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;
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)
{
}
private:
R0 const first_;
R1 const next_;
std::size_t N_;
std::size_t M_;
};
} // implementation_defined
/** 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.
*/
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,
implementation_defined::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 implementation_defined::range_rule_t<Rule1, Rule2>{
first, next, N, M};
}
#endif
} // grammar
} // urls
} // boost
#include <boost/url/grammar/impl/range_rule.hpp>
#endif