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 /** Request the removal of unused capacity. 362 363 This function attempts to reduce @ref capacity() 364 to @ref size(), which may not succeed. 365 366 @esafe 367 368 No-throw guarantee. 369 */ 370 void 371 shrink_to_fit() noexcept; 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 writable bytes. 400 using mutable_buffers_type = net::mutable_buffer; 401 402 /// Returns the number of readable bytes. 403 std::size_t size() const404 size() const noexcept 405 { 406 return dist(in_, out_); 407 } 408 409 /// Return the maximum number of bytes, both readable and writable, that can ever be held. 410 std::size_t max_size() const411 max_size() const noexcept 412 { 413 return max_; 414 } 415 416 /// Return the maximum number of bytes, both readable and writable, that can be held without requiring an allocation. 417 std::size_t capacity() const418 capacity() const noexcept 419 { 420 return dist(begin_, end_); 421 } 422 423 /// Returns a constant buffer sequence representing the readable bytes 424 const_buffers_type data() const425 data() const noexcept 426 { 427 return {in_, dist(in_, out_)}; 428 } 429 430 /// Returns a constant buffer sequence representing the readable bytes 431 const_buffers_type cdata() const432 cdata() const noexcept 433 { 434 return data(); 435 } 436 437 /// Returns a mutable buffer sequence representing the readable bytes 438 mutable_buffers_type data()439 data() noexcept 440 { 441 return {in_, dist(in_, out_)}; 442 } 443 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. 449 450 All buffers sequences previously obtained using 451 @ref data or @ref prepare become invalid. 452 453 @param n The desired number of bytes in the returned buffer 454 sequence. 455 456 @throws std::length_error if `size() + n` exceeds either 457 `max_size()` or the allocator's maximum allocation size. 458 459 @esafe 460 461 Strong guarantee. 462 */ 463 mutable_buffers_type 464 prepare(std::size_t n); 465 466 /** Append writable bytes to the readable bytes. 467 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. 472 473 All buffers sequences previously obtained using 474 @ref data or @ref prepare become invalid. 475 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. 479 480 @esafe 481 482 No-throw guarantee. 483 */ 484 void commit(std::size_t n)485 commit(std::size_t n) noexcept 486 { 487 out_ += (std::min)(n, dist(out_, last_)); 488 } 489 490 /** Remove bytes from beginning of the readable bytes. 491 492 Removes n bytes from the beginning of the readable bytes. 493 494 All buffers sequences previously obtained using 495 @ref data or @ref prepare become invalid. 496 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. 500 501 @esafe 502 503 No-throw guarantee. 504 */ 505 void 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); 519 }; 520 521 /// A flat buffer which uses the default allocator. 522 using flat_buffer = 523 basic_flat_buffer<std::allocator<char>>; 524 525 } // beast 526 } // boost 527 528 #include <boost/beast/core/impl/flat_buffer.hpp> 529 530 #endif 531