GCC Code Coverage Report


Directory: libs/url/
File: include/boost/url/grammar/impl/range_rule.hpp
Date: 2025-11-10 19:06:22
Exec Total Coverage
Lines: 267 269 99.3%
Functions: 132 158 83.5%
Branches: 37 54 68.5%

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