]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/beast/core/impl/multi_buffer.ipp
Add patch for failing prerm scripts
[ceph.git] / ceph / src / boost / boost / beast / core / impl / multi_buffer.ipp
CommitLineData
7c673cae 1//
b32b8144 2// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
7c673cae
FG
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//
b32b8144
FG
7// Official repository: https://github.com/boostorg/beast
8//
7c673cae 9
b32b8144
FG
10#ifndef BOOST_BEAST_IMPL_MULTI_BUFFER_IPP
11#define BOOST_BEAST_IMPL_MULTI_BUFFER_IPP
7c673cae 12
b32b8144 13#include <boost/beast/core/detail/type_traits.hpp>
7c673cae 14#include <boost/assert.hpp>
b32b8144 15#include <boost/throw_exception.hpp>
7c673cae
FG
16#include <algorithm>
17#include <exception>
18#include <sstream>
19#include <string>
20#include <utility>
21
b32b8144 22namespace boost {
7c673cae
FG
23namespace beast {
24
25/* These diagrams illustrate the layout and state variables.
26
271 Input and output contained entirely in one element:
28
29 0 out_
30 |<-------------+------------------------------------------->|
31 in_pos_ out_pos_ out_end_
32
33
342 Output contained in first and second elements:
35
36 out_
37 |<------+----------+------->| |<----------+-------------->|
38 in_pos_ out_pos_ out_end_
39
40
413 Output contained in the second element:
42
43 out_
44 |<------------+------------>| |<----+-------------------->|
45 in_pos_ out_pos_ out_end_
46
47
484 Output contained in second and third elements:
49
50 out_
51 |<-----+-------->| |<-------+------>| |<--------------->|
52 in_pos_ out_pos_ out_end_
53
54
555 Input sequence is empty:
56
57 out_
58 |<------+------------------>| |<-----------+------------->|
59 out_pos_ out_end_
60 in_pos_
61
62
636 Output sequence is empty:
64
65 out_
66 |<------+------------------>| |<------+------------------>|
67 in_pos_ out_pos_
68 out_end_
69
70
717 The end of output can point to the end of an element.
72 But out_pos_ should never point to the end:
73
74 out_
75 |<------+------------------>| |<------+------------------>|
76 in_pos_ out_pos_ out_end_
77
78
798 When the input sequence entirely fills the last element and
80 the output sequence is empty, out_ will point to the end of
81 the list of buffers, and out_pos_ and out_end_ will be 0:
82
83
84 |<------+------------------>| out_ == list_.end()
85 in_pos_ out_pos_ == 0
86 out_end_ == 0
87*/
88
89template<class Allocator>
b32b8144 90class basic_multi_buffer<Allocator>::element
7c673cae
FG
91 : public boost::intrusive::list_base_hook<
92 boost::intrusive::link_mode<
93 boost::intrusive::normal_link>>
94{
b32b8144
FG
95 using size_type =
96 typename detail::allocator_traits<Allocator>::size_type;
7c673cae
FG
97
98 size_type const size_;
99
100public:
101 element(element const&) = delete;
102 element& operator=(element const&) = delete;
103
104 explicit
105 element(size_type n)
106 : size_(n)
107 {
108 }
109
110 size_type
111 size() const
112 {
113 return size_;
114 }
115
116 char*
117 data() const
118 {
119 return const_cast<char*>(
120 reinterpret_cast<char const*>(this+1));
121 }
122};
123
124template<class Allocator>
b32b8144 125class basic_multi_buffer<Allocator>::const_buffers_type
7c673cae 126{
b32b8144 127 basic_multi_buffer const* b_;
7c673cae 128
b32b8144 129 friend class basic_multi_buffer;
7c673cae
FG
130
131 explicit
b32b8144 132 const_buffers_type(basic_multi_buffer const& b);
7c673cae
FG
133
134public:
11fdf7f2 135 using value_type = boost::asio::const_buffer;
7c673cae
FG
136
137 class const_iterator;
138
139 const_buffers_type() = delete;
140 const_buffers_type(const_buffers_type const&) = default;
141 const_buffers_type& operator=(const_buffers_type const&) = default;
142
143 const_iterator
144 begin() const;
145
146 const_iterator
147 end() const;
b32b8144
FG
148
149 friend
150 std::size_t
151 buffer_size(const_buffers_type const& buffers)
152 {
153 return buffers.b_->size();
154 }
7c673cae
FG
155};
156
157template<class Allocator>
b32b8144 158class basic_multi_buffer<Allocator>::mutable_buffers_type
7c673cae 159{
b32b8144 160 basic_multi_buffer const* b_;
7c673cae 161
b32b8144 162 friend class basic_multi_buffer;
7c673cae
FG
163
164 explicit
b32b8144 165 mutable_buffers_type(basic_multi_buffer const& b);
7c673cae
FG
166
167public:
168 using value_type = mutable_buffer;
169
170 class const_iterator;
171
172 mutable_buffers_type() = delete;
173 mutable_buffers_type(mutable_buffers_type const&) = default;
174 mutable_buffers_type& operator=(mutable_buffers_type const&) = default;
175
176 const_iterator
177 begin() const;
178
179 const_iterator
180 end() const;
181};
182
183//------------------------------------------------------------------------------
184
185template<class Allocator>
b32b8144 186class basic_multi_buffer<Allocator>::const_buffers_type::const_iterator
7c673cae 187{
b32b8144 188 basic_multi_buffer const* b_ = nullptr;
7c673cae
FG
189 typename list_type::const_iterator it_;
190
191public:
192 using value_type =
193 typename const_buffers_type::value_type;
194 using pointer = value_type const*;
195 using reference = value_type;
196 using difference_type = std::ptrdiff_t;
197 using iterator_category =
198 std::bidirectional_iterator_tag;
199
200 const_iterator() = default;
201 const_iterator(const_iterator&& other) = default;
202 const_iterator(const_iterator const& other) = default;
203 const_iterator& operator=(const_iterator&& other) = default;
204 const_iterator& operator=(const_iterator const& other) = default;
205
b32b8144 206 const_iterator(basic_multi_buffer const& b,
7c673cae 207 typename list_type::const_iterator const& it)
b32b8144 208 : b_(&b)
7c673cae
FG
209 , it_(it)
210 {
211 }
212
213 bool
214 operator==(const_iterator const& other) const
215 {
b32b8144 216 return b_ == other.b_ && it_ == other.it_;
7c673cae
FG
217 }
218
219 bool
220 operator!=(const_iterator const& other) const
221 {
222 return !(*this == other);
223 }
224
225 reference
226 operator*() const
227 {
228 auto const& e = *it_;
229 return value_type{e.data(),
b32b8144
FG
230 (b_->out_ == b_->list_.end() ||
231 &e != &*b_->out_) ? e.size() : b_->out_pos_} +
232 (&e == &*b_->list_.begin() ? b_->in_pos_ : 0);
7c673cae
FG
233 }
234
235 pointer
236 operator->() const = delete;
237
238 const_iterator&
239 operator++()
240 {
241 ++it_;
242 return *this;
243 }
244
245 const_iterator
246 operator++(int)
247 {
248 auto temp = *this;
249 ++(*this);
250 return temp;
251 }
252
253 const_iterator&
254 operator--()
255 {
256 --it_;
257 return *this;
258 }
259
260 const_iterator
261 operator--(int)
262 {
263 auto temp = *this;
264 --(*this);
265 return temp;
266 }
267};
268
269template<class Allocator>
b32b8144
FG
270basic_multi_buffer<Allocator>::
271const_buffers_type::
272const_buffers_type(
273 basic_multi_buffer const& b)
274 : b_(&b)
7c673cae
FG
275{
276}
277
278template<class Allocator>
279auto
b32b8144
FG
280basic_multi_buffer<Allocator>::
281const_buffers_type::
282begin() const ->
7c673cae
FG
283 const_iterator
284{
b32b8144 285 return const_iterator{*b_, b_->list_.begin()};
7c673cae
FG
286}
287
288template<class Allocator>
289auto
b32b8144
FG
290basic_multi_buffer<Allocator>::
291const_buffers_type::
292end() const ->
7c673cae
FG
293 const_iterator
294{
b32b8144
FG
295 return const_iterator{*b_, b_->out_ ==
296 b_->list_.end() ? b_->list_.end() :
297 std::next(b_->out_)};
7c673cae
FG
298}
299
300//------------------------------------------------------------------------------
301
302template<class Allocator>
b32b8144 303class basic_multi_buffer<Allocator>::mutable_buffers_type::const_iterator
7c673cae 304{
b32b8144 305 basic_multi_buffer const* b_ = nullptr;
7c673cae
FG
306 typename list_type::const_iterator it_;
307
308public:
309 using value_type =
310 typename mutable_buffers_type::value_type;
311 using pointer = value_type const*;
312 using reference = value_type;
313 using difference_type = std::ptrdiff_t;
314 using iterator_category =
315 std::bidirectional_iterator_tag;
316
317 const_iterator() = default;
318 const_iterator(const_iterator&& other) = default;
319 const_iterator(const_iterator const& other) = default;
320 const_iterator& operator=(const_iterator&& other) = default;
321 const_iterator& operator=(const_iterator const& other) = default;
322
b32b8144 323 const_iterator(basic_multi_buffer const& b,
7c673cae 324 typename list_type::const_iterator const& it)
b32b8144 325 : b_(&b)
7c673cae
FG
326 , it_(it)
327 {
328 }
329
330 bool
331 operator==(const_iterator const& other) const
332 {
b32b8144 333 return b_ == other.b_ && it_ == other.it_;
7c673cae
FG
334 }
335
336 bool
337 operator!=(const_iterator const& other) const
338 {
339 return !(*this == other);
340 }
341
342 reference
343 operator*() const
344 {
345 auto const& e = *it_;
346 return value_type{e.data(),
b32b8144
FG
347 &e == &*std::prev(b_->list_.end()) ?
348 b_->out_end_ : e.size()} +
349 (&e == &*b_->out_ ? b_->out_pos_ : 0);
7c673cae
FG
350 }
351
352 pointer
353 operator->() const = delete;
354
355 const_iterator&
356 operator++()
357 {
358 ++it_;
359 return *this;
360 }
361
362 const_iterator
363 operator++(int)
364 {
365 auto temp = *this;
366 ++(*this);
367 return temp;
368 }
369
370 const_iterator&
371 operator--()
372 {
373 --it_;
374 return *this;
375 }
376
377 const_iterator
378 operator--(int)
379 {
380 auto temp = *this;
381 --(*this);
382 return temp;
383 }
384};
385
386template<class Allocator>
b32b8144
FG
387basic_multi_buffer<Allocator>::
388mutable_buffers_type::
389mutable_buffers_type(
390 basic_multi_buffer const& b)
391 : b_(&b)
7c673cae
FG
392{
393}
394
395template<class Allocator>
396auto
b32b8144
FG
397basic_multi_buffer<Allocator>::
398mutable_buffers_type::
399begin() const ->
7c673cae
FG
400 const_iterator
401{
b32b8144 402 return const_iterator{*b_, b_->out_};
7c673cae
FG
403}
404
405template<class Allocator>
406auto
b32b8144
FG
407basic_multi_buffer<Allocator>::
408mutable_buffers_type::
409end() const ->
7c673cae
FG
410 const_iterator
411{
b32b8144 412 return const_iterator{*b_, b_->list_.end()};
7c673cae
FG
413}
414
415//------------------------------------------------------------------------------
416
417template<class Allocator>
b32b8144
FG
418basic_multi_buffer<Allocator>::
419~basic_multi_buffer()
7c673cae
FG
420{
421 delete_list();
422}
423
424template<class Allocator>
b32b8144
FG
425basic_multi_buffer<Allocator>::
426basic_multi_buffer()
427 : out_(list_.end())
428{
429}
430
431template<class Allocator>
432basic_multi_buffer<Allocator>::
433basic_multi_buffer(std::size_t limit)
434 : max_(limit)
435 , out_(list_.end())
436{
437}
438
439template<class Allocator>
440basic_multi_buffer<Allocator>::
441basic_multi_buffer(Allocator const& alloc)
442 : detail::empty_base_optimization<
443 base_alloc_type>(alloc)
444 , out_(list_.end())
445{
446}
447
448template<class Allocator>
449basic_multi_buffer<Allocator>::
450basic_multi_buffer(std::size_t limit,
451 Allocator const& alloc)
452 : detail::empty_base_optimization<
453 base_alloc_type>(alloc)
454 , max_(limit)
455 , out_(list_.end())
456{
457}
458
459template<class Allocator>
460basic_multi_buffer<Allocator>::
461basic_multi_buffer(basic_multi_buffer&& other)
462 : detail::empty_base_optimization<
463 base_alloc_type>(std::move(other.member()))
464 , max_(other.max_)
7c673cae
FG
465 , in_size_(other.in_size_)
466 , in_pos_(other.in_pos_)
467 , out_pos_(other.out_pos_)
468 , out_end_(other.out_end_)
469{
470 auto const at_end =
471 other.out_ == other.list_.end();
472 list_ = std::move(other.list_);
473 out_ = at_end ? list_.end() : other.out_;
474 other.in_size_ = 0;
475 other.out_ = other.list_.end();
476 other.in_pos_ = 0;
477 other.out_pos_ = 0;
478 other.out_end_ = 0;
479}
480
481template<class Allocator>
b32b8144
FG
482basic_multi_buffer<Allocator>::
483basic_multi_buffer(basic_multi_buffer&& other,
484 Allocator const& alloc)
485 : detail::empty_base_optimization<
486 base_alloc_type>(alloc)
487 , max_(other.max_)
7c673cae 488{
7c673cae 489 if(this->member() != other.member())
b32b8144
FG
490 {
491 out_ = list_.end();
492 copy_from(other);
493 other.reset();
494 }
7c673cae 495 else
b32b8144
FG
496 {
497 auto const at_end =
498 other.out_ == other.list_.end();
499 list_ = std::move(other.list_);
500 out_ = at_end ? list_.end() : other.out_;
501 in_size_ = other.in_size_;
502 in_pos_ = other.in_pos_;
503 out_pos_ = other.out_pos_;
504 out_end_ = other.out_end_;
505 other.in_size_ = 0;
506 other.out_ = other.list_.end();
507 other.in_pos_ = 0;
508 other.out_pos_ = 0;
509 other.out_end_ = 0;
510 }
7c673cae
FG
511}
512
513template<class Allocator>
b32b8144
FG
514basic_multi_buffer<Allocator>::
515basic_multi_buffer(basic_multi_buffer const& other)
516 : detail::empty_base_optimization<
517 base_alloc_type>(alloc_traits::
518 select_on_container_copy_construction(
519 other.member()))
520 , max_(other.max_)
521 , out_(list_.end())
7c673cae 522{
b32b8144 523 copy_from(other);
7c673cae
FG
524}
525
526template<class Allocator>
b32b8144
FG
527basic_multi_buffer<Allocator>::
528basic_multi_buffer(basic_multi_buffer const& other,
529 Allocator const& alloc)
530 : detail::empty_base_optimization<
531 base_alloc_type>(alloc)
532 , max_(other.max_)
533 , out_(list_.end())
7c673cae 534{
b32b8144 535 copy_from(other);
7c673cae
FG
536}
537
538template<class Allocator>
b32b8144
FG
539template<class OtherAlloc>
540basic_multi_buffer<Allocator>::
541basic_multi_buffer(
542 basic_multi_buffer<OtherAlloc> const& other)
543 : out_(list_.end())
544{
545 copy_from(other);
546}
547
548template<class Allocator>
549template<class OtherAlloc>
550basic_multi_buffer<Allocator>::
551basic_multi_buffer(
552 basic_multi_buffer<OtherAlloc> const& other,
7c673cae 553 allocator_type const& alloc)
b32b8144
FG
554 : detail::empty_base_optimization<
555 base_alloc_type>(alloc)
556 , max_(other.max_)
557 , out_(list_.end())
7c673cae 558{
b32b8144 559 copy_from(other);
7c673cae
FG
560}
561
562template<class Allocator>
563auto
b32b8144
FG
564basic_multi_buffer<Allocator>::
565operator=(basic_multi_buffer&& other) ->
566 basic_multi_buffer&
7c673cae
FG
567{
568 if(this == &other)
569 return *this;
b32b8144
FG
570 reset();
571 max_ = other.max_;
572 move_assign(other, std::integral_constant<bool,
573 alloc_traits::propagate_on_container_move_assignment::value>{});
7c673cae
FG
574 return *this;
575}
576
577template<class Allocator>
b32b8144
FG
578auto
579basic_multi_buffer<Allocator>::
580operator=(basic_multi_buffer const& other) ->
581basic_multi_buffer&
7c673cae 582{
b32b8144
FG
583 if(this == &other)
584 return *this;
585 copy_assign(other, std::integral_constant<bool,
586 alloc_traits::propagate_on_container_copy_assignment::value>{});
587 return *this;
7c673cae
FG
588}
589
590template<class Allocator>
591template<class OtherAlloc>
592auto
b32b8144
FG
593basic_multi_buffer<Allocator>::
594operator=(
595 basic_multi_buffer<OtherAlloc> const& other) ->
596 basic_multi_buffer&
7c673cae 597{
b32b8144
FG
598 reset();
599 max_ = other.max_;
600 copy_from(other);
7c673cae
FG
601 return *this;
602}
603
7c673cae
FG
604template<class Allocator>
605std::size_t
b32b8144
FG
606basic_multi_buffer<Allocator>::
607capacity() const
7c673cae
FG
608{
609 auto pos = out_;
610 if(pos == list_.end())
611 return in_size_;
612 auto n = pos->size() - out_pos_;
613 while(++pos != list_.end())
614 n += pos->size();
615 return in_size_ + n;
616}
617
618template<class Allocator>
619auto
b32b8144 620basic_multi_buffer<Allocator>::
7c673cae
FG
621data() const ->
622 const_buffers_type
623{
624 return const_buffers_type(*this);
625}
626
627template<class Allocator>
628auto
b32b8144
FG
629basic_multi_buffer<Allocator>::
630prepare(size_type n) ->
7c673cae
FG
631 mutable_buffers_type
632{
b32b8144
FG
633 if(in_size_ + n > max_)
634 BOOST_THROW_EXCEPTION(std::length_error{
635 "dynamic buffer overflow"});
7c673cae 636 list_type reuse;
b32b8144
FG
637 std::size_t total = in_size_;
638 // put all empty buffers on reuse list
7c673cae
FG
639 if(out_ != list_.end())
640 {
b32b8144 641 total += out_->size() - out_pos_;
7c673cae
FG
642 if(out_ != list_.iterator_to(list_.back()))
643 {
644 out_end_ = out_->size();
645 reuse.splice(reuse.end(), list_,
646 std::next(out_), list_.end());
b32b8144 647 #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
7c673cae 648 debug_check();
b32b8144 649 #endif
7c673cae
FG
650 }
651 auto const avail = out_->size() - out_pos_;
652 if(n > avail)
653 {
654 out_end_ = out_->size();
655 n -= avail;
656 }
657 else
658 {
659 out_end_ = out_pos_ + n;
660 n = 0;
661 }
b32b8144 662 #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
7c673cae 663 debug_check();
b32b8144 664 #endif
7c673cae 665 }
b32b8144 666 // get space from reuse buffers
7c673cae
FG
667 while(n > 0 && ! reuse.empty())
668 {
669 auto& e = reuse.front();
670 reuse.erase(reuse.iterator_to(e));
671 list_.push_back(e);
b32b8144 672 total += e.size();
7c673cae
FG
673 if(n > e.size())
674 {
675 out_end_ = e.size();
676 n -= e.size();
677 }
678 else
679 {
680 out_end_ = n;
681 n = 0;
682 }
b32b8144 683 #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
7c673cae 684 debug_check();
b32b8144 685 #endif
7c673cae 686 }
b32b8144
FG
687 BOOST_ASSERT(total <= max_);
688 if(! reuse.empty() || n > 0)
7c673cae 689 {
b32b8144 690 for(auto it = reuse.begin(); it != reuse.end();)
7c673cae 691 {
b32b8144
FG
692 auto& e = *it++;
693 reuse.erase(list_.iterator_to(e));
694 auto const len = sizeof(e) + e.size();
695 alloc_traits::destroy(this->member(), &e);
696 alloc_traits::deallocate(this->member(),
697 reinterpret_cast<char*>(&e), len);
7c673cae 698 }
b32b8144 699 if(n > 0)
7c673cae 700 {
b32b8144
FG
701 static auto const growth_factor = 2.0f;
702 auto const size =
703 (std::min<std::size_t>)(
704 max_ - total,
705 (std::max<std::size_t>)({
706 static_cast<std::size_t>(
707 in_size_ * growth_factor - in_size_),
708 512,
709 n}));
710 auto& e = *reinterpret_cast<element*>(static_cast<
711 void*>(alloc_traits::allocate(this->member(),
712 sizeof(element) + size)));
713 alloc_traits::construct(this->member(), &e, size);
714 list_.push_back(e);
715 if(out_ == list_.end())
716 out_ = list_.iterator_to(e);
7c673cae 717 out_end_ = n;
b32b8144
FG
718 #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
719 debug_check();
720 #endif
7c673cae 721 }
7c673cae
FG
722 }
723 return mutable_buffers_type(*this);
724}
725
726template<class Allocator>
727void
b32b8144
FG
728basic_multi_buffer<Allocator>::
729commit(size_type n)
7c673cae
FG
730{
731 if(list_.empty())
732 return;
733 if(out_ == list_.end())
734 return;
735 auto const back =
736 list_.iterator_to(list_.back());
737 while(out_ != back)
738 {
739 auto const avail =
740 out_->size() - out_pos_;
741 if(n < avail)
742 {
743 out_pos_ += n;
744 in_size_ += n;
b32b8144 745 #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
7c673cae 746 debug_check();
b32b8144 747 #endif
7c673cae
FG
748 return;
749 }
750 ++out_;
751 n -= avail;
752 out_pos_ = 0;
753 in_size_ += avail;
b32b8144 754 #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
7c673cae 755 debug_check();
b32b8144 756 #endif
7c673cae
FG
757 }
758
759 n = (std::min)(n, out_end_ - out_pos_);
760 out_pos_ += n;
761 in_size_ += n;
762 if(out_pos_ == out_->size())
763 {
764 ++out_;
765 out_pos_ = 0;
766 out_end_ = 0;
767 }
b32b8144 768#if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
7c673cae 769 debug_check();
b32b8144 770#endif
7c673cae
FG
771}
772
773template<class Allocator>
774void
b32b8144
FG
775basic_multi_buffer<Allocator>::
776consume(size_type n)
7c673cae
FG
777{
778 if(list_.empty())
779 return;
7c673cae
FG
780 for(;;)
781 {
782 if(list_.begin() != out_)
783 {
b32b8144
FG
784 auto const avail =
785 list_.front().size() - in_pos_;
7c673cae
FG
786 if(n < avail)
787 {
788 in_size_ -= n;
789 in_pos_ += n;
b32b8144 790 #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
7c673cae 791 debug_check();
b32b8144 792 #endif
7c673cae
FG
793 break;
794 }
795 n -= avail;
796 in_size_ -= avail;
797 in_pos_ = 0;
798 auto& e = list_.front();
799 list_.erase(list_.iterator_to(e));
b32b8144 800 auto const len = sizeof(e) + e.size();
7c673cae
FG
801 alloc_traits::destroy(this->member(), &e);
802 alloc_traits::deallocate(this->member(),
803 reinterpret_cast<char*>(&e), len);
b32b8144 804 #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
7c673cae 805 debug_check();
b32b8144 806 #endif
7c673cae
FG
807 }
808 else
809 {
810 auto const avail = out_pos_ - in_pos_;
811 if(n < avail)
812 {
813 in_size_ -= n;
814 in_pos_ += n;
815 }
816 else
817 {
818 in_size_ = 0;
819 if(out_ != list_.iterator_to(list_.back()) ||
820 out_pos_ != out_end_)
821 {
822 in_pos_ = out_pos_;
823 }
824 else
825 {
826 // Input and output sequences are empty, reuse buffer.
827 // Alternatively we could deallocate it.
828 in_pos_ = 0;
829 out_pos_ = 0;
830 out_end_ = 0;
831 }
832 }
b32b8144 833 #if BOOST_BEAST_MULTI_BUFFER_DEBUG_CHECK
7c673cae 834 debug_check();
b32b8144 835 #endif
7c673cae
FG
836 break;
837 }
838 }
839}
840
841template<class Allocator>
b32b8144 842inline
7c673cae 843void
b32b8144
FG
844basic_multi_buffer<Allocator>::
845delete_list()
846{
847 for(auto iter = list_.begin(); iter != list_.end();)
848 {
849 auto& e = *iter++;
850 auto const len = sizeof(e) + e.size();
851 alloc_traits::destroy(this->member(), &e);
852 alloc_traits::deallocate(this->member(),
853 reinterpret_cast<char*>(&e), len);
854 }
855}
856
857template<class Allocator>
858inline
859void
860basic_multi_buffer<Allocator>::
861reset()
7c673cae
FG
862{
863 delete_list();
864 list_.clear();
b32b8144 865 out_ = list_.end();
7c673cae
FG
866 in_size_ = 0;
867 in_pos_ = 0;
868 out_pos_ = 0;
869 out_end_ = 0;
870}
871
872template<class Allocator>
b32b8144
FG
873template<class DynamicBuffer>
874inline
7c673cae 875void
b32b8144
FG
876basic_multi_buffer<Allocator>::
877copy_from(DynamicBuffer const& buffer)
7c673cae 878{
b32b8144
FG
879 if(buffer.size() == 0)
880 return;
7c673cae 881 using boost::asio::buffer_copy;
b32b8144
FG
882 commit(buffer_copy(
883 prepare(buffer.size()), buffer.data()));
884}
885
886template<class Allocator>
887inline
888void
889basic_multi_buffer<Allocator>::
890move_assign(basic_multi_buffer& other, std::false_type)
891{
7c673cae
FG
892 if(this->member() != other.member())
893 {
b32b8144
FG
894 copy_from(other);
895 other.reset();
7c673cae
FG
896 }
897 else
b32b8144 898 {
7c673cae 899 move_assign(other, std::true_type{});
b32b8144 900 }
7c673cae
FG
901}
902
903template<class Allocator>
b32b8144 904inline
7c673cae 905void
b32b8144
FG
906basic_multi_buffer<Allocator>::
907move_assign(basic_multi_buffer& other, std::true_type)
7c673cae
FG
908{
909 this->member() = std::move(other.member());
910 auto const at_end =
911 other.out_ == other.list_.end();
912 list_ = std::move(other.list_);
913 out_ = at_end ? list_.end() : other.out_;
914
915 in_size_ = other.in_size_;
916 in_pos_ = other.in_pos_;
917 out_pos_ = other.out_pos_;
918 out_end_ = other.out_end_;
919
920 other.in_size_ = 0;
921 other.out_ = other.list_.end();
922 other.in_pos_ = 0;
923 other.out_pos_ = 0;
924 other.out_end_ = 0;
925}
926
927template<class Allocator>
b32b8144 928inline
7c673cae 929void
b32b8144
FG
930basic_multi_buffer<Allocator>::
931copy_assign(
932 basic_multi_buffer const& other, std::false_type)
7c673cae 933{
b32b8144
FG
934 reset();
935 max_ = other.max_;
936 copy_from(other);
7c673cae
FG
937}
938
939template<class Allocator>
b32b8144 940inline
7c673cae 941void
b32b8144
FG
942basic_multi_buffer<Allocator>::
943copy_assign(
944 basic_multi_buffer const& other, std::true_type)
7c673cae 945{
b32b8144
FG
946 reset();
947 max_ = other.max_;
7c673cae 948 this->member() = other.member();
b32b8144 949 copy_from(other);
7c673cae
FG
950}
951
952template<class Allocator>
b32b8144 953inline
7c673cae 954void
b32b8144
FG
955basic_multi_buffer<Allocator>::
956swap(basic_multi_buffer& other)
7c673cae 957{
b32b8144
FG
958 swap(other, typename
959 alloc_traits::propagate_on_container_swap{});
960}
961
962template<class Allocator>
963inline
964void
965basic_multi_buffer<Allocator>::
966swap(basic_multi_buffer& other, std::true_type)
967{
968 using std::swap;
969 auto const at_end0 =
970 out_ == list_.end();
971 auto const at_end1 =
972 other.out_ == other.list_.end();
973 swap(this->member(), other.member());
974 swap(list_, other.list_);
975 swap(out_, other.out_);
976 if(at_end1)
977 out_ = list_.end();
978 if(at_end0)
979 other.out_ = other.list_.end();
980 swap(in_size_, other.in_size_);
981 swap(in_pos_, other.in_pos_);
982 swap(out_pos_, other.out_pos_);
983 swap(out_end_, other.out_end_);
984}
985
986template<class Allocator>
987inline
988void
989basic_multi_buffer<Allocator>::
990swap(basic_multi_buffer& other, std::false_type)
991{
992 BOOST_ASSERT(this->member() == other.member());
993 using std::swap;
994 auto const at_end0 =
995 out_ == list_.end();
996 auto const at_end1 =
997 other.out_ == other.list_.end();
998 swap(list_, other.list_);
999 swap(out_, other.out_);
1000 if(at_end1)
1001 out_ = list_.end();
1002 if(at_end0)
1003 other.out_ = other.list_.end();
1004 swap(in_size_, other.in_size_);
1005 swap(in_pos_, other.in_pos_);
1006 swap(out_pos_, other.out_pos_);
1007 swap(out_end_, other.out_end_);
1008}
1009
1010template<class Allocator>
1011void
1012swap(
1013 basic_multi_buffer<Allocator>& lhs,
1014 basic_multi_buffer<Allocator>& rhs)
1015{
1016 lhs.swap(rhs);
7c673cae
FG
1017}
1018
1019template<class Allocator>
1020void
b32b8144
FG
1021basic_multi_buffer<Allocator>::
1022debug_check() const
7c673cae
FG
1023{
1024#ifndef NDEBUG
1025 using boost::asio::buffer_size;
1026 BOOST_ASSERT(buffer_size(data()) == in_size_);
1027 if(list_.empty())
1028 {
1029 BOOST_ASSERT(in_pos_ == 0);
1030 BOOST_ASSERT(in_size_ == 0);
1031 BOOST_ASSERT(out_pos_ == 0);
1032 BOOST_ASSERT(out_end_ == 0);
1033 BOOST_ASSERT(out_ == list_.end());
1034 return;
1035 }
1036
1037 auto const& front = list_.front();
1038
1039 BOOST_ASSERT(in_pos_ < front.size());
1040
1041 if(out_ == list_.end())
1042 {
1043 BOOST_ASSERT(out_pos_ == 0);
1044 BOOST_ASSERT(out_end_ == 0);
1045 }
1046 else
1047 {
1048 auto const& out = *out_;
1049 auto const& back = list_.back();
1050
1051 BOOST_ASSERT(out_end_ <= back.size());
1052 BOOST_ASSERT(out_pos_ < out.size());
1053 BOOST_ASSERT(&out != &front || out_pos_ >= in_pos_);
1054 BOOST_ASSERT(&out != &front || out_pos_ - in_pos_ == in_size_);
1055 BOOST_ASSERT(&out != &back || out_pos_ <= out_end_);
1056 }
1057#endif
1058}
1059
7c673cae 1060} // beast
b32b8144 1061} // boost
7c673cae
FG
1062
1063#endif