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