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_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> 15 #include <boost/asio/buffer.hpp> 16 #include <boost/core/empty_value.hpp> 17 #include <limits> 18 #include <memory> 19 #include <type_traits> 20 21 namespace boost { 22 namespace beast { 23 24 /** A dynamic buffer providing buffer sequences of length one. 25 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. 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 44 @li Buffer sequences representing the readable and writable 45 bytes, returned by @ref data and @ref prepare, will have 46 length one. 47 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 60 : private boost::empty_value< 61 typename detail::allocator_traits<Allocator>:: 62 template rebind_alloc<char>> 63 #endif 64 { 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 72 static bool constexpr default_nothrow = 73 std::is_nothrow_default_constructible<Allocator>::value; 74 75 using alloc_traits = 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; 83 84 static 85 std::size_t dist(char const * first,char const * last)86 dist(char const* first, char const* last) noexcept 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 102 /// Destructor 103 ~basic_flat_buffer(); 104 105 /** Constructor 106 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. 110 */ 111 basic_flat_buffer() noexcept(default_nothrow); 112 113 /** Constructor 114 115 After construction, @ref capacity will return zero, and 116 @ref max_size will return the specified value of `limit`. 117 118 @param limit The desired maximum size. 119 */ 120 explicit 121 basic_flat_buffer( 122 std::size_t limit) noexcept(default_nothrow); 123 124 /** Constructor 125 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. 129 130 @param alloc The allocator to use for the object. 131 132 @esafe 133 134 No-throw guarantee. 135 */ 136 explicit 137 basic_flat_buffer(Allocator const& alloc) noexcept; 138 139 /** Constructor 140 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. 147 148 @esafe 149 150 No-throw guarantee. 151 */ 152 basic_flat_buffer( 153 std::size_t limit, 154 Allocator const& alloc) noexcept; 155 156 /** Move Constructor 157 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. 161 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. 172 */ 173 basic_flat_buffer(basic_flat_buffer&& other) noexcept; 174 175 /** Move Constructor 176 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. 184 185 @param other The object to move from. After the move, 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. 190 191 @throws std::length_error if `other.size()` exceeds the 192 maximum allocation size of `alloc`. 193 */ 194 basic_flat_buffer( 195 basic_flat_buffer&& other, 196 Allocator const& alloc); 197 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. 203 204 @param other The object to copy from. 205 206 @throws std::length_error if `other.size()` exceeds the 207 maximum allocation size of the allocator. 208 */ 209 basic_flat_buffer(basic_flat_buffer const& other); 210 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. 216 217 @param other The object to copy from. 218 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`. 223 */ 224 basic_flat_buffer( 225 basic_flat_buffer const& other, 226 Allocator const& alloc); 227 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. 233 234 @param other The object to copy from. 235 236 @throws std::length_error if `other.size()` exceeds the 237 maximum allocation size of the allocator. 238 */ 239 template<class OtherAlloc> 240 basic_flat_buffer( 241 basic_flat_buffer<OtherAlloc> const& other) 242 noexcept(default_nothrow); 243 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. 249 250 @param other The object to copy from. 251 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`. 256 */ 257 template<class OtherAlloc> 258 basic_flat_buffer( 259 basic_flat_buffer<OtherAlloc> const& other, 260 Allocator const& alloc); 261 262 /** Move Assignment 263 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. 267 268 Buffer sequences previously obtained from `other` using 269 @ref data or @ref prepare remain valid after the move. 270 271 @param other The object to move from. After the move, 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. 278 */ 279 basic_flat_buffer& 280 operator=(basic_flat_buffer&& other) noexcept; 281 282 /** Copy Assignment 283 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. 289 290 @param other The object to copy from. 291 292 @throws std::length_error if `other.size()` exceeds the 293 maximum allocation size of the allocator. 294 */ 295 basic_flat_buffer& 296 operator=(basic_flat_buffer const& other); 297 298 /** Copy assignment 299 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. 305 306 @param other The object to copy from. 307 308 @throws std::length_error if `other.size()` exceeds the 309 maximum allocation size of the allocator. 310 */ 311 template<class OtherAlloc> 312 basic_flat_buffer& 313 operator=(basic_flat_buffer<OtherAlloc> const& other); 314 315 /// Returns a copy of the allocator used. 316 allocator_type get_allocator() const317 get_allocator() const 318 { 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 max_size(std::size_t n)334 max_size(std::size_t n) noexcept 335 { 336 max_ = n; 337 } 338 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 361 /** Reallocate the buffer to fit the readable bytes exactly. 362 363 Buffer sequences previously obtained using @ref data or 364 @ref prepare become invalid. 365 366 @esafe 367 368 Strong guarantee. 369 */ 370 void 371 shrink_to_fit(); 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 399 /// The MutableBufferSequence used to represent the readable bytes. 400 using mutable_data_type = net::mutable_buffer; 401 402 /// The MutableBufferSequence used to represent the writable bytes. 403 using mutable_buffers_type = net::mutable_buffer; 404 405 /// Returns the number of readable bytes. 406 std::size_t size() const407 size() const noexcept 408 { 409 return dist(in_, out_); 410 } 411 412 /// Return the maximum number of bytes, both readable and writable, that can ever be held. 413 std::size_t max_size() const414 max_size() const noexcept 415 { 416 return max_; 417 } 418 419 /// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation. 420 std::size_t capacity() const421 capacity() const noexcept 422 { 423 return dist(begin_, end_); 424 } 425 426 /// Returns a constant buffer sequence representing the readable bytes 427 const_buffers_type data() const428 data() const noexcept 429 { 430 return {in_, dist(in_, out_)}; 431 } 432 433 /// Returns a constant buffer sequence representing the readable bytes 434 const_buffers_type cdata() const435 cdata() const noexcept 436 { 437 return data(); 438 } 439 440 /// Returns a mutable buffer sequence representing the readable bytes 441 mutable_data_type data()442 data() noexcept 443 { 444 return {in_, dist(in_, out_)}; 445 } 446 447 /** Returns a mutable buffer sequence representing writable bytes. 448 449 Returns a mutable buffer sequence representing the writable 450 bytes containing exactly `n` bytes of storage. Memory may be 451 reallocated as needed. 452 453 All buffers sequences previously obtained using 454 @ref data or @ref prepare become invalid. 455 456 @param n The desired number of bytes in the returned buffer 457 sequence. 458 459 @throws std::length_error if `size() + n` exceeds either 460 `max_size()` or the allocator's maximum allocation size. 461 462 @esafe 463 464 Strong guarantee. 465 */ 466 mutable_buffers_type 467 prepare(std::size_t n); 468 469 /** Append writable bytes to the readable bytes. 470 471 Appends n bytes from the start of the writable bytes to the 472 end of the readable bytes. The remainder of the writable bytes 473 are discarded. If n is greater than the number of writable 474 bytes, all writable bytes are appended to the readable bytes. 475 476 All buffers sequences previously obtained using 477 @ref data or @ref prepare become invalid. 478 479 @param n The number of bytes to append. If this number 480 is greater than the number of writable bytes, all 481 writable bytes are appended. 482 483 @esafe 484 485 No-throw guarantee. 486 */ 487 void commit(std::size_t n)488 commit(std::size_t n) noexcept 489 { 490 out_ += (std::min)(n, dist(out_, last_)); 491 } 492 493 /** Remove bytes from beginning of the readable bytes. 494 495 Removes n bytes from the beginning of the readable bytes. 496 497 All buffers sequences previously obtained using 498 @ref data or @ref prepare become invalid. 499 500 @param n The number of bytes to remove. If this number 501 is greater than the number of readable bytes, all 502 readable bytes are removed. 503 504 @esafe 505 506 No-throw guarantee. 507 */ 508 void 509 consume(std::size_t n) noexcept; 510 511 private: 512 template<class OtherAlloc> 513 void copy_from(basic_flat_buffer<OtherAlloc> const& other); 514 void move_assign(basic_flat_buffer&, std::true_type); 515 void move_assign(basic_flat_buffer&, std::false_type); 516 void copy_assign(basic_flat_buffer const&, std::true_type); 517 void copy_assign(basic_flat_buffer const&, std::false_type); 518 void swap(basic_flat_buffer&); 519 void swap(basic_flat_buffer&, std::true_type); 520 void swap(basic_flat_buffer&, std::false_type); 521 char* alloc(std::size_t n); 522 }; 523 524 /// A flat buffer which uses the default allocator. 525 using flat_buffer = 526 basic_flat_buffer<std::allocator<char>>; 527 528 } // beast 529 } // boost 530 531 #include <boost/beast/core/impl/flat_buffer.hpp> 532 533 #endif 534