]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/beast/core/multi_buffer.hpp
import new upstream nautilus stable release 14.2.8
[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 readable_bytes;
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 /// The type of allocator used.
160 using allocator_type = Allocator;
161
162 /// Destructor
163 ~basic_multi_buffer();
164
165 /** Constructor
166
167 After construction, @ref capacity will return zero, and
168 @ref max_size will return the largest value which may
169 be passed to the allocator's `allocate` function.
170 */
171 basic_multi_buffer() noexcept(default_nothrow);
172
173 /** Constructor
174
175 After construction, @ref capacity will return zero, and
176 @ref max_size will return the specified value of `limit`.
177
178 @param limit The desired maximum size.
179 */
180 explicit
181 basic_multi_buffer(
182 std::size_t limit) noexcept(default_nothrow);
183
184 /** Constructor
185
186 After construction, @ref capacity will return zero, and
187 @ref max_size will return the largest value which may
188 be passed to the allocator's `allocate` function.
189
190 @param alloc The allocator to use for the object.
191
192 @esafe
193
194 No-throw guarantee.
195 */
196 explicit
197 basic_multi_buffer(Allocator const& alloc) noexcept;
198
199 /** Constructor
200
201 After construction, @ref capacity will return zero, and
202 @ref max_size will return the specified value of `limit`.
203
204 @param limit The desired maximum size.
205
206 @param alloc The allocator to use for the object.
207
208 @esafe
209
210 No-throw guarantee.
211 */
212 basic_multi_buffer(
213 std::size_t limit, Allocator const& alloc) noexcept;
214
215 /** Move Constructor
216
217 The container is constructed with the contents of `other`
218 using move semantics. The maximum size will be the same
219 as the moved-from object.
220
221 Buffer sequences previously obtained from `other` using
222 @ref data or @ref prepare remain valid after the move.
223
224 @param other The object to move from. After the move, the
225 moved-from object will have zero capacity, zero readable
226 bytes, and zero writable bytes.
227
228 @esafe
229
230 No-throw guarantee.
231 */
232 basic_multi_buffer(basic_multi_buffer&& other) noexcept;
233
234 /** Move Constructor
235
236 Using `alloc` as the allocator for the new container, the
237 contents of `other` are moved. If `alloc != other.get_allocator()`,
238 this results in a copy. The maximum size will be the same
239 as the moved-from object.
240
241 Buffer sequences previously obtained from `other` using
242 @ref data or @ref prepare become invalid after the move.
243
244 @param other The object to move from. After the move,
245 the moved-from object will have zero capacity, zero readable
246 bytes, and zero writable bytes.
247
248 @param alloc The allocator to use for the object.
249
250 @throws std::length_error if `other.size()` exceeds the
251 maximum allocation size of `alloc`.
252 */
253 basic_multi_buffer(
254 basic_multi_buffer&& other,
255 Allocator const& alloc);
256
257 /** Copy Constructor
258
259 This container is constructed with the contents of `other`
260 using copy semantics. The maximum size will be the same
261 as the copied object.
262
263 @param other The object to copy from.
264
265 @throws std::length_error if `other.size()` exceeds the
266 maximum allocation size of the allocator.
267 */
268 basic_multi_buffer(basic_multi_buffer const& other);
269
270 /** Copy Constructor
271
272 This container is constructed with the contents of `other`
273 using copy semantics and the specified allocator. The maximum
274 size will be the same as the copied object.
275
276 @param other The object to copy from.
277
278 @param alloc The allocator to use for the object.
279
280 @throws std::length_error if `other.size()` exceeds the
281 maximum allocation size of `alloc`.
282 */
283 basic_multi_buffer(basic_multi_buffer const& other,
284 Allocator const& alloc);
285
286 /** Copy Constructor
287
288 This container is constructed with the contents of `other`
289 using copy semantics. The maximum size will be the same
290 as the copied object.
291
292 @param other The object to copy from.
293
294 @throws std::length_error if `other.size()` exceeds the
295 maximum allocation size of the allocator.
296 */
297 template<class OtherAlloc>
298 basic_multi_buffer(basic_multi_buffer<
299 OtherAlloc> const& other);
300
301 /** Copy Constructor
302
303 This container is constructed with the contents of `other`
304 using copy semantics. The maximum size will be the same
305 as the copied object.
306
307 @param other The object to copy from.
308
309 @param alloc The allocator to use for the object.
310
311 @throws std::length_error if `other.size()` exceeds the
312 maximum allocation size of `alloc`.
313 */
314 template<class OtherAlloc>
315 basic_multi_buffer(
316 basic_multi_buffer<OtherAlloc> const& other,
317 allocator_type const& alloc);
318
319 /** Move Assignment
320
321 The container is assigned with the contents of `other`
322 using move semantics. The maximum size will be the same
323 as the moved-from object.
324
325 Buffer sequences previously obtained from `other` using
326 @ref data or @ref prepare remain valid after the move.
327
328 @param other The object to move from. After the move,
329 the moved-from object will have zero capacity, zero readable
330 bytes, and zero writable bytes.
331 */
332 basic_multi_buffer&
333 operator=(basic_multi_buffer&& other);
334
335 /** Copy Assignment
336
337 The container is assigned with the contents of `other`
338 using copy semantics. The maximum size will be the same
339 as the copied object.
340
341 After the copy, `this` will have zero writable bytes.
342
343 @param other The object to copy from.
344
345 @throws std::length_error if `other.size()` exceeds the
346 maximum allocation size of the allocator.
347 */
348 basic_multi_buffer& operator=(
349 basic_multi_buffer const& other);
350
351 /** Copy Assignment
352
353 The container is assigned with the contents of `other`
354 using copy semantics. The maximum size will be the same
355 as the copied object.
356
357 After the copy, `this` will have zero writable bytes.
358
359 @param other The object to copy from.
360
361 @throws std::length_error if `other.size()` exceeds the
362 maximum allocation size of the allocator.
363 */
364 template<class OtherAlloc>
365 basic_multi_buffer& operator=(
366 basic_multi_buffer<OtherAlloc> const& other);
367
368 /// Returns a copy of the allocator used.
369 allocator_type
370 get_allocator() const
371 {
372 return this->get();
373 }
374
375 /** Set the maximum allowed capacity
376
377 This function changes the currently configured upper limit
378 on capacity to the specified value.
379
380 @param n The maximum number of bytes ever allowed for capacity.
381
382 @esafe
383
384 No-throw guarantee.
385 */
386 void
387 max_size(std::size_t n) noexcept
388 {
389 max_ = n;
390 }
391
392 /** Guarantee a minimum capacity
393
394 This function adjusts the internal storage (if necessary)
395 to guarantee space for at least `n` bytes.
396
397 Buffer sequences previously obtained using @ref data remain
398 valid, while buffer sequences previously obtained using
399 @ref prepare become invalid.
400
401 @param n The minimum number of byte for the new capacity.
402 If this value is greater than the maximum size, then the
403 maximum size will be adjusted upwards to this value.
404
405 @throws std::length_error if n is larger than the maximum
406 allocation size of the allocator.
407
408 @esafe
409
410 Strong guarantee.
411 */
412 void
413 reserve(std::size_t n);
414
415 /** Reallocate the buffer to fit the readable bytes exactly.
416
417 Buffer sequences previously obtained using @ref data or
418 @ref prepare become invalid.
419
420 @esafe
421
422 Strong guarantee.
423 */
424 void
425 shrink_to_fit();
426
427 /** Set the size of the readable and writable bytes to zero.
428
429 This clears the buffer without changing capacity.
430 Buffer sequences previously obtained using @ref data or
431 @ref prepare become invalid.
432
433 @esafe
434
435 No-throw guarantee.
436 */
437 void
438 clear() noexcept;
439
440 /// Exchange two dynamic buffers
441 template<class Alloc>
442 friend
443 void
444 swap(
445 basic_multi_buffer<Alloc>& lhs,
446 basic_multi_buffer<Alloc>& rhs) noexcept;
447
448 //--------------------------------------------------------------------------
449
450 #if BOOST_BEAST_DOXYGEN
451 /// The ConstBufferSequence used to represent the readable bytes.
452 using const_buffers_type = __implementation_defined__;
453
454 /// The MutableBufferSequence used to represent the readable bytes.
455 using mutable_data_type = __implementation_defined__;
456
457 /// The MutableBufferSequence used to represent the writable bytes.
458 using mutable_buffers_type = __implementation_defined__;
459 #else
460 using const_buffers_type = readable_bytes<false>;
461 using mutable_data_type = readable_bytes<true>;
462 class mutable_buffers_type;
463 #endif
464
465 /// Returns the number of readable bytes.
466 size_type
467 size() const noexcept
468 {
469 return in_size_;
470 }
471
472 /// Return the maximum number of bytes, both readable and writable, that can ever be held.
473 size_type
474 max_size() const noexcept
475 {
476 return max_;
477 }
478
479 /// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation.
480 std::size_t
481 capacity() const noexcept;
482
483 /** Returns a constant buffer sequence representing the readable bytes
484
485 @note The sequence may contain multiple contiguous memory regions.
486 */
487 const_buffers_type
488 data() const noexcept;
489
490 /** Returns a constant buffer sequence representing the readable bytes
491
492 @note The sequence may contain multiple contiguous memory regions.
493 */
494 const_buffers_type
495 cdata() const noexcept
496 {
497 return data();
498 }
499
500 /** Returns a mutable buffer sequence representing the readable bytes.
501
502 @note The sequence may contain multiple contiguous memory regions.
503 */
504 mutable_data_type
505 data() noexcept;
506
507 /** Returns a mutable buffer sequence representing writable bytes.
508
509 Returns a mutable buffer sequence representing the writable
510 bytes containing exactly `n` bytes of storage. Memory may be
511 reallocated as needed.
512
513 All buffer sequences previously obtained using @ref prepare are
514 invalidated. Buffer sequences previously obtained using @ref data
515 remain valid.
516
517 @param n The desired number of bytes in the returned buffer
518 sequence.
519
520 @throws std::length_error if `size() + n` exceeds `max_size()`.
521
522 @esafe
523
524 Strong guarantee.
525 */
526 mutable_buffers_type
527 prepare(size_type n);
528
529 /** Append writable bytes to the readable bytes.
530
531 Appends n bytes from the start of the writable bytes to the
532 end of the readable bytes. The remainder of the writable bytes
533 are discarded. If n is greater than the number of writable
534 bytes, all writable bytes are appended to the readable bytes.
535
536 All buffer sequences previously obtained using @ref prepare are
537 invalidated. Buffer sequences previously obtained using @ref data
538 remain valid.
539
540 @param n The number of bytes to append. If this number
541 is greater than the number of writable bytes, all
542 writable bytes are appended.
543
544 @esafe
545
546 No-throw guarantee.
547 */
548 void
549 commit(size_type n) noexcept;
550
551 /** Remove bytes from beginning of the readable bytes.
552
553 Removes n bytes from the beginning of the readable bytes.
554
555 All buffers sequences previously obtained using
556 @ref data or @ref prepare are invalidated.
557
558 @param n The number of bytes to remove. If this number
559 is greater than the number of readable bytes, all
560 readable bytes are removed.
561
562 @esafe
563
564 No-throw guarantee.
565 */
566 void
567 consume(size_type n) noexcept;
568
569 private:
570 template<class OtherAlloc>
571 friend class basic_multi_buffer;
572
573 template<class OtherAlloc>
574 void copy_from(basic_multi_buffer<OtherAlloc> const&);
575 void move_assign(basic_multi_buffer& other, std::false_type);
576 void move_assign(basic_multi_buffer& other, std::true_type) noexcept;
577 void copy_assign(basic_multi_buffer const& other, std::false_type);
578 void copy_assign(basic_multi_buffer const& other, std::true_type);
579 void swap(basic_multi_buffer&) noexcept;
580 void swap(basic_multi_buffer&, std::true_type) noexcept;
581 void swap(basic_multi_buffer&, std::false_type) noexcept;
582 void destroy(list_type& list) noexcept;
583 void destroy(const_iter it);
584 void destroy(element& e);
585 element& alloc(std::size_t size);
586 void debug_check() const;
587 };
588
589 /// A typical multi buffer
590 using multi_buffer = basic_multi_buffer<std::allocator<char>>;
591
592 } // beast
593 } // boost
594
595 #include <boost/beast/core/impl/multi_buffer.hpp>
596
597 #endif