GCC Code Coverage Report


Directory: libs/url/
File: boost/url/grammar/impl/range_rule.hpp
Date: 2024-03-15 19:37:09
Exec Total Coverage
Lines: 224 234 95.7%
Functions: 94 116 81.0%
Branches: 30 46 65.2%

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