]>
Commit | Line | Data |
---|---|---|
b32b8144 | 1 | // |
92f5a8d4 | 2 | // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) |
b32b8144 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 | // | |
7 | // Official repository: https://github.com/boostorg/beast | |
8 | // | |
9 | ||
10 | #ifndef BOOST_BEAST_FLAT_BUFFER_HPP | |
11 | #define BOOST_BEAST_FLAT_BUFFER_HPP | |
12 | ||
13 | #include <boost/beast/core/detail/config.hpp> | |
14 | #include <boost/beast/core/detail/allocator.hpp> | |
b32b8144 | 15 | #include <boost/asio/buffer.hpp> |
92f5a8d4 | 16 | #include <boost/core/empty_value.hpp> |
b32b8144 FG |
17 | #include <limits> |
18 | #include <memory> | |
92f5a8d4 | 19 | #include <type_traits> |
b32b8144 FG |
20 | |
21 | namespace boost { | |
22 | namespace beast { | |
23 | ||
92f5a8d4 | 24 | /** A dynamic buffer providing buffer sequences of length one. |
b32b8144 | 25 | |
92f5a8d4 TL |
26 | A dynamic buffer encapsulates memory storage that may be |
27 | automatically resized as required, where the memory is | |
28 | divided into two regions: readable bytes followed by | |
29 | writable bytes. These memory regions are internal to | |
30 | the dynamic buffer, but direct access to the elements | |
31 | is provided to permit them to be efficiently used with | |
32 | I/O operations. | |
33 | ||
34 | Objects of this type meet the requirements of <em>DynamicBuffer</em> | |
35 | and have the following additional properties: | |
36 | ||
37 | @li A mutable buffer sequence representing the readable | |
38 | bytes is returned by @ref data when `this` is non-const. | |
b32b8144 FG |
39 | |
40 | @li A configurable maximum buffer size may be set upon | |
41 | construction. Attempts to exceed the buffer size will throw | |
42 | `std::length_error`. | |
43 | ||
92f5a8d4 TL |
44 | @li Buffer sequences representing the readable and writable |
45 | bytes, returned by @ref data and @ref prepare, will have | |
46 | length one. | |
47 | ||
b32b8144 FG |
48 | Upon construction, a maximum size for the buffer may be |
49 | specified. If this limit is exceeded, the `std::length_error` | |
50 | exception will be thrown. | |
51 | ||
52 | @note This class is designed for use with algorithms that | |
53 | take dynamic buffers as parameters, and are optimized | |
54 | for the case where the input sequence or output sequence | |
55 | is stored in a single contiguous buffer. | |
56 | */ | |
57 | template<class Allocator> | |
58 | class basic_flat_buffer | |
59 | #if ! BOOST_BEAST_DOXYGEN | |
92f5a8d4 | 60 | : private boost::empty_value< |
b32b8144 FG |
61 | typename detail::allocator_traits<Allocator>:: |
62 | template rebind_alloc<char>> | |
63 | #endif | |
64 | { | |
b32b8144 FG |
65 | template<class OtherAlloc> |
66 | friend class basic_flat_buffer; | |
67 | ||
68 | using base_alloc_type = typename | |
69 | detail::allocator_traits<Allocator>:: | |
70 | template rebind_alloc<char>; | |
71 | ||
92f5a8d4 TL |
72 | static bool constexpr default_nothrow = |
73 | std::is_nothrow_default_constructible<Allocator>::value; | |
74 | ||
b32b8144 | 75 | using alloc_traits = |
92f5a8d4 TL |
76 | beast::detail::allocator_traits<base_alloc_type>; |
77 | ||
78 | using pocma = typename | |
79 | alloc_traits::propagate_on_container_move_assignment; | |
80 | ||
81 | using pocca = typename | |
82 | alloc_traits::propagate_on_container_copy_assignment; | |
b32b8144 FG |
83 | |
84 | static | |
b32b8144 | 85 | std::size_t |
92f5a8d4 | 86 | dist(char const* first, char const* last) noexcept |
b32b8144 FG |
87 | { |
88 | return static_cast<std::size_t>(last - first); | |
89 | } | |
90 | ||
91 | char* begin_; | |
92 | char* in_; | |
93 | char* out_; | |
94 | char* last_; | |
95 | char* end_; | |
96 | std::size_t max_; | |
97 | ||
98 | public: | |
99 | /// The type of allocator used. | |
100 | using allocator_type = Allocator; | |
101 | ||
b32b8144 FG |
102 | /// Destructor |
103 | ~basic_flat_buffer(); | |
104 | ||
105 | /** Constructor | |
106 | ||
92f5a8d4 TL |
107 | After construction, @ref capacity will return zero, and |
108 | @ref max_size will return the largest value which may | |
109 | be passed to the allocator's `allocate` function. | |
b32b8144 | 110 | */ |
92f5a8d4 | 111 | basic_flat_buffer() noexcept(default_nothrow); |
b32b8144 FG |
112 | |
113 | /** Constructor | |
114 | ||
92f5a8d4 TL |
115 | After construction, @ref capacity will return zero, and |
116 | @ref max_size will return the specified value of `limit`. | |
b32b8144 | 117 | |
92f5a8d4 | 118 | @param limit The desired maximum size. |
b32b8144 FG |
119 | */ |
120 | explicit | |
92f5a8d4 TL |
121 | basic_flat_buffer( |
122 | std::size_t limit) noexcept(default_nothrow); | |
b32b8144 FG |
123 | |
124 | /** Constructor | |
125 | ||
92f5a8d4 TL |
126 | After construction, @ref capacity will return zero, and |
127 | @ref max_size will return the largest value which may | |
128 | be passed to the allocator's `allocate` function. | |
b32b8144 | 129 | |
92f5a8d4 TL |
130 | @param alloc The allocator to use for the object. |
131 | ||
132 | @esafe | |
133 | ||
134 | No-throw guarantee. | |
b32b8144 FG |
135 | */ |
136 | explicit | |
92f5a8d4 | 137 | basic_flat_buffer(Allocator const& alloc) noexcept; |
b32b8144 FG |
138 | |
139 | /** Constructor | |
140 | ||
92f5a8d4 TL |
141 | After construction, @ref capacity will return zero, and |
142 | @ref max_size will return the specified value of `limit`. | |
143 | ||
144 | @param limit The desired maximum size. | |
145 | ||
146 | @param alloc The allocator to use for the object. | |
b32b8144 | 147 | |
92f5a8d4 | 148 | @esafe |
b32b8144 | 149 | |
92f5a8d4 | 150 | No-throw guarantee. |
b32b8144 FG |
151 | */ |
152 | basic_flat_buffer( | |
92f5a8d4 TL |
153 | std::size_t limit, |
154 | Allocator const& alloc) noexcept; | |
b32b8144 | 155 | |
92f5a8d4 | 156 | /** Move Constructor |
b32b8144 | 157 | |
92f5a8d4 TL |
158 | The container is constructed with the contents of `other` |
159 | using move semantics. The maximum size will be the same | |
160 | as the moved-from object. | |
b32b8144 | 161 | |
92f5a8d4 TL |
162 | Buffer sequences previously obtained from `other` using |
163 | @ref data or @ref prepare remain valid after the move. | |
164 | ||
165 | @param other The object to move from. After the move, the | |
166 | moved-from object will have zero capacity, zero readable | |
167 | bytes, and zero writable bytes. | |
168 | ||
169 | @esafe | |
170 | ||
171 | No-throw guarantee. | |
b32b8144 | 172 | */ |
92f5a8d4 | 173 | basic_flat_buffer(basic_flat_buffer&& other) noexcept; |
b32b8144 | 174 | |
92f5a8d4 | 175 | /** Move Constructor |
b32b8144 | 176 | |
92f5a8d4 TL |
177 | Using `alloc` as the allocator for the new container, the |
178 | contents of `other` are moved. If `alloc != other.get_allocator()`, | |
179 | this results in a copy. The maximum size will be the same | |
180 | as the moved-from object. | |
181 | ||
182 | Buffer sequences previously obtained from `other` using | |
183 | @ref data or @ref prepare become invalid after the move. | |
b32b8144 FG |
184 | |
185 | @param other The object to move from. After the move, | |
92f5a8d4 TL |
186 | the moved-from object will have zero capacity, zero readable |
187 | bytes, and zero writable bytes. | |
188 | ||
189 | @param alloc The allocator to use for the object. | |
b32b8144 | 190 | |
92f5a8d4 TL |
191 | @throws std::length_error if `other.size()` exceeds the |
192 | maximum allocation size of `alloc`. | |
b32b8144 FG |
193 | */ |
194 | basic_flat_buffer( | |
92f5a8d4 TL |
195 | basic_flat_buffer&& other, |
196 | Allocator const& alloc); | |
b32b8144 | 197 | |
92f5a8d4 TL |
198 | /** Copy Constructor |
199 | ||
200 | This container is constructed with the contents of `other` | |
201 | using copy semantics. The maximum size will be the same | |
202 | as the copied object. | |
b32b8144 FG |
203 | |
204 | @param other The object to copy from. | |
92f5a8d4 TL |
205 | |
206 | @throws std::length_error if `other.size()` exceeds the | |
207 | maximum allocation size of the allocator. | |
b32b8144 FG |
208 | */ |
209 | basic_flat_buffer(basic_flat_buffer const& other); | |
210 | ||
92f5a8d4 TL |
211 | /** Copy Constructor |
212 | ||
213 | This container is constructed with the contents of `other` | |
214 | using copy semantics and the specified allocator. The maximum | |
215 | size will be the same as the copied object. | |
b32b8144 FG |
216 | |
217 | @param other The object to copy from. | |
218 | ||
92f5a8d4 TL |
219 | @param alloc The allocator to use for the object. |
220 | ||
221 | @throws std::length_error if `other.size()` exceeds the | |
222 | maximum allocation size of `alloc`. | |
b32b8144 | 223 | */ |
92f5a8d4 TL |
224 | basic_flat_buffer( |
225 | basic_flat_buffer const& other, | |
b32b8144 FG |
226 | Allocator const& alloc); |
227 | ||
92f5a8d4 TL |
228 | /** Copy Constructor |
229 | ||
230 | This container is constructed with the contents of `other` | |
231 | using copy semantics. The maximum size will be the same | |
232 | as the copied object. | |
b32b8144 FG |
233 | |
234 | @param other The object to copy from. | |
92f5a8d4 TL |
235 | |
236 | @throws std::length_error if `other.size()` exceeds the | |
237 | maximum allocation size of the allocator. | |
b32b8144 FG |
238 | */ |
239 | template<class OtherAlloc> | |
240 | basic_flat_buffer( | |
92f5a8d4 TL |
241 | basic_flat_buffer<OtherAlloc> const& other) |
242 | noexcept(default_nothrow); | |
b32b8144 | 243 | |
92f5a8d4 TL |
244 | /** Copy Constructor |
245 | ||
246 | This container is constructed with the contents of `other` | |
247 | using copy semantics. The maximum size will be the same | |
248 | as the copied object. | |
b32b8144 FG |
249 | |
250 | @param other The object to copy from. | |
251 | ||
92f5a8d4 TL |
252 | @param alloc The allocator to use for the object. |
253 | ||
254 | @throws std::length_error if `other.size()` exceeds the | |
255 | maximum allocation size of `alloc`. | |
b32b8144 FG |
256 | */ |
257 | template<class OtherAlloc> | |
258 | basic_flat_buffer( | |
259 | basic_flat_buffer<OtherAlloc> const& other, | |
92f5a8d4 TL |
260 | Allocator const& alloc); |
261 | ||
262 | /** Move Assignment | |
b32b8144 | 263 | |
92f5a8d4 TL |
264 | The container is assigned with the contents of `other` |
265 | using move semantics. The maximum size will be the same | |
266 | as the moved-from object. | |
b32b8144 | 267 | |
92f5a8d4 TL |
268 | Buffer sequences previously obtained from `other` using |
269 | @ref data or @ref prepare remain valid after the move. | |
b32b8144 FG |
270 | |
271 | @param other The object to move from. After the move, | |
92f5a8d4 TL |
272 | the moved-from object will have zero capacity, zero readable |
273 | bytes, and zero writable bytes. | |
274 | ||
275 | @esafe | |
276 | ||
277 | No-throw guarantee. | |
b32b8144 FG |
278 | */ |
279 | basic_flat_buffer& | |
92f5a8d4 | 280 | operator=(basic_flat_buffer&& other) noexcept; |
b32b8144 | 281 | |
92f5a8d4 | 282 | /** Copy Assignment |
b32b8144 | 283 | |
92f5a8d4 TL |
284 | The container is assigned with the contents of `other` |
285 | using copy semantics. The maximum size will be the same | |
286 | as the copied object. | |
287 | ||
288 | After the copy, `this` will have zero writable bytes. | |
b32b8144 FG |
289 | |
290 | @param other The object to copy from. | |
92f5a8d4 TL |
291 | |
292 | @throws std::length_error if `other.size()` exceeds the | |
293 | maximum allocation size of the allocator. | |
b32b8144 FG |
294 | */ |
295 | basic_flat_buffer& | |
296 | operator=(basic_flat_buffer const& other); | |
297 | ||
298 | /** Copy assignment | |
299 | ||
92f5a8d4 TL |
300 | The container is assigned with the contents of `other` |
301 | using copy semantics. The maximum size will be the same | |
302 | as the copied object. | |
303 | ||
304 | After the copy, `this` will have zero writable bytes. | |
b32b8144 FG |
305 | |
306 | @param other The object to copy from. | |
92f5a8d4 TL |
307 | |
308 | @throws std::length_error if `other.size()` exceeds the | |
309 | maximum allocation size of the allocator. | |
b32b8144 FG |
310 | */ |
311 | template<class OtherAlloc> | |
312 | basic_flat_buffer& | |
313 | operator=(basic_flat_buffer<OtherAlloc> const& other); | |
314 | ||
92f5a8d4 | 315 | /// Returns a copy of the allocator used. |
b32b8144 FG |
316 | allocator_type |
317 | get_allocator() const | |
318 | { | |
92f5a8d4 TL |
319 | return this->get(); |
320 | } | |
321 | ||
322 | /** Set the maximum allowed capacity | |
323 | ||
324 | This function changes the currently configured upper limit | |
325 | on capacity to the specified value. | |
326 | ||
327 | @param n The maximum number of bytes ever allowed for capacity. | |
328 | ||
329 | @esafe | |
330 | ||
331 | No-throw guarantee. | |
332 | */ | |
333 | void | |
334 | max_size(std::size_t n) noexcept | |
335 | { | |
336 | max_ = n; | |
b32b8144 FG |
337 | } |
338 | ||
92f5a8d4 TL |
339 | /** Guarantee a minimum capacity |
340 | ||
341 | This function adjusts the internal storage (if necessary) | |
342 | to guarantee space for at least `n` bytes. | |
343 | ||
344 | Buffer sequences previously obtained using @ref data or | |
345 | @ref prepare become invalid. | |
346 | ||
347 | @param n The minimum number of byte for the new capacity. | |
348 | If this value is greater than the maximum size, then the | |
349 | maximum size will be adjusted upwards to this value. | |
350 | ||
351 | @esafe | |
352 | ||
353 | Basic guarantee. | |
354 | ||
355 | @throws std::length_error if n is larger than the maximum | |
356 | allocation size of the allocator. | |
357 | */ | |
358 | void | |
359 | reserve(std::size_t n); | |
360 | ||
f67539c2 | 361 | /** Request the removal of unused capacity. |
92f5a8d4 | 362 | |
f67539c2 TL |
363 | This function attempts to reduce @ref capacity() |
364 | to @ref size(), which may not succeed. | |
92f5a8d4 TL |
365 | |
366 | @esafe | |
367 | ||
f67539c2 | 368 | No-throw guarantee. |
92f5a8d4 TL |
369 | */ |
370 | void | |
f67539c2 | 371 | shrink_to_fit() noexcept; |
92f5a8d4 TL |
372 | |
373 | /** Set the size of the readable and writable bytes to zero. | |
374 | ||
375 | This clears the buffer without changing capacity. | |
376 | Buffer sequences previously obtained using @ref data or | |
377 | @ref prepare become invalid. | |
378 | ||
379 | @esafe | |
380 | ||
381 | No-throw guarantee. | |
382 | */ | |
383 | void | |
384 | clear() noexcept; | |
385 | ||
386 | /// Exchange two dynamic buffers | |
387 | template<class Alloc> | |
388 | friend | |
389 | void | |
390 | swap( | |
391 | basic_flat_buffer<Alloc>&, | |
392 | basic_flat_buffer<Alloc>&); | |
393 | ||
394 | //-------------------------------------------------------------------------- | |
395 | ||
396 | /// The ConstBufferSequence used to represent the readable bytes. | |
397 | using const_buffers_type = net::const_buffer; | |
398 | ||
92f5a8d4 TL |
399 | /// The MutableBufferSequence used to represent the writable bytes. |
400 | using mutable_buffers_type = net::mutable_buffer; | |
401 | ||
402 | /// Returns the number of readable bytes. | |
b32b8144 | 403 | std::size_t |
92f5a8d4 | 404 | size() const noexcept |
b32b8144 FG |
405 | { |
406 | return dist(in_, out_); | |
407 | } | |
408 | ||
92f5a8d4 | 409 | /// Return the maximum number of bytes, both readable and writable, that can ever be held. |
b32b8144 | 410 | std::size_t |
92f5a8d4 | 411 | max_size() const noexcept |
b32b8144 FG |
412 | { |
413 | return max_; | |
414 | } | |
415 | ||
92f5a8d4 | 416 | /// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation. |
b32b8144 | 417 | std::size_t |
92f5a8d4 | 418 | capacity() const noexcept |
b32b8144 FG |
419 | { |
420 | return dist(begin_, end_); | |
421 | } | |
422 | ||
92f5a8d4 | 423 | /// Returns a constant buffer sequence representing the readable bytes |
b32b8144 | 424 | const_buffers_type |
92f5a8d4 | 425 | data() const noexcept |
b32b8144 FG |
426 | { |
427 | return {in_, dist(in_, out_)}; | |
428 | } | |
429 | ||
92f5a8d4 TL |
430 | /// Returns a constant buffer sequence representing the readable bytes |
431 | const_buffers_type | |
432 | cdata() const noexcept | |
433 | { | |
434 | return data(); | |
435 | } | |
b32b8144 | 436 | |
92f5a8d4 | 437 | /// Returns a mutable buffer sequence representing the readable bytes |
f67539c2 | 438 | mutable_buffers_type |
92f5a8d4 TL |
439 | data() noexcept |
440 | { | |
441 | return {in_, dist(in_, out_)}; | |
442 | } | |
b32b8144 | 443 | |
92f5a8d4 TL |
444 | /** Returns a mutable buffer sequence representing writable bytes. |
445 | ||
446 | Returns a mutable buffer sequence representing the writable | |
447 | bytes containing exactly `n` bytes of storage. Memory may be | |
448 | reallocated as needed. | |
b32b8144 | 449 | |
92f5a8d4 TL |
450 | All buffers sequences previously obtained using |
451 | @ref data or @ref prepare become invalid. | |
b32b8144 | 452 | |
92f5a8d4 TL |
453 | @param n The desired number of bytes in the returned buffer |
454 | sequence. | |
b32b8144 | 455 | |
92f5a8d4 TL |
456 | @throws std::length_error if `size() + n` exceeds either |
457 | `max_size()` or the allocator's maximum allocation size. | |
b32b8144 | 458 | |
92f5a8d4 | 459 | @esafe |
b32b8144 | 460 | |
92f5a8d4 | 461 | Strong guarantee. |
b32b8144 | 462 | */ |
92f5a8d4 TL |
463 | mutable_buffers_type |
464 | prepare(std::size_t n); | |
b32b8144 | 465 | |
92f5a8d4 | 466 | /** Append writable bytes to the readable bytes. |
b32b8144 | 467 | |
92f5a8d4 TL |
468 | Appends n bytes from the start of the writable bytes to the |
469 | end of the readable bytes. The remainder of the writable bytes | |
470 | are discarded. If n is greater than the number of writable | |
471 | bytes, all writable bytes are appended to the readable bytes. | |
b32b8144 | 472 | |
92f5a8d4 TL |
473 | All buffers sequences previously obtained using |
474 | @ref data or @ref prepare become invalid. | |
b32b8144 | 475 | |
92f5a8d4 TL |
476 | @param n The number of bytes to append. If this number |
477 | is greater than the number of writable bytes, all | |
478 | writable bytes are appended. | |
b32b8144 | 479 | |
92f5a8d4 | 480 | @esafe |
b32b8144 | 481 | |
92f5a8d4 TL |
482 | No-throw guarantee. |
483 | */ | |
b32b8144 | 484 | void |
92f5a8d4 TL |
485 | commit(std::size_t n) noexcept |
486 | { | |
487 | out_ += (std::min)(n, dist(out_, last_)); | |
488 | } | |
b32b8144 | 489 | |
92f5a8d4 | 490 | /** Remove bytes from beginning of the readable bytes. |
b32b8144 | 491 | |
92f5a8d4 | 492 | Removes n bytes from the beginning of the readable bytes. |
b32b8144 | 493 | |
92f5a8d4 TL |
494 | All buffers sequences previously obtained using |
495 | @ref data or @ref prepare become invalid. | |
b32b8144 | 496 | |
92f5a8d4 TL |
497 | @param n The number of bytes to remove. If this number |
498 | is greater than the number of readable bytes, all | |
499 | readable bytes are removed. | |
b32b8144 | 500 | |
92f5a8d4 | 501 | @esafe |
b32b8144 | 502 | |
92f5a8d4 TL |
503 | No-throw guarantee. |
504 | */ | |
b32b8144 | 505 | void |
92f5a8d4 TL |
506 | consume(std::size_t n) noexcept; |
507 | ||
508 | private: | |
509 | template<class OtherAlloc> | |
510 | void copy_from(basic_flat_buffer<OtherAlloc> const& other); | |
511 | void move_assign(basic_flat_buffer&, std::true_type); | |
512 | void move_assign(basic_flat_buffer&, std::false_type); | |
513 | void copy_assign(basic_flat_buffer const&, std::true_type); | |
514 | void copy_assign(basic_flat_buffer const&, std::false_type); | |
515 | void swap(basic_flat_buffer&); | |
516 | void swap(basic_flat_buffer&, std::true_type); | |
517 | void swap(basic_flat_buffer&, std::false_type); | |
518 | char* alloc(std::size_t n); | |
b32b8144 FG |
519 | }; |
520 | ||
92f5a8d4 | 521 | /// A flat buffer which uses the default allocator. |
b32b8144 FG |
522 | using flat_buffer = |
523 | basic_flat_buffer<std::allocator<char>>; | |
524 | ||
525 | } // beast | |
526 | } // boost | |
527 | ||
92f5a8d4 | 528 | #include <boost/beast/core/impl/flat_buffer.hpp> |
b32b8144 FG |
529 | |
530 | #endif |