consuming_buffers.hpp 10 KB

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