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

100.0% Lines (269/269) 87.0% Functions (120/138)
include/boost/url/grammar/impl/range_rule.hpp
Line TLA 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 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 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 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 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 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 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 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 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 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 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 BOOST_URL_CXX20_CONSTEXPR
746 auto
747 25 implementation_defined::range_rule_t<R>::
748 parse(
749 char const*& it,
750 char const* end) const ->
751 system::result<value_type>
752 {
753 using T = typename R::value_type;
754
755 25 std::size_t n = 0;
756 25 auto const it0 = it;
757 25 auto it1 = it;
758 25 auto rv = (grammar::parse)(
759 25 it, end, next_);
760 25 if( !rv )
761 {
762 3 if(rv.error() != error::end_of_range)
763 {
764 // rewind unless error::end_of_range
765 3 it = it1;
766 }
767 3 if(n < N_)
768 {
769 // too few
770 2 BOOST_URL_CONSTEXPR_RETURN_EC(
771 error::mismatch);
772 }
773 // good
774 2 return range<T>(
775 1 core::string_view(it0, it - it0),
776 3 n, any_rule<T>(next_));
777 }
778 31 for(;;)
779 {
780 53 ++n;
781 53 it1 = it;
782 53 rv = (grammar::parse)(
783 53 it, end, next_);
784 53 if( !rv )
785 {
786 18 if(rv.error() != error::end_of_range)
787 {
788 // rewind unless error::end_of_range
789 18 it = it1;
790 }
791 18 break;
792 }
793 35 if(n >= M_)
794 {
795 // too many
796 4 BOOST_URL_CONSTEXPR_RETURN_EC(
797 error::mismatch);
798 }
799 }
800 18 if(n < N_)
801 {
802 // too few
803 2 BOOST_URL_CONSTEXPR_RETURN_EC(
804 error::mismatch);
805 }
806 // good
807 32 return range<T>(
808 16 core::string_view(it0, it - it0),
809 48 n, any_rule<T>(next_));
810 }
811
812 //------------------------------------------------
813
814 template<class R0, class R1>
815 BOOST_URL_CXX20_CONSTEXPR
816 auto
817 131 implementation_defined::range_rule_t<R0, R1>::
818 parse(
819 char const*& it,
820 char const* end) const ->
821 system::result<range<typename
822 R0::value_type>>
823 {
824 using T = typename R0::value_type;
825
826 131 std::size_t n = 0;
827 131 auto const it0 = it;
828 131 auto it1 = it;
829 131 auto rv = (grammar::parse)(
830 131 it, end, first_);
831 131 if( !rv )
832 {
833 4 if(rv.error() != error::end_of_range)
834 {
835 4 it = it1;
836 }
837 4 if(n < N_)
838 {
839 3 BOOST_URL_CONSTEXPR_RETURN_EC(
840 error::mismatch);
841 }
842 2 return range<T>(
843 1 core::string_view(it0, it - it0),
844 3 n, any_rule<T>(first_, next_));
845 }
846 236 for(;;)
847 {
848 363 ++n;
849 363 it1 = it;
850 363 rv = (grammar::parse)(
851 363 it, end, next_);
852 363 if( !rv )
853 {
854 123 if(rv.error() != error::end_of_range)
855 {
856 // rewind unless error::end_of_range
857 123 it = it1;
858 }
859 123 break;
860 }
861 240 if(n >= M_)
862 {
863 // too many
864 4 BOOST_URL_CONSTEXPR_RETURN_EC(
865 error::mismatch);
866 }
867 }
868 123 if(n < N_)
869 {
870 // too few
871 1 BOOST_URL_CONSTEXPR_RETURN_EC(
872 error::mismatch);
873 }
874 // good
875 244 return range<T>(
876 122 core::string_view(it0, it - it0),
877 366 n, any_rule<T>(first_, next_));
878 113 }
879
880 } // grammar
881 } // urls
882 } // boost
883
884 #endif
885