]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // Copyright (c) 2016-2017 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/beast | |
8 | // | |
9 | ||
10 | #ifndef BOOST_BEAST_MULTI_BUFFER_HPP | |
11 | #define BOOST_BEAST_MULTI_BUFFER_HPP | |
12 | ||
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> | |
18 | #include <iterator> | |
19 | #include <limits> | |
20 | #include <memory> | |
21 | #include <type_traits> | |
22 | ||
23 | namespace boost { | |
24 | namespace beast { | |
25 | ||
26 | /** A @b DynamicBuffer that uses multiple buffers internally. | |
27 | ||
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 | |
31 | sequence. | |
32 | ||
33 | @note Meets the requirements of @b DynamicBuffer. | |
34 | ||
35 | @tparam Allocator The allocator to use for managing memory. | |
36 | */ | |
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>> | |
43 | #endif | |
44 | { | |
45 | using base_alloc_type = typename | |
46 | detail::allocator_traits<Allocator>:: | |
47 | template rebind_alloc<char>; | |
48 | ||
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. | |
52 | class element; | |
53 | ||
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; | |
59 | ||
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; | |
63 | ||
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"); | |
67 | ||
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"); | |
71 | ||
72 | std::size_t max_ = | |
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() | |
80 | ||
81 | public: | |
82 | /// The type of allocator used. | |
83 | using allocator_type = Allocator; | |
84 | ||
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; | |
88 | ||
89 | /// The type used to represent the output sequence as a list of buffers. | |
90 | using mutable_buffers_type = implementation_defined; | |
91 | ||
92 | #else | |
93 | class const_buffers_type; | |
94 | ||
95 | class mutable_buffers_type; | |
96 | ||
97 | #endif | |
98 | ||
99 | /// Destructor | |
100 | ~basic_multi_buffer(); | |
101 | ||
102 | /** Constructor | |
103 | ||
104 | Upon construction, capacity will be zero. | |
105 | */ | |
106 | basic_multi_buffer(); | |
107 | ||
108 | /** Constructor. | |
109 | ||
110 | @param limit The setting for @ref max_size. | |
111 | */ | |
112 | explicit | |
113 | basic_multi_buffer(std::size_t limit); | |
114 | ||
115 | /** Constructor. | |
116 | ||
117 | @param alloc The allocator to use. | |
118 | */ | |
119 | explicit | |
120 | basic_multi_buffer(Allocator const& alloc); | |
121 | ||
122 | /** Constructor. | |
123 | ||
124 | @param limit The setting for @ref max_size. | |
125 | ||
126 | @param alloc The allocator to use. | |
127 | */ | |
128 | basic_multi_buffer( | |
129 | std::size_t limit, Allocator const& alloc); | |
130 | ||
131 | /** Move constructor | |
132 | ||
133 | After the move, `*this` will have an empty output sequence. | |
134 | ||
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. | |
138 | */ | |
139 | basic_multi_buffer(basic_multi_buffer&& other); | |
140 | ||
141 | /** Move constructor | |
142 | ||
143 | After the move, `*this` will have an empty output sequence. | |
144 | ||
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. | |
148 | ||
149 | @param alloc The allocator to use. | |
150 | */ | |
151 | basic_multi_buffer(basic_multi_buffer&& other, | |
152 | Allocator const& alloc); | |
153 | ||
154 | /** Copy constructor. | |
155 | ||
156 | @param other The object to copy from. | |
157 | */ | |
158 | basic_multi_buffer(basic_multi_buffer const& other); | |
159 | ||
160 | /** Copy constructor | |
161 | ||
162 | @param other The object to copy from. | |
163 | ||
164 | @param alloc The allocator to use. | |
165 | */ | |
166 | basic_multi_buffer(basic_multi_buffer const& other, | |
167 | Allocator const& alloc); | |
168 | ||
169 | /** Copy constructor. | |
170 | ||
171 | @param other The object to copy from. | |
172 | */ | |
173 | template<class OtherAlloc> | |
174 | basic_multi_buffer(basic_multi_buffer< | |
175 | OtherAlloc> const& other); | |
176 | ||
177 | /** Copy constructor. | |
178 | ||
179 | @param other The object to copy from. | |
180 | ||
181 | @param alloc The allocator to use. | |
182 | */ | |
183 | template<class OtherAlloc> | |
184 | basic_multi_buffer(basic_multi_buffer< | |
185 | OtherAlloc> const& other, allocator_type const& alloc); | |
186 | ||
187 | /** Move assignment | |
188 | ||
189 | After the move, `*this` will have an empty output sequence. | |
190 | ||
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. | |
194 | */ | |
195 | basic_multi_buffer& | |
196 | operator=(basic_multi_buffer&& other); | |
197 | ||
198 | /** Copy assignment | |
199 | ||
200 | After the copy, `*this` will have an empty output sequence. | |
201 | ||
202 | @param other The object to copy from. | |
203 | */ | |
204 | basic_multi_buffer& operator=(basic_multi_buffer const& other); | |
205 | ||
206 | /** Copy assignment | |
207 | ||
208 | After the copy, `*this` will have an empty output sequence. | |
209 | ||
210 | @param other The object to copy from. | |
211 | */ | |
212 | template<class OtherAlloc> | |
213 | basic_multi_buffer& operator=( | |
214 | basic_multi_buffer<OtherAlloc> const& other); | |
215 | ||
216 | /// Returns a copy of the associated allocator. | |
217 | allocator_type | |
218 | get_allocator() const | |
219 | { | |
220 | return this->member(); | |
221 | } | |
222 | ||
223 | /// Returns the size of the input sequence. | |
224 | size_type | |
225 | size() const | |
226 | { | |
227 | return in_size_; | |
228 | } | |
229 | ||
230 | /// Returns the permitted maximum sum of the sizes of the input and output sequence. | |
231 | size_type | |
232 | max_size() const | |
233 | { | |
234 | return max_; | |
235 | } | |
236 | ||
237 | /// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation. | |
238 | std::size_t | |
239 | capacity() const; | |
240 | ||
241 | /** Get a list of buffers that represents the input sequence. | |
242 | ||
243 | @note These buffers remain valid across subsequent calls to `prepare`. | |
244 | */ | |
245 | const_buffers_type | |
246 | data() const; | |
247 | ||
248 | /** Get a list of buffers that represents the output sequence, with the given size. | |
249 | ||
250 | @note Buffers representing the input sequence acquired prior to | |
251 | this call remain valid. | |
252 | */ | |
253 | mutable_buffers_type | |
254 | prepare(size_type n); | |
255 | ||
256 | /** Move bytes from the output sequence to the input sequence. | |
257 | ||
258 | @note Buffers representing the input sequence acquired prior to | |
259 | this call remain valid. | |
260 | */ | |
261 | void | |
262 | commit(size_type n); | |
263 | ||
264 | /// Remove bytes from the input sequence. | |
265 | void | |
266 | consume(size_type n); | |
267 | ||
268 | template<class Alloc> | |
269 | friend | |
270 | void | |
271 | swap( | |
272 | basic_multi_buffer<Alloc>& lhs, | |
273 | basic_multi_buffer<Alloc>& rhs); | |
274 | ||
275 | private: | |
276 | template<class OtherAlloc> | |
277 | friend class basic_multi_buffer; | |
278 | ||
279 | void | |
280 | delete_list(); | |
281 | ||
282 | void | |
283 | reset(); | |
284 | ||
285 | template<class DynamicBuffer> | |
286 | void | |
287 | copy_from(DynamicBuffer const& other); | |
288 | ||
289 | void | |
290 | move_assign(basic_multi_buffer& other, std::false_type); | |
291 | ||
292 | void | |
293 | move_assign(basic_multi_buffer& other, std::true_type); | |
294 | ||
295 | void | |
296 | copy_assign(basic_multi_buffer const& other, std::false_type); | |
297 | ||
298 | void | |
299 | copy_assign(basic_multi_buffer const& other, std::true_type); | |
300 | ||
301 | void | |
302 | swap(basic_multi_buffer&); | |
303 | ||
304 | void | |
305 | swap(basic_multi_buffer&, std::true_type); | |
306 | ||
307 | void | |
308 | swap(basic_multi_buffer&, std::false_type); | |
309 | ||
310 | void | |
311 | debug_check() const; | |
312 | }; | |
313 | ||
314 | /// A typical multi buffer | |
315 | using multi_buffer = basic_multi_buffer<std::allocator<char>>; | |
316 | ||
317 | } // beast | |
318 | } // boost | |
319 | ||
320 | #include <boost/beast/core/impl/multi_buffer.ipp> | |
321 | ||
322 | #endif |