2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_MULTI_BUFFER_HPP
11 #define BOOST_BEAST_MULTI_BUFFER_HPP
13 #include <boost/beast/core/detail/config.hpp>
14 #include <boost/beast/core/detail/allocator.hpp>
15 #include <boost/beast/core/detail/empty_base_optimization.hpp>
16 #include <boost/asio/buffer.hpp>
17 #include <boost/intrusive/list.hpp>
21 #include <type_traits>
26 /** A @b DynamicBuffer that uses multiple buffers internally.
28 The implementation uses a sequence of one or more character arrays
29 of varying sizes. Additional character array objects are appended to
30 the sequence to accommodate changes in the size of the character
33 @note Meets the requirements of @b DynamicBuffer.
35 @tparam Allocator The allocator to use for managing memory.
37 template<class Allocator>
38 class basic_multi_buffer
39 #if ! BOOST_BEAST_DOXYGEN
40 : private detail::empty_base_optimization<
41 typename detail::allocator_traits<Allocator>::
42 template rebind_alloc<char>>
45 using base_alloc_type = typename
46 detail::allocator_traits<Allocator>::
47 template rebind_alloc<char>;
49 // Storage for the list of buffers representing the input
50 // and output sequences. The allocation for each element
51 // contains `element` followed by raw storage bytes.
54 using alloc_traits = detail::allocator_traits<base_alloc_type>;
55 using list_type = typename boost::intrusive::make_list<element,
56 boost::intrusive::constant_time_size<true>>::type;
57 using iter = typename list_type::iterator;
58 using const_iter = typename list_type::const_iterator;
60 using size_type = typename alloc_traits::size_type;
61 using const_buffer = boost::asio::const_buffer;
62 using mutable_buffer = boost::asio::mutable_buffer;
64 static_assert(std::is_base_of<std::bidirectional_iterator_tag,
65 typename std::iterator_traits<iter>::iterator_category>::value,
66 "BidirectionalIterator requirements not met");
68 static_assert(std::is_base_of<std::bidirectional_iterator_tag,
69 typename std::iterator_traits<const_iter>::iterator_category>::value,
70 "BidirectionalIterator requirements not met");
73 (std::numeric_limits<std::size_t>::max)();
74 list_type list_; // list of allocated buffers
75 iter out_; // element that contains out_pos_
76 size_type in_size_ = 0; // size of the input sequence
77 size_type in_pos_ = 0; // input offset in list_.front()
78 size_type out_pos_ = 0; // output offset in *out_
79 size_type out_end_ = 0; // output end offset in list_.back()
82 /// The type of allocator used.
83 using allocator_type = Allocator;
85 #if BOOST_BEAST_DOXYGEN
86 /// The type used to represent the input sequence as a list of buffers.
87 using const_buffers_type = implementation_defined;
89 /// The type used to represent the output sequence as a list of buffers.
90 using mutable_buffers_type = implementation_defined;
93 class const_buffers_type;
95 class mutable_buffers_type;
100 ~basic_multi_buffer();
104 Upon construction, capacity will be zero.
106 basic_multi_buffer();
110 @param limit The setting for @ref max_size.
113 basic_multi_buffer(std::size_t limit);
117 @param alloc The allocator to use.
120 basic_multi_buffer(Allocator const& alloc);
124 @param limit The setting for @ref max_size.
126 @param alloc The allocator to use.
129 std::size_t limit, Allocator const& alloc);
133 After the move, `*this` will have an empty output sequence.
135 @param other The object to move from. After the move,
136 The object's state will be as if constructed using
137 its current allocator and limit.
139 basic_multi_buffer(basic_multi_buffer&& other);
143 After the move, `*this` will have an empty output sequence.
145 @param other The object to move from. After the move,
146 The object's state will be as if constructed using
147 its current allocator and limit.
149 @param alloc The allocator to use.
151 basic_multi_buffer(basic_multi_buffer&& other,
152 Allocator const& alloc);
154 /** Copy constructor.
156 @param other The object to copy from.
158 basic_multi_buffer(basic_multi_buffer const& other);
162 @param other The object to copy from.
164 @param alloc The allocator to use.
166 basic_multi_buffer(basic_multi_buffer const& other,
167 Allocator const& alloc);
169 /** Copy constructor.
171 @param other The object to copy from.
173 template<class OtherAlloc>
174 basic_multi_buffer(basic_multi_buffer<
175 OtherAlloc> const& other);
177 /** Copy constructor.
179 @param other The object to copy from.
181 @param alloc The allocator to use.
183 template<class OtherAlloc>
184 basic_multi_buffer(basic_multi_buffer<
185 OtherAlloc> const& other, allocator_type const& alloc);
189 After the move, `*this` will have an empty output sequence.
191 @param other The object to move from. After the move,
192 The object's state will be as if constructed using
193 its current allocator and limit.
196 operator=(basic_multi_buffer&& other);
200 After the copy, `*this` will have an empty output sequence.
202 @param other The object to copy from.
204 basic_multi_buffer& operator=(basic_multi_buffer const& other);
208 After the copy, `*this` will have an empty output sequence.
210 @param other The object to copy from.
212 template<class OtherAlloc>
213 basic_multi_buffer& operator=(
214 basic_multi_buffer<OtherAlloc> const& other);
216 /// Returns a copy of the associated allocator.
218 get_allocator() const
220 return this->member();
223 /// Returns the size of the input sequence.
230 /// Returns the permitted maximum sum of the sizes of the input and output sequence.
237 /// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation.
241 /** Get a list of buffers that represents the input sequence.
243 @note These buffers remain valid across subsequent calls to `prepare`.
248 /** Get a list of buffers that represents the output sequence, with the given size.
250 @note Buffers representing the input sequence acquired prior to
251 this call remain valid.
254 prepare(size_type n);
256 /** Move bytes from the output sequence to the input sequence.
258 @note Buffers representing the input sequence acquired prior to
259 this call remain valid.
264 /// Remove bytes from the input sequence.
266 consume(size_type n);
268 template<class Alloc>
272 basic_multi_buffer<Alloc>& lhs,
273 basic_multi_buffer<Alloc>& rhs);
276 template<class OtherAlloc>
277 friend class basic_multi_buffer;
285 template<class DynamicBuffer>
287 copy_from(DynamicBuffer const& other);
290 move_assign(basic_multi_buffer& other, std::false_type);
293 move_assign(basic_multi_buffer& other, std::true_type);
296 copy_assign(basic_multi_buffer const& other, std::false_type);
299 copy_assign(basic_multi_buffer const& other, std::true_type);
302 swap(basic_multi_buffer&);
305 swap(basic_multi_buffer&, std::true_type);
308 swap(basic_multi_buffer&, std::false_type);
314 /// A typical multi buffer
315 using multi_buffer = basic_multi_buffer<std::allocator<char>>;
320 #include <boost/beast/core/impl/multi_buffer.ipp>