Line data 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 : 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 25 : it, end, next_);
759 25 : if( !rv )
760 : {
761 3 : if(rv.error() != error::end_of_range)
762 : {
763 : // rewind unless error::end_of_range
764 3 : it = it1;
765 : }
766 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 53 : it, end, next_);
783 53 : if( !rv )
784 : {
785 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 35 : if(n >= M_)
793 : {
794 : // too many
795 4 : BOOST_URL_CONSTEXPR_RETURN_EC(
796 : error::mismatch);
797 : }
798 : }
799 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 131 : if( !rv )
830 : {
831 4 : if(rv.error() != error::end_of_range)
832 : {
833 4 : it = it1;
834 : }
835 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 363 : it, end, next_);
850 363 : if( !rv )
851 : {
852 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 240 : if(n >= M_)
860 : {
861 : // too many
862 4 : BOOST_URL_CONSTEXPR_RETURN_EC(
863 : error::mismatch);
864 : }
865 : }
866 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
|