consuming_buffers.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. //
  2. // detail/consuming_buffers.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP
  11. #define BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #include <cstddef>
  17. #include <boost/asio/buffer.hpp>
  18. #include <boost/asio/detail/buffer_sequence_adapter.hpp>
  19. #include <boost/asio/detail/limits.hpp>
  20. #include <boost/asio/registered_buffer.hpp>
  21. #include <boost/asio/detail/push_options.hpp>
  22. namespace boost {
  23. namespace asio {
  24. namespace detail {
  25. // Helper template to determine the maximum number of prepared buffers.
  26. template <typename Buffers>
  27. struct prepared_buffers_max
  28. {
  29. enum { value = buffer_sequence_adapter_base::max_buffers };
  30. };
  31. template <typename Elem, std::size_t N>
  32. struct prepared_buffers_max<boost::array<Elem, N>>
  33. {
  34. enum { value = N };
  35. };
  36. template <typename Elem, std::size_t N>
  37. struct prepared_buffers_max<std::array<Elem, N>>
  38. {
  39. enum { value = N };
  40. };
  41. // A buffer sequence used to represent a subsequence of the buffers.
  42. template <typename Buffer, std::size_t MaxBuffers>
  43. struct prepared_buffers
  44. {
  45. typedef Buffer value_type;
  46. typedef const Buffer* const_iterator;
  47. enum { max_buffers = MaxBuffers < 16 ? MaxBuffers : 16 };
  48. prepared_buffers() : count(0) {}
  49. const_iterator begin() const { return elems; }
  50. const_iterator end() const { return elems + count; }
  51. Buffer elems[max_buffers];
  52. std::size_t count;
  53. };
  54. // A proxy for a sub-range in a list of buffers.
  55. template <typename Buffer, typename Buffers, typename Buffer_Iterator>
  56. class consuming_buffers
  57. {
  58. public:
  59. typedef prepared_buffers<Buffer, prepared_buffers_max<Buffers>::value>
  60. prepared_buffers_type;
  61. // Construct to represent the entire list of buffers.
  62. explicit consuming_buffers(const Buffers& buffers)
  63. : buffers_(buffers),
  64. total_consumed_(0),
  65. next_elem_(0),
  66. next_elem_offset_(0)
  67. {
  68. using boost::asio::buffer_size;
  69. total_size_ = buffer_size(buffers);
  70. }
  71. // Determine if we are at the end of the buffers.
  72. bool empty() const
  73. {
  74. return total_consumed_ >= total_size_;
  75. }
  76. // Get the buffer for a single transfer, with a size.
  77. prepared_buffers_type prepare(std::size_t max_size)
  78. {
  79. prepared_buffers_type result;
  80. Buffer_Iterator next = boost::asio::buffer_sequence_begin(buffers_);
  81. Buffer_Iterator end = boost::asio::buffer_sequence_end(buffers_);
  82. std::advance(next, next_elem_);
  83. std::size_t elem_offset = next_elem_offset_;
  84. while (next != end && max_size > 0 && (result.count) < result.max_buffers)
  85. {
  86. Buffer next_buf = Buffer(*next) + elem_offset;
  87. result.elems[result.count] = boost::asio::buffer(next_buf, max_size);
  88. max_size -= result.elems[result.count].size();
  89. elem_offset = 0;
  90. if (result.elems[result.count].size() > 0)
  91. ++result.count;
  92. ++next;
  93. }
  94. return result;
  95. }
  96. // Consume the specified number of bytes from the buffers.
  97. void consume(std::size_t size)
  98. {
  99. total_consumed_ += size;
  100. Buffer_Iterator next = boost::asio::buffer_sequence_begin(buffers_);
  101. Buffer_Iterator end = boost::asio::buffer_sequence_end(buffers_);
  102. std::advance(next, next_elem_);
  103. while (next != end && size > 0)
  104. {
  105. Buffer next_buf = Buffer(*next) + next_elem_offset_;
  106. if (size < next_buf.size())
  107. {
  108. next_elem_offset_ += size;
  109. size = 0;
  110. }
  111. else
  112. {
  113. size -= next_buf.size();
  114. next_elem_offset_ = 0;
  115. ++next_elem_;
  116. ++next;
  117. }
  118. }
  119. }
  120. // Get the total number of bytes consumed from the buffers.
  121. std::size_t total_consumed() const
  122. {
  123. return total_consumed_;
  124. }
  125. private:
  126. Buffers buffers_;
  127. std::size_t total_size_;
  128. std::size_t total_consumed_;
  129. std::size_t next_elem_;
  130. std::size_t next_elem_offset_;
  131. };
  132. // Base class of all consuming_buffers specialisations for single buffers.
  133. template <typename Buffer>
  134. class consuming_single_buffer
  135. {
  136. public:
  137. // Construct to represent the entire list of buffers.
  138. template <typename Buffer1>
  139. explicit consuming_single_buffer(const Buffer1& buffer)
  140. : buffer_(buffer),
  141. total_consumed_(0)
  142. {
  143. }
  144. // Determine if we are at the end of the buffers.
  145. bool empty() const
  146. {
  147. return total_consumed_ >= buffer_.size();
  148. }
  149. // Get the buffer for a single transfer, with a size.
  150. Buffer prepare(std::size_t max_size)
  151. {
  152. return boost::asio::buffer(buffer_ + total_consumed_, max_size);
  153. }
  154. // Consume the specified number of bytes from the buffers.
  155. void consume(std::size_t size)
  156. {
  157. total_consumed_ += size;
  158. }
  159. // Get the total number of bytes consumed from the buffers.
  160. std::size_t total_consumed() const
  161. {
  162. return total_consumed_;
  163. }
  164. private:
  165. Buffer buffer_;
  166. std::size_t total_consumed_;
  167. };
  168. template <>
  169. class consuming_buffers<mutable_buffer, mutable_buffer, const mutable_buffer*>
  170. : public consuming_single_buffer<mutable_buffer>
  171. {
  172. public:
  173. explicit consuming_buffers(const mutable_buffer& buffer)
  174. : consuming_single_buffer<mutable_buffer>(buffer)
  175. {
  176. }
  177. };
  178. template <>
  179. class consuming_buffers<const_buffer, mutable_buffer, const mutable_buffer*>
  180. : public consuming_single_buffer<const_buffer>
  181. {
  182. public:
  183. explicit consuming_buffers(const mutable_buffer& buffer)
  184. : consuming_single_buffer<const_buffer>(buffer)
  185. {
  186. }
  187. };
  188. template <>
  189. class consuming_buffers<const_buffer, const_buffer, const const_buffer*>
  190. : public consuming_single_buffer<const_buffer>
  191. {
  192. public:
  193. explicit consuming_buffers(const const_buffer& buffer)
  194. : consuming_single_buffer<const_buffer>(buffer)
  195. {
  196. }
  197. };
  198. template <>
  199. class consuming_buffers<mutable_buffer,
  200. mutable_registered_buffer, const mutable_buffer*>
  201. : public consuming_single_buffer<mutable_registered_buffer>
  202. {
  203. public:
  204. explicit consuming_buffers(const mutable_registered_buffer& buffer)
  205. : consuming_single_buffer<mutable_registered_buffer>(buffer)
  206. {
  207. }
  208. };
  209. template <>
  210. class consuming_buffers<const_buffer,
  211. mutable_registered_buffer, const mutable_buffer*>
  212. : public consuming_single_buffer<mutable_registered_buffer>
  213. {
  214. public:
  215. explicit consuming_buffers(const mutable_registered_buffer& buffer)
  216. : consuming_single_buffer<mutable_registered_buffer>(buffer)
  217. {
  218. }
  219. };
  220. template <>
  221. class consuming_buffers<const_buffer,
  222. const_registered_buffer, const const_buffer*>
  223. : public consuming_single_buffer<const_registered_buffer>
  224. {
  225. public:
  226. explicit consuming_buffers(const const_registered_buffer& buffer)
  227. : consuming_single_buffer<const_registered_buffer>(buffer)
  228. {
  229. }
  230. };
  231. template <typename Buffer, typename Elem>
  232. class consuming_buffers<Buffer, boost::array<Elem, 2>,
  233. typename boost::array<Elem, 2>::const_iterator>
  234. {
  235. public:
  236. // Construct to represent the entire list of buffers.
  237. explicit consuming_buffers(const boost::array<Elem, 2>& buffers)
  238. : buffers_(buffers),
  239. total_consumed_(0)
  240. {
  241. }
  242. // Determine if we are at the end of the buffers.
  243. bool empty() const
  244. {
  245. return total_consumed_ >=
  246. Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();
  247. }
  248. // Get the buffer for a single transfer, with a size.
  249. boost::array<Buffer, 2> prepare(std::size_t max_size)
  250. {
  251. boost::array<Buffer, 2> result = {{
  252. Buffer(buffers_[0]), Buffer(buffers_[1]) }};
  253. std::size_t buffer0_size = result[0].size();
  254. result[0] = boost::asio::buffer(result[0] + total_consumed_, max_size);
  255. result[1] = boost::asio::buffer(
  256. result[1] + (total_consumed_ < buffer0_size
  257. ? 0 : total_consumed_ - buffer0_size),
  258. max_size - result[0].size());
  259. return result;
  260. }
  261. // Consume the specified number of bytes from the buffers.
  262. void consume(std::size_t size)
  263. {
  264. total_consumed_ += size;
  265. }
  266. // Get the total number of bytes consumed from the buffers.
  267. std::size_t total_consumed() const
  268. {
  269. return total_consumed_;
  270. }
  271. private:
  272. boost::array<Elem, 2> buffers_;
  273. std::size_t total_consumed_;
  274. };
  275. template <typename Buffer, typename Elem>
  276. class consuming_buffers<Buffer, std::array<Elem, 2>,
  277. typename std::array<Elem, 2>::const_iterator>
  278. {
  279. public:
  280. // Construct to represent the entire list of buffers.
  281. explicit consuming_buffers(const std::array<Elem, 2>& buffers)
  282. : buffers_(buffers),
  283. total_consumed_(0)
  284. {
  285. }
  286. // Determine if we are at the end of the buffers.
  287. bool empty() const
  288. {
  289. return total_consumed_ >=
  290. Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();
  291. }
  292. // Get the buffer for a single transfer, with a size.
  293. std::array<Buffer, 2> prepare(std::size_t max_size)
  294. {
  295. std::array<Buffer, 2> result = {{
  296. Buffer(buffers_[0]), Buffer(buffers_[1]) }};
  297. std::size_t buffer0_size = result[0].size();
  298. result[0] = boost::asio::buffer(result[0] + total_consumed_, max_size);
  299. result[1] = boost::asio::buffer(
  300. result[1] + (total_consumed_ < buffer0_size
  301. ? 0 : total_consumed_ - buffer0_size),
  302. max_size - result[0].size());
  303. return result;
  304. }
  305. // Consume the specified number of bytes from the buffers.
  306. void consume(std::size_t size)
  307. {
  308. total_consumed_ += size;
  309. }
  310. // Get the total number of bytes consumed from the buffers.
  311. std::size_t total_consumed() const
  312. {
  313. return total_consumed_;
  314. }
  315. private:
  316. std::array<Elem, 2> buffers_;
  317. std::size_t total_consumed_;
  318. };
  319. // Specialisation for null_buffers to ensure that the null_buffers type is
  320. // always passed through to the underlying read or write operation.
  321. template <typename Buffer>
  322. class consuming_buffers<Buffer, null_buffers, const mutable_buffer*>
  323. : public boost::asio::null_buffers
  324. {
  325. public:
  326. consuming_buffers(const null_buffers&)
  327. {
  328. // No-op.
  329. }
  330. bool empty()
  331. {
  332. return false;
  333. }
  334. null_buffers prepare(std::size_t)
  335. {
  336. return null_buffers();
  337. }
  338. void consume(std::size_t)
  339. {
  340. // No-op.
  341. }
  342. std::size_t total_consumed() const
  343. {
  344. return 0;
  345. }
  346. };
  347. } // namespace detail
  348. } // namespace asio
  349. } // namespace boost
  350. #include <boost/asio/detail/pop_options.hpp>
  351. #endif // BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP