consuming_buffers.hpp 11 KB

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