GCC Code Coverage Report


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