Line data Source code
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 1068 : ~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 25 : impl1(R const& next) noexcept
88 : : empty_value<R>(
89 : empty_init,
90 25 : next)
91 : {
92 25 : }
93 :
94 : private:
95 71 : impl1(impl1&&) noexcept = default;
96 2 : impl1(impl1 const&) noexcept = default;
97 :
98 : void
99 71 : move(void* dest
100 : ) noexcept override
101 : {
102 142 : ::new(dest) impl1(
103 71 : std::move(*this));
104 71 : }
105 :
106 : void
107 2 : copy(void* dest
108 : ) const noexcept override
109 : {
110 2 : ::new(dest) impl1(*this);
111 2 : }
112 :
113 : system::result<T>
114 5 : first(
115 : char const*& it,
116 : char const* end)
117 : const noexcept override
118 : {
119 5 : return grammar::parse(
120 5 : it, end, this->get());
121 : }
122 :
123 : system::result<T>
124 8 : next(
125 : char const*& it,
126 : char const* end)
127 : const noexcept override
128 : {
129 8 : return grammar::parse(
130 8 : 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 21 : ~impl1()
168 : {
169 21 : if(p_)
170 7 : get().~impl();
171 42 : }
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 4 : impl2(
282 : R0 const& first,
283 : R1 const& next) noexcept
284 4 : {
285 4 : ::new(p_->addr()) impl{
286 : first, next};
287 4 : }
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 14 : impl2(impl2&&) noexcept = default;
300 2 : impl2(impl2 const&) noexcept = default;
301 :
302 : impl const&
303 13 : get() const noexcept
304 : {
305 : return *reinterpret_cast<
306 13 : impl const*>(p_->addr());
307 : }
308 :
309 20 : ~impl2()
310 : {
311 20 : if(p_)
312 6 : get().~impl();
313 40 : }
314 :
315 : void
316 14 : move(void* dest
317 : ) noexcept override
318 : {
319 28 : ::new(dest) impl2(
320 14 : std::move(*this));
321 14 : }
322 :
323 : void
324 2 : copy(void* dest
325 : ) const noexcept override
326 : {
327 2 : ::new(dest) impl2(*this);
328 2 : }
329 :
330 : system::result<T>
331 2 : first(
332 : char const*& it,
333 : char const* end)
334 : const noexcept override
335 : {
336 2 : return grammar::parse(
337 2 : it, end, get().first);
338 : }
339 :
340 : system::result<T>
341 5 : next(
342 : char const*& it,
343 : char const* end)
344 : const noexcept override
345 : {
346 5 : return grammar::parse(
347 5 : 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 : if(this == &other)
405 0 : 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 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 30 : 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 30 : ::new(sb_.addr()) impl1<R,
451 : sizeof(impl1<R, true>) <=
452 : BufferSize>(next);
453 30 : }
454 :
455 : //------------------------------------------------
456 :
457 : template<class T>
458 : template<
459 : class R0, class R1>
460 123 : 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 123 : ::new(sb_.addr()) impl2<R0, R1,
483 : sizeof(impl2<R0, R1, true>
484 : ) <= BufferSize>(
485 : first, next);
486 123 : }
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 : if(this == &other)
557 0 : 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 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 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 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 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 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 41 : 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 41 : std::size_t n = 0;
754 41 : auto const it0 = it;
755 41 : auto it1 = it;
756 41 : auto rv = (grammar::parse)(
757 41 : it, end, next_);
758 41 : if( !rv )
759 : {
760 7 : if(rv.error() != error::end_of_range)
761 : {
762 : // rewind unless error::end_of_range
763 7 : it = it1;
764 : }
765 7 : if(n < N_)
766 : {
767 : // too few
768 6 : BOOST_URL_RETURN_EC(
769 : error::mismatch);
770 : }
771 : // good
772 2 : return range<T>(
773 1 : core::string_view(it0, it - it0),
774 3 : n, any_rule<T>(next_));
775 : }
776 34 : for(;;)
777 : {
778 68 : ++n;
779 68 : it1 = it;
780 68 : rv = (grammar::parse)(
781 68 : it, end, next_);
782 68 : if( !rv )
783 : {
784 30 : if(rv.error() != error::end_of_range)
785 : {
786 : // rewind unless error::end_of_range
787 30 : it = it1;
788 : }
789 30 : break;
790 : }
791 38 : if(n >= M_)
792 : {
793 : // too many
794 4 : BOOST_URL_RETURN_EC(
795 : error::mismatch);
796 : }
797 : }
798 30 : if(n < N_)
799 : {
800 : // too few
801 2 : BOOST_URL_RETURN_EC(
802 : error::mismatch);
803 : }
804 : // good
805 56 : return range<T>(
806 28 : core::string_view(it0, it - it0),
807 84 : 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 131 : if( !rv )
829 : {
830 4 : if(rv.error() != error::end_of_range)
831 : {
832 4 : it = it1;
833 : }
834 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 363 : it, end, next_);
849 363 : if( !rv )
850 : {
851 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 240 : if(n >= M_)
859 : {
860 : // too many
861 4 : BOOST_URL_RETURN_EC(
862 : error::mismatch);
863 : }
864 : }
865 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
|