]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/beast/core/multi_buffer.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / beast / core / multi_buffer.hpp
1 //
2 // Copyright (c) 2016-2019 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/asio/buffer.hpp>
16 #include <boost/core/empty_value.hpp>
17 #include <boost/intrusive/list.hpp>
18 #include <boost/type_traits/type_with_alignment.hpp>
19 #include <iterator>
20 #include <limits>
21 #include <memory>
22 #include <type_traits>
23
24 namespace boost {
25 namespace beast {
26
27 /** A dynamic buffer providing sequences of variable length.
28
29 A dynamic buffer encapsulates memory storage that may be
30 automatically resized as required, where the memory is
31 divided into two regions: readable bytes followed by
32 writable bytes. These memory regions are internal to
33 the dynamic buffer, but direct access to the elements
34 is provided to permit them to be efficiently used with
35 I/O operations.
36
37 The implementation uses a sequence of one or more byte
38 arrays of varying sizes to represent the readable and
39 writable bytes. Additional byte array objects are
40 appended to the sequence to accommodate changes in the
41 desired size. The behavior and implementation of this
42 container is most similar to `std::deque`.
43
44 Objects of this type meet the requirements of <em>DynamicBuffer</em>
45 and have the following additional properties:
46
47 @li A mutable buffer sequence representing the readable
48 bytes is returned by @ref data when `this` is non-const.
49
50 @li Buffer sequences representing the readable and writable
51 bytes, returned by @ref data and @ref prepare, may have
52 length greater than one.
53
54 @li A configurable maximum size may be set upon construction
55 and adjusted afterwards. Calls to @ref prepare that would
56 exceed this size will throw `std::length_error`.
57
58 @li Sequences previously obtained using @ref data remain
59 valid after calls to @ref prepare or @ref commit.
60
61 @tparam Allocator The allocator to use for managing memory.
62 */
63 template<class Allocator>
64 class basic_multi_buffer
65 #if ! BOOST_BEAST_DOXYGEN
66 : private boost::empty_value<Allocator>
67 #endif
68 {
69 // Fancy pointers are not supported
70 static_assert(std::is_pointer<typename
71 std::allocator_traits<Allocator>::pointer>::value,
72 "Allocator must use regular pointers");
73
74 static bool constexpr default_nothrow =
75 std::is_nothrow_default_constructible<Allocator>::value;
76
77 // Storage for the list of buffers representing the input
78 // and output sequences. The allocation for each element
79 // contains `element` followed by raw storage bytes.
80 class element
81 : public boost::intrusive::list_base_hook<
82 boost::intrusive::link_mode<
83 boost::intrusive::normal_link>>
84 {
85 using size_type = typename
86 detail::allocator_traits<Allocator>::size_type;
87
88 size_type const size_;
89
90 public:
91 element(element const&) = delete;
92
93 explicit
94 element(size_type n) noexcept
95 : size_(n)
96 {
97 }
98
99 size_type
100 size() const noexcept
101 {
102 return size_;
103 }
104
105 char*
106 data() const noexcept
107 {
108 return const_cast<char*>(
109 reinterpret_cast<char const*>(this + 1));
110 }
111 };
112
113 template<bool>
114 class subrange;
115
116 using size_type = typename
117 detail::allocator_traits<Allocator>::size_type;
118
119 using align_type = typename
120 boost::type_with_alignment<alignof(element)>::type;
121
122 using rebind_type = typename
123 beast::detail::allocator_traits<Allocator>::
124 template rebind_alloc<align_type>;
125
126 using alloc_traits =
127 beast::detail::allocator_traits<rebind_type>;
128
129 using list_type = typename boost::intrusive::make_list<
130 element, boost::intrusive::constant_time_size<true>>::type;
131
132 using iter = typename list_type::iterator;
133
134 using const_iter = typename list_type::const_iterator;
135
136 using pocma = typename
137 alloc_traits::propagate_on_container_move_assignment;
138
139 using pocca = typename
140 alloc_traits::propagate_on_container_copy_assignment;
141
142 static_assert(std::is_base_of<std::bidirectional_iterator_tag,
143 typename std::iterator_traits<iter>::iterator_category>::value,
144 "BidirectionalIterator type requirements not met");
145
146 static_assert(std::is_base_of<std::bidirectional_iterator_tag,
147 typename std::iterator_traits<const_iter>::iterator_category>::value,
148 "BidirectionalIterator type requirements not met");
149
150 std::size_t max_;
151 list_type list_; // list of allocated buffers
152 iter out_; // element that contains out_pos_
153 size_type in_size_ = 0; // size of the input sequence
154 size_type in_pos_ = 0; // input offset in list_.front()
155 size_type out_pos_ = 0; // output offset in *out_
156 size_type out_end_ = 0; // output end offset in list_.back()
157
158 public:
159 #if BOOST_BEAST_DOXYGEN
160 /// The ConstBufferSequence used to represent the readable bytes.
161 using const_buffers_type = __implementation_defined__;
162
163 /// The MutableBufferSequence used to represent the writable bytes.
164 using mutable_buffers_type = __implementation_defined__;
165 #else
166 using const_buffers_type = subrange<false>;
167
168 using mutable_buffers_type = subrange<true>;
169 #endif
170
171 /// The type of allocator used.
172 using allocator_type = Allocator;
173
174 /// Destructor
175 ~basic_multi_buffer();
176
177 /** Constructor
178
179 After construction, @ref capacity will return zero, and
180 @ref max_size will return the largest value which may
181 be passed to the allocator's `allocate` function.
182 */
183 basic_multi_buffer() noexcept(default_nothrow);
184
185 /** Constructor
186
187 After construction, @ref capacity will return zero, and
188 @ref max_size will return the specified value of `limit`.
189
190 @param limit The desired maximum size.
191 */
192 explicit
193 basic_multi_buffer(
194 std::size_t limit) noexcept(default_nothrow);
195
196 /** Constructor
197
198 After construction, @ref capacity will return zero, and
199 @ref max_size will return the largest value which may
200 be passed to the allocator's `allocate` function.
201
202 @param alloc The allocator to use for the object.
203
204 @esafe
205
206 No-throw guarantee.
207 */
208 explicit
209 basic_multi_buffer(Allocator const& alloc) noexcept;
210
211 /** Constructor
212
213 After construction, @ref capacity will return zero, and
214 @ref max_size will return the specified value of `limit`.
215
216 @param limit The desired maximum size.
217
218 @param alloc The allocator to use for the object.
219
220 @esafe
221
222 No-throw guarantee.
223 */
224 basic_multi_buffer(
225 std::size_t limit, Allocator const& alloc) noexcept;
226
227 /** Move Constructor
228
229 The container is constructed with the contents of `other`
230 using move semantics. The maximum size will be the same
231 as the moved-from object.
232
233 Buffer sequences previously obtained from `other` using
234 @ref data or @ref prepare remain valid after the move.
235
236 @param other The object to move from. After the move, the
237 moved-from object will have zero capacity, zero readable
238 bytes, and zero writable bytes.
239
240 @esafe
241
242 No-throw guarantee.
243 */
244 basic_multi_buffer(basic_multi_buffer&& other) noexcept;
245
246 /** Move Constructor
247
248 Using `alloc` as the allocator for the new container, the
249 contents of `other` are moved. If `alloc != other.get_allocator()`,
250 this results in a copy. The maximum size will be the same
251 as the moved-from object.
252
253 Buffer sequences previously obtained from `other` using
254 @ref data or @ref prepare become invalid after the move.
255
256 @param other The object to move from. After the move,
257 the moved-from object will have zero capacity, zero readable
258 bytes, and zero writable bytes.
259
260 @param alloc The allocator to use for the object.
261
262 @throws std::length_error if `other.size()` exceeds the
263 maximum allocation size of `alloc`.
264 */
265 basic_multi_buffer(
266 basic_multi_buffer&& other,
267 Allocator const& alloc);
268
269 /** Copy Constructor
270
271 This container is constructed with the contents of `other`
272 using copy semantics. The maximum size will be the same
273 as the copied object.
274
275 @param other The object to copy from.
276
277 @throws std::length_error if `other.size()` exceeds the
278 maximum allocation size of the allocator.
279 */
280 basic_multi_buffer(basic_multi_buffer const& other);
281
282 /** Copy Constructor
283
284 This container is constructed with the contents of `other`
285 using copy semantics and the specified allocator. The maximum
286 size will be the same as the copied object.
287
288 @param other The object to copy from.
289
290 @param alloc The allocator to use for the object.
291
292 @throws std::length_error if `other.size()` exceeds the
293 maximum allocation size of `alloc`.
294 */
295 basic_multi_buffer(basic_multi_buffer const& other,
296 Allocator const& alloc);
297
298 /** Copy Constructor
299
300 This container is constructed with the contents of `other`
301 using copy semantics. The maximum size will be the same
302 as the copied object.
303
304 @param other The object to copy from.
305
306 @throws std::length_error if `other.size()` exceeds the
307 maximum allocation size of the allocator.
308 */
309 template<class OtherAlloc>
310 basic_multi_buffer(basic_multi_buffer<
311 OtherAlloc> const& other);
312
313 /** Copy Constructor
314
315 This container is constructed with the contents of `other`
316 using copy semantics. The maximum size will be the same
317 as the copied object.
318
319 @param other The object to copy from.
320
321 @param alloc The allocator to use for the object.
322
323 @throws std::length_error if `other.size()` exceeds the
324 maximum allocation size of `alloc`.
325 */
326 template<class OtherAlloc>
327 basic_multi_buffer(
328 basic_multi_buffer<OtherAlloc> const& other,
329 allocator_type const& alloc);
330
331 /** Move Assignment
332
333 The container is assigned with the contents of `other`
334 using move semantics. The maximum size will be the same
335 as the moved-from object.
336
337 Buffer sequences previously obtained from `other` using
338 @ref data or @ref prepare remain valid after the move.
339
340 @param other The object to move from. After the move,
341 the moved-from object will have zero capacity, zero readable
342 bytes, and zero writable bytes.
343 */
344 basic_multi_buffer&
345 operator=(basic_multi_buffer&& other);
346
347 /** Copy Assignment
348
349 The container is assigned with the contents of `other`
350 using copy semantics. The maximum size will be the same
351 as the copied object.
352
353 After the copy, `this` will have zero writable bytes.
354
355 @param other The object to copy from.
356
357 @throws std::length_error if `other.size()` exceeds the
358 maximum allocation size of the allocator.
359 */
360 basic_multi_buffer& operator=(
361 basic_multi_buffer const& other);
362
363 /** Copy Assignment
364
365 The container is assigned with the contents of `other`
366 using copy semantics. The maximum size will be the same
367 as the copied object.
368
369 After the copy, `this` will have zero writable bytes.
370
371 @param other The object to copy from.
372
373 @throws std::length_error if `other.size()` exceeds the
374 maximum allocation size of the allocator.
375 */
376 template<class OtherAlloc>
377 basic_multi_buffer& operator=(
378 basic_multi_buffer<OtherAlloc> const& other);
379
380 /// Returns a copy of the allocator used.
381 allocator_type
382 get_allocator() const
383 {
384 return this->get();
385 }
386
387 /** Set the maximum allowed capacity
388
389 This function changes the currently configured upper limit
390 on capacity to the specified value.
391
392 @param n The maximum number of bytes ever allowed for capacity.
393
394 @esafe
395
396 No-throw guarantee.
397 */
398 void
399 max_size(std::size_t n) noexcept
400 {
401 max_ = n;
402 }
403
404 /** Guarantee a minimum capacity
405
406 This function adjusts the internal storage (if necessary)
407 to guarantee space for at least `n` bytes.
408
409 Buffer sequences previously obtained using @ref data remain
410 valid, while buffer sequences previously obtained using
411 @ref prepare become invalid.
412
413 @param n The minimum number of byte for the new capacity.
414 If this value is greater than the maximum size, then the
415 maximum size will be adjusted upwards to this value.
416
417 @throws std::length_error if n is larger than the maximum
418 allocation size of the allocator.
419
420 @esafe
421
422 Strong guarantee.
423 */
424 void
425 reserve(std::size_t n);
426
427 /** Reallocate the buffer to fit the readable bytes exactly.
428
429 Buffer sequences previously obtained using @ref data or
430 @ref prepare become invalid.
431
432 @esafe
433
434 Strong guarantee.
435 */
436 void
437 shrink_to_fit();
438
439 /** Set the size of the readable and writable bytes to zero.
440
441 This clears the buffer without changing capacity.
442 Buffer sequences previously obtained using @ref data or
443 @ref prepare become invalid.
444
445 @esafe
446
447 No-throw guarantee.
448 */
449 void
450 clear() noexcept;
451
452 /// Exchange two dynamic buffers
453 template<class Alloc>
454 friend
455 void
456 swap(
457 basic_multi_buffer<Alloc>& lhs,
458 basic_multi_buffer<Alloc>& rhs) noexcept;
459
460 //--------------------------------------------------------------------------
461
462 /// Returns the number of readable bytes.
463 size_type
464 size() const noexcept
465 {
466 return in_size_;
467 }
468
469 /// Return the maximum number of bytes, both readable and writable, that can ever be held.
470 size_type
471 max_size() const noexcept
472 {
473 return max_;
474 }
475
476 /// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
477 std::size_t
478 capacity() const noexcept;
479
480 /** Returns a constant buffer sequence representing the readable bytes
481
482 @note The sequence may contain multiple contiguous memory regions.
483 */
484 const_buffers_type
485 data() const noexcept;
486
487 /** Returns a constant buffer sequence representing the readable bytes
488
489 @note The sequence may contain multiple contiguous memory regions.
490 */
491 const_buffers_type
492 cdata() const noexcept
493 {
494 return data();
495 }
496
497 /** Returns a mutable buffer sequence representing the readable bytes.
498
499 @note The sequence may contain multiple contiguous memory regions.
500 */
501 mutable_buffers_type
502 data() noexcept;
503
504 /** Returns a mutable buffer sequence representing writable bytes.
505
506 Returns a mutable buffer sequence representing the writable
507 bytes containing exactly `n` bytes of storage. Memory may be
508 reallocated as needed.
509
510 All buffer sequences previously obtained using @ref prepare are
511 invalidated. Buffer sequences previously obtained using @ref data
512 remain valid.
513
514 @param n The desired number of bytes in the returned buffer
515 sequence.
516
517 @throws std::length_error if `size() + n` exceeds `max_size()`.
518
519 @esafe
520
521 Strong guarantee.
522 */
523 mutable_buffers_type
524 prepare(size_type n);
525
526 /** Append writable bytes to the readable bytes.
527
528 Appends n bytes from the start of the writable bytes to the
529 end of the readable bytes. The remainder of the writable bytes
530 are discarded. If n is greater than the number of writable
531 bytes, all writable bytes are appended to the readable bytes.
532
533 All buffer sequences previously obtained using @ref prepare are
534 invalidated. Buffer sequences previously obtained using @ref data
535 remain valid.
536
537 @param n The number of bytes to append. If this number
538 is greater than the number of writable bytes, all
539 writable bytes are appended.
540
541 @esafe
542
543 No-throw guarantee.
544 */
545 void
546 commit(size_type n) noexcept;
547
548 /** Remove bytes from beginning of the readable bytes.
549
550 Removes n bytes from the beginning of the readable bytes.
551
552 All buffers sequences previously obtained using
553 @ref data or @ref prepare are invalidated.
554
555 @param n The number of bytes to remove. If this number
556 is greater than the number of readable bytes, all
557 readable bytes are removed.
558
559 @esafe
560
561 No-throw guarantee.
562 */
563 void
564 consume(size_type n) noexcept;
565
566 private:
567 template<class OtherAlloc>
568 friend class basic_multi_buffer;
569
570 template<class OtherAlloc>
571 void copy_from(basic_multi_buffer<OtherAlloc> const&);
572 void move_assign(basic_multi_buffer& other, std::false_type);
573 void move_assign(basic_multi_buffer& other, std::true_type) noexcept;
574 void copy_assign(basic_multi_buffer const& other, std::false_type);
575 void copy_assign(basic_multi_buffer const& other, std::true_type);
576 void swap(basic_multi_buffer&) noexcept;
577 void swap(basic_multi_buffer&, std::true_type) noexcept;
578 void swap(basic_multi_buffer&, std::false_type) noexcept;
579 void destroy(list_type& list) noexcept;
580 void destroy(const_iter it);
581 void destroy(element& e);
582 element& alloc(std::size_t size);
583 void debug_check() const;
584 };
585
586 /// A typical multi buffer
587 using multi_buffer = basic_multi_buffer<std::allocator<char>>;
588
589 } // beast
590 } // boost
591
592 #include <boost/beast/core/impl/multi_buffer.hpp>
593
594 #endif