include/boost/url/grammar/impl/range_rule.hpp

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