consuming_buffers.hpp 11 KB

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