GCC Code Coverage Report


Directory: libs/url/
File: boost/url/grammar/range_rule.hpp
Date: 2024-08-19 20:08:56
Exec Total Coverage
Lines: 29 29 100.0%
Functions: 21 21 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 //
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
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)
6 //
7 // Official repository: https://github.com/boostorg/url
8 //
9
10 #ifndef BOOST_URL_GRAMMAR_RANGE_RULE_HPP
11 #define BOOST_URL_GRAMMAR_RANGE_RULE_HPP
12
13 #include <boost/url/detail/config.hpp>
14 #include <boost/url/error.hpp>
15 #include <boost/core/detail/string_view.hpp>
16 #include <boost/url/grammar/parse.hpp>
17 #include <boost/url/grammar/type_traits.hpp>
18 #include <boost/static_assert.hpp>
19 #include <cstddef>
20 #include <iterator>
21 #include <type_traits>
22 #include <stddef.h> // ::max_align_t
23
24 namespace boost {
25 namespace urls {
26 namespace grammar {
27 namespace implementation_defined {
28 template<class R0, class R1>
29 struct range_rule_t;
30 } // implementation_defined
31
32 /** A forward range of parsed elements
33
34 Objects of this type are forward ranges
35 returned when parsing using the
36 @ref range_rule.
37 Iteration is performed by re-parsing the
38 underlying character buffer. Ownership
39 of the buffer is not transferred; the
40 caller is responsible for ensuring that
41 the lifetime of the buffer extends until
42 it is no longer referenced by the range.
43
44 @note
45
46 The implementation may use temporary,
47 recycled storage for type-erasure. Objects
48 of type `range` are intended to be used
49 ephemerally. That is, for short durations
50 such as within a function scope. If it is
51 necessary to store the range for a long
52 period of time or with static storage
53 duration, it is necessary to copy the
54 contents to an object of a different type.
55
56 @tparam T The value type of the range
57
58 @see
59 @ref parse,
60 @ref range_rule.
61 */
62 template<class T>
63 class range
64 {
65 // buffer size for type-erased rule
66 static constexpr
67 std::size_t BufferSize = 128;
68
69 struct small_buffer
70 {
71 alignas(alignof(::max_align_t))
72 unsigned char buf[BufferSize];
73
74 707 void const* addr() const noexcept
75 {
76 707 return buf;
77 }
78
79 3317 void* addr() noexcept
80 {
81 3317 return buf;
82 }
83 };
84
85 small_buffer sb_;
86 core::string_view s_;
87 std::size_t n_ = 0;
88
89 //--------------------------------------------
90
91 struct any_rule;
92
93 template<class R, bool>
94 struct impl1;
95
96 template<
97 class R0, class R1, bool>
98 struct impl2;
99
100 template<
101 class R0, class R1>
102 friend struct implementation_defined::range_rule_t;
103
104 any_rule&
105 3317 get() noexcept
106 {
107 return *reinterpret_cast<
108 3317 any_rule*>(sb_.addr());
109 }
110
111 any_rule const&
112 707 get() const noexcept
113 {
114 return *reinterpret_cast<
115 any_rule const*>(
116 707 sb_.addr());
117 }
118
119 template<class R>
120 range(
121 core::string_view s,
122 std::size_t n,
123 R const& r);
124
125 template<
126 class R0, class R1>
127 range(
128 core::string_view s,
129 std::size_t n,
130 R0 const& first,
131 R1 const& next);
132
133 public:
134 /** The type of each element of the range
135 */
136 using value_type = T;
137
138 /** The type of each element of the range
139 */
140 using reference = T const&;
141
142 /** The type of each element of the range
143 */
144 using const_reference = T const&;
145
146 /** Provided for compatibility, unused
147 */
148 using pointer = void const*;
149
150 /** The type used to represent unsigned integers
151 */
152 using size_type = std::size_t;
153
154 /** The type used to represent signed integers
155 */
156 using difference_type = std::ptrdiff_t;
157
158 /** A constant, forward iterator to elements of the range
159 */
160 class iterator;
161
162 /** A constant, forward iterator to elements of the range
163 */
164 using const_iterator = iterator;
165
166 /** Destructor
167 */
168 ~range();
169
170 /** Constructor
171
172 Default-constructed ranges have
173 zero elements.
174
175 @par Exception Safety
176 Throws nothing.
177 */
178 range() noexcept;
179
180 /** Constructor
181
182 The new range references the
183 same underlying character buffer.
184 Ownership is not transferred; the
185 caller is responsible for ensuring
186 that the lifetime of the buffer
187 extends until it is no longer
188 referenced. The moved-from object
189 becomes as if default-constructed.
190
191 @par Exception Safety
192 Throws nothing.
193 */
194 range(range&&) noexcept;
195
196 /** Constructor
197
198 The copy references the same
199 underlying character buffer.
200 Ownership is not transferred; the
201 caller is responsible for ensuring
202 that the lifetime of the buffer
203 extends until it is no longer
204 referenced.
205
206 @par Exception Safety
207 Throws nothing.
208 */
209 range(range const&) noexcept;
210
211 /** Assignment
212
213 After the move, this references the
214 same underlying character buffer. Ownership
215 is not transferred; the caller is responsible
216 for ensuring that the lifetime of the buffer
217 extends until it is no longer referenced.
218 The moved-from object becomes as if
219 default-constructed.
220
221 @par Exception Safety
222 Throws nothing.
223 */
224 range&
225 operator=(range&&) noexcept;
226
227 /** Assignment
228
229 The copy references the same
230 underlying character buffer.
231 Ownership is not transferred; the
232 caller is responsible for ensuring
233 that the lifetime of the buffer
234 extends until it is no longer
235 referenced.
236
237 @par Exception Safety
238 Throws nothing.
239 */
240 range&
241 operator=(range const&) noexcept;
242
243 /** Return an iterator to the beginning
244 */
245 iterator begin() const noexcept;
246
247 /** Return an iterator to the end
248 */
249 iterator end() const noexcept;
250
251 /** Return true if the range is empty
252 */
253 bool
254 11 empty() const noexcept
255 {
256 11 return n_ == 0;
257 }
258
259 /** Return the number of elements in the range
260 */
261 std::size_t
262 34 size() const noexcept
263 {
264 34 return n_;
265 }
266
267 /** Return the matching part of the string
268 */
269 core::string_view
270 19 string() const noexcept
271 {
272 19 return s_;
273 }
274 };
275
276 //------------------------------------------------
277
278 #ifndef BOOST_URL_DOCS
279 namespace implementation_defined {
280 template<
281 class R0,
282 class R1 = void>
283 struct range_rule_t;
284 }
285 #endif
286
287 //------------------------------------------------
288
289 /** Match a repeating number of elements
290
291 Elements are matched using the passed rule.
292 <br>
293 Normally when the rule returns an error,
294 the range ends and the input is rewound to
295 one past the last character that matched
296 successfully. However, if the rule returns
297 the special value @ref error::end_of_range, the
298 input is not rewound. This allows for rules
299 which consume input without producing
300 elements in the range. For example, to
301 relax the grammar for a comma-delimited
302 list by allowing extra commas in between
303 elements.
304
305 @par Value Type
306 @code
307 using value_type = range< typename Rule::value_type >;
308 @endcode
309
310 @par Example
311 Rules are used with the function @ref parse.
312 @code
313 // range = 1*( ";" token )
314
315 system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
316 range_rule(
317 tuple_rule(
318 squelch( delim_rule( ';' ) ),
319 token_rule( alpha_chars ) ),
320 1 ) );
321 @endcode
322
323 @par BNF
324 @code
325 range = <N>*<M>next
326 @endcode
327
328 @par Specification
329 @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
330 >3.6. Variable Repetition (rfc5234)</a>
331
332 @param next The rule to use for matching
333 each element. The range extends until this
334 rule returns an error.
335
336 @param N The minimum number of elements for
337 the range to be valid. If omitted, this
338 defaults to zero.
339
340 @param M The maximum number of elements for
341 the range to be valid. If omitted, this
342 defaults to unlimited.
343
344 @see
345 @ref alpha_chars,
346 @ref delim_rule,
347 @ref error::end_of_range,
348 @ref parse,
349 @ref range,
350 @ref tuple_rule,
351 @ref squelch.
352 */
353 #ifdef BOOST_URL_DOCS
354 template<class Rule>
355 constexpr
356 __implementation_defined__
357 range_rule(
358 Rule next,
359 std::size_t N = 0,
360 std::size_t M =
361 std::size_t(-1)) noexcept;
362 #else
363 namespace implementation_defined {
364 template<class R>
365 struct range_rule_t<R>
366 {
367 using value_type =
368 range<typename R::value_type>;
369
370 system::result<value_type>
371 parse(
372 char const*& it,
373 char const* end) const;
374
375 constexpr
376 18 range_rule_t(
377 R const& next,
378 std::size_t N,
379 std::size_t M) noexcept
380 18 : next_(next)
381 18 , N_(N)
382 18 , M_(M)
383 {
384 18 }
385
386 private:
387 R const next_;
388 std::size_t N_;
389 std::size_t M_;
390 };
391 } // implementation_defined
392
393 /** Match a repeating number of elements
394
395 Elements are matched using the passed rule.
396 <br>
397 Normally when the rule returns an error,
398 the range ends and the input is rewound to
399 one past the last character that matched
400 successfully. However, if the rule returns
401 the special value @ref error::end_of_range, the
402 input is not rewound. This allows for rules
403 which consume input without producing
404 elements in the range. For example, to
405 relax the grammar for a comma-delimited
406 list by allowing extra commas in between
407 elements.
408
409 @par Value Type
410 @code
411 using value_type = range< typename Rule::value_type >;
412 @endcode
413
414 @par Example
415 Rules are used with the function @ref parse.
416 @code
417 // range = 1*( ";" token )
418
419 system::result< range<core::string_view> > rv = parse( ";alpha;xray;charlie",
420 range_rule(
421 tuple_rule(
422 squelch( delim_rule( ';' ) ),
423 token_rule( alpha_chars ) ),
424 1 ) );
425 @endcode
426
427 @par BNF
428 @code
429 range = <N>*<M>next
430 @endcode
431
432 @par Specification
433 @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
434 >3.6. Variable Repetition (rfc5234)</a>
435
436 @param next The rule to use for matching
437 each element. The range extends until this
438 rule returns an error.
439
440 @param N The minimum number of elements for
441 the range to be valid. If omitted, this
442 defaults to zero.
443
444 @param M The maximum number of elements for
445 the range to be valid. If omitted, this
446 defaults to unlimited.
447
448 @see
449 @ref alpha_chars,
450 @ref delim_rule,
451 @ref error::end_of_range,
452 @ref parse,
453 @ref range,
454 @ref tuple_rule,
455 @ref squelch.
456 */
457 template<class Rule>
458 constexpr
459 implementation_defined::range_rule_t<Rule>
460 18 range_rule(
461 Rule const& next,
462 std::size_t N = 0,
463 std::size_t M =
464 std::size_t(-1)) noexcept
465 {
466 // If you get a compile error here it
467 // means that your rule does not meet
468 // the type requirements. Please check
469 // the documentation.
470 static_assert(
471 is_rule<Rule>::value,
472 "Rule requirements not met");
473
474 return implementation_defined::range_rule_t<Rule>{
475 18 next, N, M};
476 }
477 #endif
478
479 //------------------------------------------------
480
481 /** Match a repeating number of elements
482
483 Two rules are used for match. The rule
484 `first` is used for matching the first
485 element, while the `next` rule is used
486 to match every subsequent element.
487 <br>
488 Normally when the rule returns an error,
489 the range ends and the input is rewound to
490 one past the last character that matched
491 successfully. However, if the rule returns
492 the special value @ref error::end_of_range, the
493 input is not rewound. This allows for rules
494 which consume input without producing
495 elements in the range. For example, to
496 relax the grammar for a comma-delimited
497 list by allowing extra commas in between
498 elements.
499
500 @par Value Type
501 @code
502 using value_type = range< typename Rule::value_type >;
503 @endcode
504
505 @par Example
506 Rules are used with the function @ref parse.
507 @code
508 // range = [ token ] *( "," token )
509
510 system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
511 range_rule(
512 token_rule( alpha_chars ), // first
513 tuple_rule( // next
514 squelch( delim_rule(',') ),
515 token_rule( alpha_chars ) ) ) );
516 @endcode
517
518 @par BNF
519 @code
520 range = <1>*<1>first
521 / first <N-1>*<M-1>next
522 @endcode
523
524 @par Specification
525 @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
526 >3.6. Variable Repetition (rfc5234)</a>
527
528 @param first The rule to use for matching
529 the first element. If this rule returns
530 an error, the range is empty.
531
532 @param next The rule to use for matching
533 each subsequent element. The range extends
534 until this rule returns an error.
535
536 @param N The minimum number of elements for
537 the range to be valid. If omitted, this
538 defaults to zero.
539
540 @param M The maximum number of elements for
541 the range to be valid. If omitted, this
542 defaults to unlimited.
543
544 @see
545 @ref alpha_chars,
546 @ref delim_rule,
547 @ref error::end_of_range,
548 @ref parse,
549 @ref range,
550 @ref tuple_rule,
551 @ref squelch.
552 */
553 #ifdef BOOST_URL_DOCS
554 template<
555 class Rule1, class Rule2>
556 constexpr
557 __implementation_defined__
558 range_rule(
559 Rule1 first,
560 Rule2 next,
561 std::size_t N = 0,
562 std::size_t M =
563 std::size_t(-1)) noexcept;
564 #else
565 namespace implementation_defined {
566 template<class R0, class R1>
567 struct range_rule_t
568 {
569 using value_type =
570 range<typename R0::value_type>;
571
572 system::result<value_type>
573 parse(
574 char const*& it,
575 char const* end) const;
576
577 constexpr
578 1 range_rule_t(
579 R0 const& first,
580 R1 const& next,
581 std::size_t N,
582 std::size_t M) noexcept
583 1 : first_(first)
584 1 , next_(next)
585 1 , N_(N)
586 1 , M_(M)
587 {
588 1 }
589
590 private:
591 R0 const first_;
592 R1 const next_;
593 std::size_t N_;
594 std::size_t M_;
595 };
596 } // implementation_defined
597
598 /** Match a repeating number of elements
599
600 Two rules are used for match. The rule
601 `first` is used for matching the first
602 element, while the `next` rule is used
603 to match every subsequent element.
604 <br>
605 Normally when the rule returns an error,
606 the range ends and the input is rewound to
607 one past the last character that matched
608 successfully. However, if the rule returns
609 the special value @ref error::end_of_range, the
610 input is not rewound. This allows for rules
611 which consume input without producing
612 elements in the range. For example, to
613 relax the grammar for a comma-delimited
614 list by allowing extra commas in between
615 elements.
616
617 @par Value Type
618 @code
619 using value_type = range< typename Rule::value_type >;
620 @endcode
621
622 @par Example
623 Rules are used with the function @ref parse.
624 @code
625 // range = [ token ] *( "," token )
626
627 system::result< range< core::string_view > > rv = parse( "whiskey,tango,foxtrot",
628 range_rule(
629 token_rule( alpha_chars ), // first
630 tuple_rule( // next
631 squelch( delim_rule(',') ),
632 token_rule( alpha_chars ) ) ) );
633 @endcode
634
635 @par BNF
636 @code
637 range = <1>*<1>first
638 / first <N-1>*<M-1>next
639 @endcode
640
641 @par Specification
642 @li <a href="https://datatracker.ietf.org/doc/html/rfc5234#section-3.6"
643 >3.6. Variable Repetition (rfc5234)</a>
644
645 @param first The rule to use for matching
646 the first element. If this rule returns
647 an error, the range is empty.
648
649 @param next The rule to use for matching
650 each subsequent element. The range extends
651 until this rule returns an error.
652
653 @param N The minimum number of elements for
654 the range to be valid. If omitted, this
655 defaults to zero.
656
657 @param M The maximum number of elements for
658 the range to be valid. If omitted, this
659 defaults to unlimited.
660
661 @see
662 @ref alpha_chars,
663 @ref delim_rule,
664 @ref error::end_of_range,
665 @ref parse,
666 @ref range,
667 @ref tuple_rule,
668 @ref squelch.
669 */
670 template<
671 class Rule1, class Rule2>
672 constexpr
673 auto
674 1 range_rule(
675 Rule1 const& first,
676 Rule2 const& next,
677 std::size_t N = 0,
678 std::size_t M =
679 std::size_t(-1)) noexcept ->
680 #if 1
681 typename std::enable_if<
682 ! std::is_integral<Rule2>::value,
683 implementation_defined::range_rule_t<Rule1, Rule2>>::type
684 #else
685 range_rule_t<Rule1, Rule2>
686 #endif
687 {
688 // If you get a compile error here it
689 // means that your rule does not meet
690 // the type requirements. Please check
691 // the documentation.
692 static_assert(
693 is_rule<Rule1>::value,
694 "Rule requirements not met");
695 static_assert(
696 is_rule<Rule2>::value,
697 "Rule requirements not met");
698
699 // If you get a compile error here it
700 // means that your rules do not have
701 // the exact same value_type. Please
702 // check the documentation.
703 static_assert(
704 std::is_same<
705 typename Rule1::value_type,
706 typename Rule2::value_type>::value,
707 "Rule requirements not met");
708
709 return implementation_defined::range_rule_t<Rule1, Rule2>{
710 1 first, next, N, M};
711 }
712 #endif
713
714 } // grammar
715 } // urls
716 } // boost
717
718 #include <boost/url/grammar/impl/range_rule.hpp>
719
720 #endif
721