Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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/CPPAlliance/http_proto
8 : //
9 :
10 : #ifndef BOOST_HTTP_PROTO_BUFFER_HPP
11 : #define BOOST_HTTP_PROTO_BUFFER_HPP
12 :
13 : #include <boost/http_proto/detail/config.hpp>
14 : #include <boost/assert.hpp>
15 : #include <boost/config/workaround.hpp>
16 : #include <boost/type_traits/make_void.hpp>
17 : #include <cstdlib>
18 : #include <cstring>
19 : #include <iterator>
20 : #include <type_traits>
21 : #include <utility>
22 :
23 : namespace boost {
24 : namespace http_proto {
25 :
26 : /** size tag for tag_invoke.
27 : */
28 : struct size_tag {};
29 :
30 : /** prefix tag for tag_invoke.
31 : */
32 : struct prefix_tag {};
33 :
34 : /** suffix tag for tag-invoke.
35 : */
36 : struct suffix_tag {};
37 :
38 : //------------------------------------------------
39 :
40 : /** Holds a buffer that can be modified.
41 : */
42 : class mutable_buffer
43 : {
44 : unsigned char* p_ = nullptr;
45 : std::size_t n_ = 0;
46 :
47 : public:
48 : using value_type = mutable_buffer;
49 : using const_iterator =
50 : value_type const*;
51 :
52 3187 : mutable_buffer() = default;
53 : mutable_buffer(
54 : mutable_buffer const&) = default;
55 : mutable_buffer& operator=(
56 : mutable_buffer const&) = default;
57 :
58 8333 : mutable_buffer(
59 : void* data,
60 : std::size_t size) noexcept
61 8333 : : p_(static_cast<
62 : unsigned char*>(data))
63 8333 : , n_(size)
64 : {
65 8333 : }
66 :
67 : #ifndef BOOST_HTTP_PROTO_DOCS
68 : // conversion to boost::asio::mutable_buffer
69 : template<
70 : class T
71 : , class = typename std::enable_if<
72 : std::is_constructible<T,
73 : void*, std::size_t>::value
74 : && ! std::is_same<T, mutable_buffer>::value
75 : //&& ! std::is_same<T, const_buffer>::value
76 : >::type
77 : >
78 : operator T() const noexcept
79 : {
80 : return T{ data(), size() };
81 : }
82 : #endif
83 :
84 : void*
85 7884 : data() const noexcept
86 : {
87 7884 : return p_;
88 : }
89 :
90 : std::size_t
91 23271 : size() const noexcept
92 : {
93 23271 : return n_;
94 : }
95 :
96 : const_iterator
97 56 : begin() const noexcept
98 : {
99 56 : return this;
100 : }
101 :
102 : const_iterator
103 56 : end() const noexcept
104 : {
105 56 : return this + 1;
106 : }
107 :
108 : /** Remove a prefix from the buffer.
109 : */
110 : mutable_buffer&
111 4848 : operator+=(std::size_t n) noexcept
112 : {
113 4848 : if(n >= n_)
114 : {
115 33 : p_ = p_ + n_;
116 33 : n_ = 0;
117 33 : return *this;
118 : }
119 4815 : p_ = p_ + n;
120 4815 : n_ -= n;
121 4815 : return *this;
122 : }
123 :
124 : /** Return the buffer with a prefix removed.
125 : */
126 : friend
127 : mutable_buffer
128 4844 : operator+(
129 : mutable_buffer b,
130 : std::size_t n) noexcept
131 : {
132 4844 : return b += n;
133 : }
134 :
135 : /** Return the buffer with a prefix removed.
136 : */
137 : friend
138 : mutable_buffer
139 1 : operator+(
140 : std::size_t n,
141 : mutable_buffer b) noexcept
142 : {
143 1 : return b += n;
144 : }
145 :
146 : #ifndef BOOST_HTTP_PROTO_DOCS
147 : friend
148 : mutable_buffer
149 2 : tag_invoke(
150 : prefix_tag const&,
151 : mutable_buffer const& b,
152 : std::size_t n) noexcept
153 : {
154 2 : if(n < b.size())
155 2 : return { b.p_, n };
156 0 : return b;
157 : }
158 :
159 : friend
160 : mutable_buffer
161 2 : tag_invoke(
162 : suffix_tag const&,
163 : mutable_buffer const& b,
164 : std::size_t n) noexcept
165 : {
166 2 : if(n < b.size())
167 2 : return { b.p_ + b.n_ - n, n };
168 0 : return b;
169 : }
170 : #endif
171 : };
172 :
173 : //------------------------------------------------
174 :
175 : /** Holds a buffer that cannot be modified.
176 : */
177 : class const_buffer
178 : {
179 : unsigned char const* p_ = nullptr;
180 : std::size_t n_ = 0;
181 :
182 : public:
183 : using value_type = const_buffer;
184 : using const_iterator =
185 : value_type const*;
186 :
187 29 : const_buffer() = default;
188 : const_buffer(
189 : const_buffer const&) = default;
190 : const_buffer& operator=(
191 : const_buffer const&) = default;
192 :
193 5326 : const_buffer(
194 : void const* data,
195 : std::size_t size) noexcept
196 5326 : : p_(static_cast<
197 : unsigned char const*>(data))
198 5326 : , n_(size)
199 : {
200 5326 : }
201 :
202 14 : const_buffer(
203 : mutable_buffer const& b) noexcept
204 14 : : p_(static_cast<
205 14 : unsigned char const*>(b.data()))
206 14 : , n_(b.size())
207 : {
208 14 : }
209 :
210 : #ifndef BOOST_HTTP_PROTO_DOCS
211 : // conversion to boost::asio::const_buffer
212 : template<
213 : class T
214 : , class = typename std::enable_if<
215 : std::is_constructible<T,
216 : void const*, std::size_t>::value &&
217 : ! std::is_same<T, mutable_buffer>::value &&
218 : ! std::is_same<T, const_buffer>::value
219 : >::type
220 : >
221 : operator T() const noexcept
222 : {
223 : return T{ data(), size() };
224 : }
225 : #endif
226 :
227 : void const*
228 4851 : data() const noexcept
229 : {
230 4851 : return p_;
231 : }
232 :
233 : std::size_t
234 15078 : size() const noexcept
235 : {
236 15078 : return n_;
237 : }
238 :
239 : const_iterator
240 216 : begin() const noexcept
241 : {
242 216 : return this;
243 : }
244 :
245 : const_iterator
246 216 : end() const noexcept
247 : {
248 216 : return this + 1;
249 : }
250 :
251 : /** Remove a prefix from the buffer.
252 : */
253 : const_buffer&
254 4847 : operator+=(std::size_t n) noexcept
255 : {
256 4847 : if(n >= n_)
257 : {
258 33 : p_ = p_ + n_;
259 33 : n_ = 0;
260 33 : return *this;
261 : }
262 4814 : p_ = p_ + n;
263 4814 : n_ -= n;
264 4814 : return *this;
265 : }
266 :
267 : /** Return the buffer with a prefix removed.
268 : */
269 : friend
270 : const_buffer
271 4844 : operator+(
272 : const_buffer b,
273 : std::size_t n) noexcept
274 : {
275 4844 : return b += n;
276 : }
277 :
278 : /** Return the buffer with a prefix removed.
279 : */
280 : friend
281 : const_buffer
282 1 : operator+(
283 : std::size_t n,
284 : const_buffer b) noexcept
285 : {
286 1 : return b += n;
287 : }
288 :
289 : #ifndef BOOST_HTTP_PROTO_DOCS
290 : friend
291 : const_buffer
292 2 : tag_invoke(
293 : prefix_tag const&,
294 : const_buffer const& b,
295 : std::size_t n) noexcept
296 : {
297 2 : if(n < b.size())
298 2 : return { b.p_, n };
299 0 : return b;
300 : }
301 :
302 : friend
303 : const_buffer
304 2 : tag_invoke(
305 : suffix_tag const&,
306 : const_buffer const& b,
307 : std::size_t n) noexcept
308 : {
309 2 : if(n < b.size())
310 2 : return { b.p_ + b.n_ - n, n };
311 0 : return b;
312 : }
313 : #endif
314 : };
315 :
316 : //------------------------------------------------
317 :
318 : #ifndef BOOST_HTTP_PROTO_DOCS
319 : namespace detail {
320 :
321 : // is bidirectional iterator
322 : template<class T, class = void>
323 : struct is_bidir_iter : std::false_type
324 : {
325 : };
326 :
327 : template<class T>
328 : struct is_bidir_iter<T, boost::void_t<decltype(
329 : // LegacyIterator
330 : *std::declval<T&>()
331 : ),
332 : // LegacyIterator
333 : typename std::iterator_traits<T>::value_type,
334 : typename std::iterator_traits<T>::difference_type,
335 : typename std::iterator_traits<T>::reference,
336 : typename std::iterator_traits<T>::pointer,
337 : typename std::iterator_traits<T>::iterator_category,
338 : typename std::enable_if<
339 : // LegacyIterator
340 : std::is_copy_constructible<T>::value &&
341 : std::is_copy_assignable<T>::value &&
342 : std::is_destructible<T>::value &&
343 : std::is_same<T&, decltype(
344 : ++std::declval<T&>())>::value &&
345 : // Swappable
346 : // VFALCO TODO
347 : // EqualityComparable
348 : std::is_convertible<decltype(
349 : std::declval<T const&>() ==
350 : std::declval<T const&>()),
351 : bool>::value &&
352 : // LegacyInputIterator
353 : std::is_convertible<typename
354 : std::iterator_traits<T>::reference, typename
355 : std::iterator_traits<T>::value_type>::value &&
356 : std::is_same<typename
357 : std::iterator_traits<T>::reference,
358 : decltype(*std::declval<T const&>())>::value &&
359 : std::is_convertible<decltype(
360 : std::declval<T const&>() !=
361 : std::declval<T const&>()),
362 : bool>::value &&
363 : std::is_same<T&, decltype(
364 : ++std::declval<T&>())>::value &&
365 : // VFALCO (void)r++ (void)++r
366 : std::is_convertible<decltype(
367 : *std::declval<T&>()++), typename
368 : std::iterator_traits<T>::value_type>::value &&
369 : // LegacyForwardIterator
370 : std::is_default_constructible<T>::value &&
371 : std::is_same<T, decltype(
372 : std::declval<T&>()++)>::value &&
373 : std::is_same<typename
374 : std::iterator_traits<T>::reference,
375 : decltype(*std::declval<T&>()++)
376 : >::value &&
377 : // LegacyBidirectionalIterator
378 : std::is_same<T&, decltype(
379 : --std::declval<T&>())>::value &&
380 : std::is_convertible<decltype(
381 : std::declval<T&>()--),
382 : T const&>::value &&
383 : std::is_same<typename
384 : std::iterator_traits<T>::reference,
385 : decltype(*std::declval<T&>()--)>::value
386 : >::type >>
387 : : std::true_type
388 : {
389 : };
390 :
391 : } // detail
392 : #endif
393 :
394 : //------------------------------------------------
395 :
396 : // https://www.boost.org/doc/libs/1_65_0/doc/html/boost_asio/reference/ConstBufferSequence.html
397 :
398 : /** Determine if T is a ConstBuffers.
399 : */
400 : #if BOOST_HTTP_PROTO_DOCS
401 : template<class T>
402 : struct is_const_buffers
403 : : std::integral_constant<bool, ...>{};
404 : #else
405 :
406 : template<class T, class = void>
407 : struct is_const_buffers : std::false_type
408 : {
409 : };
410 :
411 : template<class T>
412 : struct is_const_buffers<T const>
413 : : is_const_buffers<typename
414 : std::decay<T>::type>
415 : {
416 : };
417 :
418 : template<class T>
419 : struct is_const_buffers<T const&>
420 : : is_const_buffers<typename
421 : std::decay<T>::type>
422 : {
423 : };
424 :
425 : template<class T>
426 : struct is_const_buffers<T&>
427 : : is_const_buffers<typename
428 : std::decay<T>::type>
429 : {
430 : };
431 :
432 : template<class T>
433 : struct is_const_buffers<T, boost::void_t<
434 : typename std::enable_if<
435 : (std::is_same<const_buffer, typename
436 : T::value_type>::value
437 : || std::is_same<mutable_buffer, typename
438 : T::value_type>::value
439 : ) &&
440 : detail::is_bidir_iter<typename
441 : T::const_iterator>::value &&
442 : std::is_same<typename
443 : T::const_iterator, decltype(
444 : std::declval<T const&>().begin())
445 : >::value &&
446 : std::is_same<typename
447 : T::const_iterator, decltype(
448 : std::declval<T const&>().end())
449 : >::value && (
450 : std::is_same<const_buffer, typename
451 : std::remove_const<typename
452 : std::iterator_traits<
453 : typename T::const_iterator
454 : >::value_type>::type
455 : >::value ||
456 : std::is_same<mutable_buffer, typename
457 : std::remove_const<typename
458 : std::iterator_traits<
459 : typename T::const_iterator
460 : >::value_type>::type
461 : >::value)
462 : >::type
463 : > > : std::is_move_constructible<T>
464 : {
465 : };
466 :
467 : #endif
468 :
469 : /** Determine if T is a MutableBuffers.
470 : */
471 : #if BOOST_HTTP_PROTO_DOCS
472 : template<class T>
473 : struct is_mutable_buffers
474 : : std::integral_constant<bool, ...>{};
475 : #else
476 :
477 : template<class T, class = void>
478 : struct is_mutable_buffers : std::false_type
479 : {
480 : };
481 :
482 : template<class T>
483 : struct is_mutable_buffers<T const>
484 : : is_mutable_buffers<typename
485 : std::decay<T>::type>
486 : {
487 : };
488 :
489 : template<class T>
490 : struct is_mutable_buffers<T const&>
491 : : is_mutable_buffers<typename
492 : std::decay<T>::type>
493 : {
494 : };
495 :
496 : template<class T>
497 : struct is_mutable_buffers<T&>
498 : : is_mutable_buffers<typename
499 : std::decay<T>::type>
500 : {
501 : };
502 :
503 : template<class T>
504 : struct is_mutable_buffers<T, boost::void_t<
505 : typename std::enable_if<
506 : detail::is_bidir_iter<typename
507 : T::const_iterator>::value &&
508 : std::is_same<typename
509 : T::const_iterator, decltype(
510 : std::declval<T const&>().begin())
511 : >::value &&
512 : std::is_same<typename
513 : T::const_iterator, decltype(
514 : std::declval<T const&>().end())
515 : >::value &&
516 : std::is_same<mutable_buffer, typename
517 : std::remove_const<typename
518 : std::iterator_traits<
519 : typename T::const_iterator
520 : >::value_type>::type
521 : >::value
522 : >::type
523 : >> : std::is_move_constructible<T>
524 : {
525 : };
526 :
527 : #endif
528 :
529 : //------------------------------------------------
530 :
531 : /** Determine if T is a DynamicBuffer
532 : */
533 : #if BOOST_HTTP_PROTO_DOCS
534 : template<class T>
535 : struct is_dynamic_buffer
536 : : std::integral_constant<bool, ...>{};
537 : #else
538 :
539 : template<
540 : class T,
541 : class = void>
542 : struct is_dynamic_buffer : std::false_type {};
543 :
544 : template<class T>
545 : struct is_dynamic_buffer<
546 : T, boost::void_t<decltype(
547 : std::declval<std::size_t&>() =
548 : std::declval<T const&>().size()
549 : ,std::declval<std::size_t&>() =
550 : std::declval<T const&>().max_size()
551 : ,std::declval<std::size_t&>() =
552 : std::declval<T const&>().capacity()
553 : ,std::declval<T&>().commit(
554 : std::declval<std::size_t>())
555 : ,std::declval<T&>().consume(
556 : std::declval<std::size_t>())
557 : )
558 : ,typename std::enable_if<
559 : is_const_buffers<typename
560 : T::const_buffers_type>::value
561 : && is_mutable_buffers<typename
562 : T::mutable_buffers_type>::value
563 : >::type
564 : ,typename std::enable_if<
565 : std::is_same<decltype(
566 : std::declval<T const&>().data()),
567 : typename T::const_buffers_type>::value
568 : && std::is_same<decltype(
569 : std::declval<T&>().prepare(
570 : std::declval<std::size_t>())),
571 : typename T::mutable_buffers_type>::value
572 : >::type
573 : > > : std::true_type
574 : {
575 : };
576 :
577 : #endif
578 :
579 : //------------------------------------------------
580 :
581 : #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
582 : # pragma warning (push)
583 : # pragma warning (disable: 4521) // multiple copy constructors specified
584 : # pragma warning (disable: 4522) // multiple assignment operators specified
585 : #endif
586 :
587 : template<bool isConst>
588 : class buffers_pair
589 : {
590 : public:
591 : // VFALCO: This type is public otherwise
592 : // asio::buffers_iterator won't compile.
593 : using value_type = typename
594 : std::conditional<isConst,
595 : const_buffer,
596 : mutable_buffer>::type;
597 :
598 : using const_iterator = value_type const*;
599 :
600 0 : buffers_pair() = default;
601 :
602 : #if defined(BOOST_HTTP_PROTO_DOCS) || ( \
603 : ! BOOST_WORKAROUND(BOOST_MSVC, < 1910))
604 : buffers_pair(
605 : buffers_pair const& other) = default;
606 : buffers_pair& operator=(
607 : buffers_pair const& other) = default;
608 :
609 : #else
610 : buffers_pair(
611 : buffers_pair const& other) noexcept
612 : : buffers_pair(
613 : *other.begin(),
614 : *(other.begin() + 1))
615 : {
616 : }
617 :
618 : buffers_pair&
619 : operator=(buffers_pair const& other)
620 : {
621 : b_[0] = other.b_[0];
622 : b_[1] = other.b_[1];
623 : return *this;
624 : }
625 : #endif
626 :
627 : // const pair construction
628 : // from mutable mutable pair
629 : template<
630 : bool isConst_ = isConst,
631 : class = typename std::enable_if<
632 : isConst_>::type>
633 : buffers_pair(
634 : buffers_pair<false> const& other)
635 : : buffers_pair(
636 : other.b_[0],
637 : other.b_[1])
638 : {
639 : }
640 :
641 : // const pair assignment
642 : // from mutable mutable pair
643 : template<
644 : bool isConst_ = isConst,
645 : class = typename std::enable_if<
646 : isConst_>::type>
647 : buffers_pair&
648 : operator=(
649 : buffers_pair<false> const& other)
650 : {
651 : b_[0] = other.b_[0];
652 : b_[1] = other.b_[1];
653 : return *this;
654 : }
655 :
656 8267 : buffers_pair(
657 : value_type b0,
658 : value_type b1) noexcept
659 8267 : {
660 8267 : if(b0.size() > 0)
661 : {
662 7877 : b_[0] = b0;
663 7877 : b_[1] = b1;
664 : }
665 : else
666 : {
667 390 : b_[0] = b1;
668 : }
669 8267 : }
670 :
671 : const_buffer
672 : operator[](
673 : std::size_t i) const noexcept
674 : {
675 : BOOST_ASSERT(i < 2);
676 : return b_[i];
677 : }
678 :
679 : const_iterator
680 8270 : begin() const noexcept
681 : {
682 8270 : return b_;
683 : }
684 :
685 : const_iterator
686 5249 : end() const noexcept
687 : {
688 5249 : if(b_[1].size() > 0)
689 4681 : return &b_[2];
690 568 : if(b_[0].size() > 0)
691 568 : return &b_[1];
692 0 : return b_;
693 : }
694 :
695 : private:
696 : value_type b_[2];
697 : };
698 :
699 : #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
700 : # pragma warning (pop)
701 : #endif
702 :
703 : /** A mutable buffers pair
704 : */
705 : using mutable_buffers_pair =
706 : buffers_pair<false>;
707 :
708 : /** A const buffers pair
709 : */
710 : using const_buffers_pair =
711 : buffers_pair<true>;
712 :
713 : //------------------------------------------------
714 :
715 : /** Return the total octets in a buffer sequence
716 : */
717 : template<
718 : class ConstBuffers
719 : #ifndef BOOST_HTTP_PROTO_DOCS
720 : , class = typename std::enable_if<
721 : is_const_buffers<ConstBuffers>::value
722 : >::type
723 : #endif
724 : >
725 : std::size_t
726 25 : buffer_size(
727 : ConstBuffers const& buffers) noexcept
728 : {
729 25 : std::size_t n = 0;
730 63 : for(const_buffer b : buffers)
731 38 : n += b.size();
732 25 : return n;
733 : }
734 :
735 : //------------------------------------------------
736 :
737 : /** Copy buffer contents
738 : */
739 : template<
740 : class MutableBuffers,
741 : class ConstBuffers>
742 : std::size_t
743 2754 : buffer_copy(
744 : MutableBuffers const& to,
745 : ConstBuffers const& from,
746 : std::size_t at_most =
747 : std::size_t(-1)) noexcept
748 : {
749 : // If you get a compile error here it
750 : // means that one or both of your types
751 : // do not meet the requirements.
752 : static_assert(
753 : is_mutable_buffers<MutableBuffers>::value,
754 : "Type requirements not met");
755 : static_assert(
756 : is_const_buffers<ConstBuffers>::value,
757 : "Type requirements not met");
758 :
759 2754 : std::size_t total = 0;
760 2754 : std::size_t pos0 = 0;
761 2754 : std::size_t pos1 = 0;
762 2754 : auto const end0 = from.end();
763 2754 : auto const end1 = to.end();
764 2754 : auto it0 = from.begin();
765 2754 : auto it1 = to.begin();
766 4843 : while(
767 5231 : total < at_most &&
768 12445 : it0 != end0 &&
769 : it1 != end1)
770 : {
771 : const_buffer b0 =
772 4843 : const_buffer(*it0) + pos0;
773 : mutable_buffer b1 =
774 4843 : mutable_buffer(*it1) + pos1;
775 : std::size_t amount =
776 27673 : [&]
777 : {
778 4843 : std::size_t n = b0.size();
779 4843 : if( n > b1.size())
780 1730 : n = b1.size();
781 4843 : if( n > at_most - total)
782 1728 : n = at_most - total;
783 4843 : std::memcpy(
784 : b1.data(),
785 : b0.data(),
786 : n);
787 4843 : return n;
788 4843 : }();
789 4843 : total += amount;
790 4843 : if(amount == b1.size())
791 : {
792 1715 : ++it1;
793 1715 : pos1 = 0;
794 : }
795 : else
796 : {
797 3128 : pos1 += amount;
798 : }
799 4843 : if(amount == b0.size())
800 : {
801 1891 : ++it0;
802 1891 : pos0 = 0;
803 : }
804 : else
805 : {
806 2952 : pos0 += amount;
807 : }
808 : }
809 2754 : return total;
810 : }
811 :
812 : //------------------------------------------------
813 :
814 : //
815 : // size
816 : //
817 :
818 : //
819 : // prefix
820 : //
821 :
822 : #ifndef BOOST_HTTP_PROTO_DOCS
823 : template<class Buffers>
824 : void
825 : tag_invoke(
826 : prefix_tag const&,
827 : Buffers const&,
828 : std::size_t) = delete;
829 : #endif
830 :
831 : /** Returns the type of a prefix of Buffers
832 : */
833 : #ifdef BOOST_HTTP_PROTO_DOCS
834 : template<class Buffers>
835 : using prefix_type = __see_below__;
836 : #else
837 : template<class Buffers>
838 : using prefix_type = decltype(
839 : tag_invoke(
840 : prefix_tag{},
841 : std::declval<Buffers const&>(),
842 : std::size_t{}));
843 : #endif
844 :
845 : /** Return a prefix of the buffers.
846 : */
847 : template<class Buffers>
848 : auto
849 4 : prefix(
850 : Buffers const& b,
851 : std::size_t n) ->
852 : prefix_type<Buffers>
853 : {
854 : static_assert(
855 : is_const_buffers<Buffers>::value,
856 : "Type requirements not met");
857 :
858 8 : return tag_invoke(
859 4 : prefix_tag{}, b, n);
860 : }
861 :
862 : /** Return a prefix of the buffers.
863 : */
864 : template<class Buffers>
865 : auto
866 2 : sans_suffix(
867 : Buffers const& b,
868 : std::size_t n) ->
869 : prefix_type<Buffers>
870 : {
871 2 : auto const n0 = buffer_size(b);
872 2 : if( n > n0)
873 0 : n = n0;
874 2 : return prefix(b, n0 - n);
875 : }
876 :
877 : //
878 : // suffix
879 : //
880 :
881 : #ifndef BOOST_HTTP_PROTO_DOCS
882 : template<class Buffers>
883 : void
884 : tag_invoke(
885 : suffix_tag const&,
886 : Buffers const&,
887 : std::size_t) = delete;
888 : #endif
889 :
890 : /** Returns the type of a suffix of Buffers.
891 : */
892 : #ifdef BOOST_HTTP_PROTO_DOCS
893 : template<class Buffers>
894 : using suffix_type = __see_below__;
895 : #else
896 : template<class Buffers>
897 : using suffix_type = decltype(
898 : tag_invoke(
899 : suffix_tag{},
900 : std::declval<Buffers const&>(),
901 : std::size_t{}));
902 : #endif
903 :
904 : /** Return a suffix of the buffers.
905 : */
906 : template<class Buffers>
907 : auto
908 4 : suffix(
909 : Buffers const& b,
910 : std::size_t n) ->
911 : suffix_type<Buffers>
912 : {
913 : static_assert(
914 : is_const_buffers<Buffers>::value,
915 : "Type requirements not met");
916 :
917 8 : return tag_invoke(
918 4 : suffix_tag{}, b, n);
919 : }
920 :
921 : /** Return a suffix of the buffers.
922 : */
923 : template<class Buffers>
924 : auto
925 2 : sans_prefix(
926 : Buffers const& b,
927 : std::size_t n) ->
928 : suffix_type<Buffers>
929 : {
930 : static_assert(
931 : is_const_buffers<Buffers>::value,
932 : "Type requirements not met");
933 :
934 2 : auto const n0 = buffer_size(b);
935 2 : if( n > n0)
936 0 : n = n0;
937 2 : return suffix(b, n0 - n);
938 : }
939 :
940 : } // http_proto
941 : } // boost
942 :
943 : #endif
|