flat_buffer.hpp 15 KB

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