consuming_buffers.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. //
  2. // detail/consuming_buffers.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2024 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<BOOST_ASIO_MUTABLE_BUFFER>
  171. {
  172. public:
  173. explicit consuming_buffers(const mutable_buffer& buffer)
  174. : consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER>(buffer)
  175. {
  176. }
  177. };
  178. template <>
  179. class consuming_buffers<const_buffer, mutable_buffer, const mutable_buffer*>
  180. : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>
  181. {
  182. public:
  183. explicit consuming_buffers(const mutable_buffer& buffer)
  184. : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer)
  185. {
  186. }
  187. };
  188. template <>
  189. class consuming_buffers<const_buffer, const_buffer, const const_buffer*>
  190. : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>
  191. {
  192. public:
  193. explicit consuming_buffers(const const_buffer& buffer)
  194. : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer)
  195. {
  196. }
  197. };
  198. #if !defined(BOOST_ASIO_NO_DEPRECATED)
  199. template <>
  200. class consuming_buffers<mutable_buffer,
  201. mutable_buffers_1, const mutable_buffer*>
  202. : public consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER>
  203. {
  204. public:
  205. explicit consuming_buffers(const mutable_buffers_1& buffer)
  206. : consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER>(buffer)
  207. {
  208. }
  209. };
  210. template <>
  211. class consuming_buffers<const_buffer, mutable_buffers_1, const mutable_buffer*>
  212. : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>
  213. {
  214. public:
  215. explicit consuming_buffers(const mutable_buffers_1& buffer)
  216. : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer)
  217. {
  218. }
  219. };
  220. template <>
  221. class consuming_buffers<const_buffer, const_buffers_1, const const_buffer*>
  222. : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>
  223. {
  224. public:
  225. explicit consuming_buffers(const const_buffers_1& buffer)
  226. : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer)
  227. {
  228. }
  229. };
  230. #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
  231. template <>
  232. class consuming_buffers<mutable_buffer,
  233. mutable_registered_buffer, const mutable_buffer*>
  234. : public consuming_single_buffer<mutable_registered_buffer>
  235. {
  236. public:
  237. explicit consuming_buffers(const mutable_registered_buffer& buffer)
  238. : consuming_single_buffer<mutable_registered_buffer>(buffer)
  239. {
  240. }
  241. };
  242. template <>
  243. class consuming_buffers<const_buffer,
  244. mutable_registered_buffer, const mutable_buffer*>
  245. : public consuming_single_buffer<mutable_registered_buffer>
  246. {
  247. public:
  248. explicit consuming_buffers(const mutable_registered_buffer& buffer)
  249. : consuming_single_buffer<mutable_registered_buffer>(buffer)
  250. {
  251. }
  252. };
  253. template <>
  254. class consuming_buffers<const_buffer,
  255. const_registered_buffer, const const_buffer*>
  256. : public consuming_single_buffer<const_registered_buffer>
  257. {
  258. public:
  259. explicit consuming_buffers(const const_registered_buffer& buffer)
  260. : consuming_single_buffer<const_registered_buffer>(buffer)
  261. {
  262. }
  263. };
  264. template <typename Buffer, typename Elem>
  265. class consuming_buffers<Buffer, boost::array<Elem, 2>,
  266. typename boost::array<Elem, 2>::const_iterator>
  267. {
  268. public:
  269. // Construct to represent the entire list of buffers.
  270. explicit consuming_buffers(const boost::array<Elem, 2>& buffers)
  271. : buffers_(buffers),
  272. total_consumed_(0)
  273. {
  274. }
  275. // Determine if we are at the end of the buffers.
  276. bool empty() const
  277. {
  278. return total_consumed_ >=
  279. Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();
  280. }
  281. // Get the buffer for a single transfer, with a size.
  282. boost::array<Buffer, 2> prepare(std::size_t max_size)
  283. {
  284. boost::array<Buffer, 2> result = {{
  285. Buffer(buffers_[0]), Buffer(buffers_[1]) }};
  286. std::size_t buffer0_size = result[0].size();
  287. result[0] = boost::asio::buffer(result[0] + total_consumed_, max_size);
  288. result[1] = boost::asio::buffer(
  289. result[1] + (total_consumed_ < buffer0_size
  290. ? 0 : total_consumed_ - buffer0_size),
  291. max_size - result[0].size());
  292. return result;
  293. }
  294. // Consume the specified number of bytes from the buffers.
  295. void consume(std::size_t size)
  296. {
  297. total_consumed_ += size;
  298. }
  299. // Get the total number of bytes consumed from the buffers.
  300. std::size_t total_consumed() const
  301. {
  302. return total_consumed_;
  303. }
  304. private:
  305. boost::array<Elem, 2> buffers_;
  306. std::size_t total_consumed_;
  307. };
  308. template <typename Buffer, typename Elem>
  309. class consuming_buffers<Buffer, std::array<Elem, 2>,
  310. typename std::array<Elem, 2>::const_iterator>
  311. {
  312. public:
  313. // Construct to represent the entire list of buffers.
  314. explicit consuming_buffers(const std::array<Elem, 2>& buffers)
  315. : buffers_(buffers),
  316. total_consumed_(0)
  317. {
  318. }
  319. // Determine if we are at the end of the buffers.
  320. bool empty() const
  321. {
  322. return total_consumed_ >=
  323. Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size();
  324. }
  325. // Get the buffer for a single transfer, with a size.
  326. std::array<Buffer, 2> prepare(std::size_t max_size)
  327. {
  328. std::array<Buffer, 2> result = {{
  329. Buffer(buffers_[0]), Buffer(buffers_[1]) }};
  330. std::size_t buffer0_size = result[0].size();
  331. result[0] = boost::asio::buffer(result[0] + total_consumed_, max_size);
  332. result[1] = boost::asio::buffer(
  333. result[1] + (total_consumed_ < buffer0_size
  334. ? 0 : total_consumed_ - buffer0_size),
  335. max_size - result[0].size());
  336. return result;
  337. }
  338. // Consume the specified number of bytes from the buffers.
  339. void consume(std::size_t size)
  340. {
  341. total_consumed_ += size;
  342. }
  343. // Get the total number of bytes consumed from the buffers.
  344. std::size_t total_consumed() const
  345. {
  346. return total_consumed_;
  347. }
  348. private:
  349. std::array<Elem, 2> buffers_;
  350. std::size_t total_consumed_;
  351. };
  352. // Specialisation for null_buffers to ensure that the null_buffers type is
  353. // always passed through to the underlying read or write operation.
  354. template <typename Buffer>
  355. class consuming_buffers<Buffer, null_buffers, const mutable_buffer*>
  356. : public boost::asio::null_buffers
  357. {
  358. public:
  359. consuming_buffers(const null_buffers&)
  360. {
  361. // No-op.
  362. }
  363. bool empty()
  364. {
  365. return false;
  366. }
  367. null_buffers prepare(std::size_t)
  368. {
  369. return null_buffers();
  370. }
  371. void consume(std::size_t)
  372. {
  373. // No-op.
  374. }
  375. std::size_t total_consumed() const
  376. {
  377. return 0;
  378. }
  379. };
  380. } // namespace detail
  381. } // namespace asio
  382. } // namespace boost
  383. #include <boost/asio/detail/pop_options.hpp>
  384. #endif // BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP