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 <type_traits>
20 : #include <utility>
21 :
22 : namespace boost {
23 : namespace http_proto {
24 :
25 : //------------------------------------------------
26 :
27 : /** Determine if T is a possibly-const buffer.
28 : */
29 : #if BOOST_HTTP_PROTO_DOCS
30 : template<bool isConst, class T>
31 : struct is_buffer
32 : : std::integral_constant<bool, ...>{};
33 : #else
34 :
35 : template<
36 : bool isConst, class T,
37 : class = void>
38 : struct is_buffer : std::false_type {};
39 :
40 : template<
41 : bool isConst, class T>
42 : struct is_buffer<
43 : isConst, T, boost::void_t<decltype(
44 : std::declval<std::size_t&>() =
45 : std::declval<T const&>().size()
46 : ),
47 : typename std::enable_if<
48 : std::is_same<
49 : void*, decltype(
50 : std::declval<T const&>().data())
51 : >::value || (
52 : std::is_same<
53 : void const*, decltype(
54 : std::declval<T const&>().data())
55 : >::value && isConst)
56 : >::type
57 : >> : std::is_copy_constructible<T>
58 : {
59 : };
60 :
61 : #endif
62 :
63 : /** Determine if T is a const buffer.
64 : */
65 : template<class T>
66 : using is_const_buffer = is_buffer<true, T>;
67 :
68 : /** Determine if T is a mutable buffer.
69 : */
70 : template<class T>
71 : using is_mutable_buffer = is_buffer<false, T>;
72 :
73 : //------------------------------------------------
74 :
75 : /** Determine if T is a buffer sequence.
76 : */
77 : #if BOOST_HTTP_PROTO_DOCS
78 : template<bool isConst, class T>
79 : struct is_buffers
80 : : std::integral_constant<bool, ...>{};
81 : #else
82 :
83 : template<
84 : bool isConst, class T,
85 : class = void>
86 : struct is_buffers
87 : : is_buffer<isConst, T>
88 : {
89 : };
90 :
91 : template<
92 : bool isConst, class T>
93 : struct is_buffers<
94 : isConst, T, boost::void_t<
95 : typename std::enable_if<
96 : is_buffer<
97 : isConst, decltype(
98 : *std::declval<T const&>().begin())
99 : >::value &&
100 : is_buffer<
101 : isConst, decltype(
102 : *std::declval<T const&>().end())
103 : >::value
104 : >::type
105 : >> : std::is_move_constructible<T>
106 : {
107 : };
108 :
109 : #endif
110 :
111 : /** Determine if T is a const buffers.
112 : */
113 : template<class T>
114 : using is_const_buffers = is_buffers<true, T>;
115 :
116 : /** Determine if T is a mutable buffers.
117 : */
118 : template<class T>
119 : using is_mutable_buffers = is_buffers<false, T>;
120 :
121 : //------------------------------------------------
122 :
123 : class mutable_buffer
124 : {
125 : void* p_ = nullptr;
126 : std::size_t n_ = 0;
127 :
128 : public:
129 711 : mutable_buffer() = default;
130 : mutable_buffer(
131 : mutable_buffer const&) = default;
132 : mutable_buffer& operator=(
133 : mutable_buffer const&) = default;
134 :
135 12727 : mutable_buffer(
136 : void* data,
137 : std::size_t size) noexcept
138 12727 : : p_(data)
139 12727 : , n_(size)
140 : {
141 12727 : }
142 :
143 : template<
144 : class MutableBuffer
145 : #ifndef BOOST_HTTP_PROTO_DOCS
146 : ,class = typename std::enable_if<
147 : is_mutable_buffer<MutableBuffer
148 : >::value>::type
149 : #endif
150 : >
151 2 : mutable_buffer(
152 : MutableBuffer const& b) noexcept
153 : : p_(b.data())
154 2 : , n_(b.size())
155 : {
156 2 : }
157 :
158 : void*
159 12288 : data() const noexcept
160 : {
161 12288 : return p_;
162 : }
163 :
164 : std::size_t
165 28616 : size() const noexcept
166 : {
167 28616 : return n_;
168 : }
169 :
170 : mutable_buffer&
171 2 : operator+=(std::size_t n) noexcept
172 : {
173 2 : if(n >= n_)
174 : {
175 0 : p_ = static_cast<
176 0 : char*>(p_) + n_;
177 0 : n_ = 0;
178 0 : return *this;
179 : }
180 2 : p_ = static_cast<
181 2 : char*>(p_) + n;
182 2 : n_ -= n;
183 2 : return *this;
184 : }
185 :
186 : friend
187 : mutable_buffer
188 4647 : operator+(
189 : mutable_buffer const& b,
190 : std::size_t n) noexcept
191 : {
192 4647 : if(n < b.size())
193 : return {
194 : static_cast<char*>(
195 4647 : b.data()) + n,
196 4647 : b.size() - n };
197 : return {
198 : static_cast<char*>(
199 0 : b.data()) + b.size(),
200 0 : 0 };
201 : }
202 :
203 : friend
204 : mutable_buffer
205 1 : operator+(
206 : std::size_t n,
207 : mutable_buffer const& b) noexcept
208 : {
209 1 : if(n < b.size())
210 : return {
211 : static_cast<char*>(
212 1 : b.data()) + n,
213 1 : b.size() - n };
214 : return {
215 : static_cast<char*>(
216 0 : b.data()) + b.size(),
217 0 : 0 };
218 : }
219 : };
220 :
221 : //------------------------------------------------
222 :
223 : class const_buffer
224 : {
225 : void const* p_ = nullptr;
226 : std::size_t n_ = 0;
227 :
228 : public:
229 30 : const_buffer() = default;
230 : const_buffer(
231 : const_buffer const&) = default;
232 : const_buffer& operator=(
233 : const_buffer const&) = default;
234 :
235 9775 : const_buffer(
236 : void const* data,
237 : std::size_t size) noexcept
238 9775 : : p_(data)
239 9775 : , n_(size)
240 : {
241 9775 : }
242 :
243 : template<
244 : class ConstBuffer
245 : #ifndef BOOST_HTTP_PROTO_DOCS
246 : ,class = typename std::enable_if<
247 : is_const_buffer<ConstBuffer
248 : >::value>::type
249 : #endif
250 : >
251 21 : const_buffer(
252 : ConstBuffer const& b) noexcept
253 : : p_(b.data())
254 21 : , n_(b.size())
255 : {
256 21 : }
257 :
258 : void const*
259 9306 : data() const noexcept
260 : {
261 9306 : return p_;
262 : }
263 :
264 : std::size_t
265 23956 : size() const noexcept
266 : {
267 23956 : return n_;
268 : }
269 :
270 : const_buffer&
271 2 : operator+=(std::size_t n) noexcept
272 : {
273 2 : if(n >= n_)
274 : {
275 0 : p_ = static_cast<
276 0 : char const*>(p_) + n_;
277 0 : n_ = 0;
278 0 : return *this;
279 : }
280 2 : p_ = static_cast<
281 2 : char const*>(p_) + n;
282 2 : n_ -= n;
283 2 : return *this;
284 : }
285 :
286 : friend
287 : const_buffer
288 4647 : operator+(
289 : const_buffer const& b,
290 : std::size_t n) noexcept
291 : {
292 4647 : if(n < b.size())
293 : return {
294 : static_cast<char const*>(
295 4647 : b.data()) + n,
296 4647 : b.size() - n };
297 : return {
298 : static_cast<char const*>(
299 0 : b.data()) + b.size(),
300 0 : 0 };
301 : }
302 :
303 : friend
304 : const_buffer
305 1 : operator+(
306 : std::size_t n,
307 : const_buffer const& b) noexcept
308 : {
309 1 : if(n < b.size())
310 : return {
311 : static_cast<char const*>(
312 1 : b.data()) + n,
313 1 : b.size() - n };
314 : return {
315 : static_cast<char const*>(
316 0 : b.data()) + b.size(),
317 0 : 0 };
318 : }
319 : };
320 :
321 : //------------------------------------------------
322 :
323 : /** A MutableBuffer of length 1
324 : */
325 : class mutable_buffers_1
326 : {
327 : mutable_buffer mb_;
328 :
329 : public:
330 : using value_type =
331 : mutable_buffer;
332 :
333 : using const_iterator =
334 : mutable_buffer const*;
335 :
336 2 : mutable_buffers_1() = default;
337 :
338 : explicit
339 15 : mutable_buffers_1(
340 : mutable_buffer mb) noexcept
341 15 : : mb_(mb)
342 : {
343 15 : }
344 :
345 : mutable_buffers_1&
346 : operator=(
347 : mutable_buffers_1 const&) = default;
348 :
349 : const_iterator
350 21 : begin() const noexcept
351 : {
352 21 : return &mb_;
353 : }
354 :
355 : const_iterator
356 21 : end() const noexcept
357 : {
358 21 : return &mb_ + 1;
359 : }
360 : };
361 :
362 : /** A ConstBuffer of length 1
363 : */
364 : class const_buffers_1
365 : {
366 : const_buffer cb_;
367 :
368 : public:
369 : using value_type =
370 : const_buffer;
371 :
372 : using const_iterator =
373 : const_buffer const*;
374 :
375 2 : const_buffers_1() = default;
376 :
377 : explicit
378 15 : const_buffers_1(
379 : const_buffer cb) noexcept
380 15 : : cb_(cb)
381 : {
382 15 : }
383 :
384 : const_buffers_1&
385 : operator=(const_buffers_1 const&) = default;
386 :
387 : const_iterator
388 21 : begin() const noexcept
389 : {
390 21 : return &cb_;
391 : }
392 :
393 : const_iterator
394 21 : end() const noexcept
395 : {
396 21 : return &cb_ + 1;
397 : }
398 : };
399 :
400 : //------------------------------------------------
401 :
402 : template<
403 : class ConstBuffer
404 : #ifndef BOOST_HTTP_PROTO_DOCS
405 : ,class = typename std::enable_if<
406 : is_const_buffer<
407 : ConstBuffer>::value &&
408 : ! is_mutable_buffer<
409 : ConstBuffer>::value
410 : >::type
411 : #endif
412 : >
413 : auto
414 15 : make_buffers(
415 : ConstBuffer const& b) ->
416 : const_buffers_1
417 : {
418 : return const_buffers_1(
419 15 : const_buffer(b));
420 : }
421 :
422 : template<
423 : class MutableBuffer
424 : #ifndef BOOST_HTTP_PROTO_DOCS
425 : ,class = typename std::enable_if<
426 : is_mutable_buffer<
427 : MutableBuffer>::value
428 : >::type
429 : #endif
430 : >
431 : auto
432 15 : make_buffers(
433 : MutableBuffer const& b) ->
434 : mutable_buffers_1
435 : {
436 : return mutable_buffers_1(
437 15 : mutable_buffer(b));
438 : }
439 :
440 : template<
441 : class Buffers
442 : #ifndef BOOST_HTTP_PROTO_DOCS
443 : ,class = typename std::enable_if<
444 : ! is_const_buffer<
445 : Buffers>::value &&
446 : is_const_buffers<
447 : Buffers>::value
448 : >::type
449 : #endif
450 : >
451 : auto
452 5118 : make_buffers(
453 : Buffers&& b) ->
454 : Buffers&&
455 : {
456 : return std::forward<
457 5118 : Buffers>(b);
458 : }
459 :
460 : //------------------------------------------------
461 :
462 : #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
463 : # pragma warning (push)
464 : # pragma warning (disable: 4521) // multiple copy constructors specified
465 : # pragma warning (disable: 4522) // multiple assignment operators specified
466 : #endif
467 :
468 : template<bool isConst>
469 : class buffers_pair
470 : {
471 : public:
472 : // VFALCO: This type is public otherwise
473 : // asio::buffers_iterator won't compile.
474 : using value_type = typename
475 : std::conditional<isConst,
476 : const_buffer,
477 : mutable_buffer>::type;
478 :
479 : using const_iterator = value_type const*;
480 :
481 : buffers_pair() = default;
482 :
483 : #if defined(BOOST_HTTP_PROTO_DOCS) || ( \
484 : ! BOOST_WORKAROUND(BOOST_MSVC, < 1910))
485 : buffers_pair(
486 : buffers_pair const& other) = default;
487 : buffers_pair& operator=(
488 : buffers_pair const& other) = default;
489 :
490 : #else
491 : buffers_pair(
492 : buffers_pair const& other)
493 : : buffers_pair(
494 : *other.begin(),
495 : *(other.begin() + 1))
496 : {
497 : }
498 :
499 : buffers_pair&
500 : operator=(buffers_pair const& other)
501 : {
502 : b_[0] = other.b_[0];
503 : b_[1] = other.b_[1];
504 : return *this;
505 : }
506 : #endif
507 :
508 : // const pair construction
509 : // from mutable mutable pair
510 : template<
511 : bool isConst_ = isConst,
512 : class = typename std::enable_if<
513 : isConst_>::type>
514 : buffers_pair(
515 : buffers_pair<false> const& other)
516 : : buffers_pair(
517 : other.b_[0],
518 : other.b_[1])
519 : {
520 : }
521 :
522 : // const pair assignment
523 : // from mutable mutable pair
524 : template<
525 : bool isConst_ = isConst,
526 : class = typename std::enable_if<
527 : isConst_>::type>
528 : buffers_pair&
529 : operator=(
530 : buffers_pair<false> const& other)
531 : {
532 : b_[0] = other.b_[0];
533 : b_[1] = other.b_[1];
534 : return *this;
535 : }
536 :
537 5086 : buffers_pair(
538 : value_type b0,
539 : value_type b1) noexcept
540 5086 : {
541 5086 : if(b0.size() > 0)
542 : {
543 4696 : b_[0] = b0;
544 4696 : b_[1] = b1;
545 : }
546 : else
547 : {
548 390 : b_[0] = b1;
549 : }
550 5086 : }
551 :
552 : const_buffer
553 8 : operator[](
554 : std::size_t i) const noexcept
555 : {
556 8 : BOOST_ASSERT(i < 2);
557 8 : return b_[i];
558 : }
559 :
560 : const_iterator
561 5089 : begin() const noexcept
562 : {
563 5089 : return b_;
564 : }
565 :
566 : const_iterator
567 5089 : end() const noexcept
568 : {
569 5089 : if(b_[1].size() > 0)
570 4681 : return &b_[2];
571 408 : if(b_[0].size() > 0)
572 408 : return &b_[1];
573 0 : return b_;
574 : }
575 :
576 : private:
577 : value_type b_[2];
578 : };
579 :
580 : #if BOOST_WORKAROUND(BOOST_MSVC, < 1910)
581 : # pragma warning (pop)
582 : #endif
583 :
584 : /** A mutable buffers pair
585 : */
586 : using mutable_buffers_pair =
587 : buffers_pair<false>;
588 :
589 : /** A const buffers pair
590 : */
591 : using const_buffers_pair =
592 : buffers_pair<true>;
593 :
594 : //------------------------------------------------
595 :
596 : /** Return the total octets in a buffer sequence
597 : */
598 : template<
599 : class ConstBuffers
600 : #ifndef BOOST_HTTP_PROTO_DOCS
601 : , class = typename std::enable_if<
602 : is_const_buffers<ConstBuffers>::value
603 : >::type
604 : #endif
605 : >
606 : std::size_t
607 20 : buffer_size(
608 : ConstBuffers const& buffers) noexcept
609 : {
610 20 : std::size_t n = 0;
611 50 : for(const_buffer b
612 20 : : make_buffers(buffers))
613 30 : n += b.size();
614 20 : return n;
615 : }
616 :
617 : //------------------------------------------------
618 :
619 : /** Copy buffer contents
620 : */
621 : template<
622 : class MutableBuffers,
623 : class ConstBuffers>
624 : std::size_t
625 2557 : buffer_copy(
626 : MutableBuffers const& to,
627 : ConstBuffers const& from,
628 : std::size_t at_most =
629 : std::size_t(-1)) noexcept
630 : {
631 : // If you get a compile error here it
632 : // means that one or both of your types
633 : // do not meet the requirements.
634 : static_assert(
635 : is_mutable_buffers<MutableBuffers>::value &&
636 : is_const_buffers<ConstBuffers>::value,
637 : "Type requirements not met");
638 :
639 2557 : std::size_t total = 0;
640 2557 : std::size_t pos0 = 0;
641 2557 : std::size_t pos1 = 0;
642 2557 : auto const& bs0 = (make_buffers)(from);
643 2557 : auto const& bs1 = (make_buffers)(to);
644 2557 : auto const end0 = bs0.end();
645 2557 : auto const end1 = bs1.end();
646 2557 : auto it0 = bs0.begin();
647 2557 : auto it1 = bs1.begin();
648 4646 : while(
649 4837 : total < at_most &&
650 11850 : it0 != end0 &&
651 : it1 != end1)
652 : {
653 : const_buffer b0 =
654 4646 : const_buffer(*it0) + pos0;
655 : mutable_buffer b1 =
656 4646 : mutable_buffer(*it1) + pos1;
657 : std::size_t amount =
658 26688 : [&]
659 : {
660 4646 : std::size_t n = b0.size();
661 4646 : if( n > b1.size())
662 1730 : n = b1.size();
663 4646 : if( n > at_most - total)
664 1728 : n = at_most - total;
665 4646 : std::memcpy(
666 : b1.data(),
667 : b0.data(),
668 : n);
669 4646 : return n;
670 4646 : }();
671 4646 : total += amount;
672 4646 : if(amount == b1.size())
673 : {
674 1682 : ++it1;
675 1682 : pos1 = 0;
676 : }
677 : else
678 : {
679 2964 : pos1 += amount;
680 : }
681 4646 : if(amount == b0.size())
682 : {
683 1694 : ++it0;
684 1694 : pos0 = 0;
685 : }
686 : else
687 : {
688 2952 : pos0 += amount;
689 : }
690 : }
691 2557 : return total;
692 : }
693 :
694 : //------------------------------------------------
695 :
696 : // VFALCO GARBAGE
697 : class mutable_buffers
698 : {
699 : mutable_buffer const* p_ = nullptr;
700 : std::size_t n_ = 0;
701 :
702 : public:
703 : using value_type = mutable_buffer;
704 :
705 : using iterator = value_type const*;
706 :
707 : mutable_buffers() = default;
708 :
709 : mutable_buffers(
710 : mutable_buffers const&) = default;
711 :
712 : mutable_buffers& operator=(
713 : mutable_buffers const&) = default;
714 :
715 2969 : mutable_buffers(
716 : value_type const* p,
717 : std::size_t n) noexcept
718 2969 : : p_(p)
719 2969 : , n_(n)
720 : {
721 2969 : }
722 :
723 : std::size_t
724 : size() const noexcept
725 : {
726 : return n_;
727 : }
728 :
729 : iterator
730 2969 : begin() const noexcept
731 : {
732 2969 : return p_;
733 : }
734 :
735 : iterator
736 : end() const noexcept
737 : {
738 : return p_ + n_;
739 : }
740 : };
741 :
742 : } // http_proto
743 : } // boost
744 :
745 : #endif
|