consuming_buffers.hpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. //
  2. // consuming_buffers.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2008 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/push_options.hpp>
  16. #include <boost/asio/detail/push_options.hpp>
  17. #include <algorithm>
  18. #include <cstddef>
  19. #include <limits>
  20. #include <boost/config.hpp>
  21. #include <boost/iterator/iterator_facade.hpp>
  22. #include <boost/asio/detail/pop_options.hpp>
  23. #include <boost/asio/buffer.hpp>
  24. #include <boost/asio/completion_condition.hpp>
  25. namespace boost {
  26. namespace asio {
  27. namespace detail {
  28. // A proxy iterator for a sub-range in a list of buffers.
  29. template <typename Buffer, typename Buffer_Iterator>
  30. class consuming_buffers_iterator
  31. : public boost::iterator_facade<
  32. consuming_buffers_iterator<Buffer, Buffer_Iterator>,
  33. const Buffer, boost::forward_traversal_tag>
  34. {
  35. public:
  36. // Default constructor creates an end iterator.
  37. consuming_buffers_iterator()
  38. : at_end_(true)
  39. {
  40. }
  41. // Construct with a buffer for the first entry and an iterator
  42. // range for the remaining entries.
  43. consuming_buffers_iterator(bool at_end, const Buffer& first,
  44. Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder,
  45. std::size_t max_size)
  46. : at_end_(max_size > 0 ? at_end : true),
  47. first_(buffer(first, max_size)),
  48. begin_remainder_(begin_remainder),
  49. end_remainder_(end_remainder),
  50. offset_(0),
  51. max_size_(max_size)
  52. {
  53. }
  54. private:
  55. friend class boost::iterator_core_access;
  56. void increment()
  57. {
  58. if (!at_end_)
  59. {
  60. if (begin_remainder_ == end_remainder_
  61. || offset_ + buffer_size(first_) >= max_size_)
  62. {
  63. at_end_ = true;
  64. }
  65. else
  66. {
  67. offset_ += buffer_size(first_);
  68. first_ = buffer(*begin_remainder_++, max_size_ - offset_);
  69. }
  70. }
  71. }
  72. bool equal(const consuming_buffers_iterator& other) const
  73. {
  74. if (at_end_ && other.at_end_)
  75. return true;
  76. return !at_end_ && !other.at_end_
  77. && buffer_cast<const void*>(first_)
  78. == buffer_cast<const void*>(other.first_)
  79. && buffer_size(first_) == buffer_size(other.first_)
  80. && begin_remainder_ == other.begin_remainder_
  81. && end_remainder_ == other.end_remainder_;
  82. }
  83. const Buffer& dereference() const
  84. {
  85. return first_;
  86. }
  87. bool at_end_;
  88. Buffer first_;
  89. Buffer_Iterator begin_remainder_;
  90. Buffer_Iterator end_remainder_;
  91. std::size_t offset_;
  92. std::size_t max_size_;
  93. };
  94. // A proxy for a sub-range in a list of buffers.
  95. template <typename Buffer, typename Buffers>
  96. class consuming_buffers
  97. {
  98. public:
  99. // The type for each element in the list of buffers.
  100. typedef Buffer value_type;
  101. // A forward-only iterator type that may be used to read elements.
  102. typedef consuming_buffers_iterator<Buffer, typename Buffers::const_iterator>
  103. const_iterator;
  104. // Construct to represent the entire list of buffers.
  105. consuming_buffers(const Buffers& buffers)
  106. : buffers_(buffers),
  107. at_end_(buffers_.begin() == buffers_.end()),
  108. first_(*buffers_.begin()),
  109. begin_remainder_(buffers_.begin()),
  110. max_size_((std::numeric_limits<std::size_t>::max)())
  111. {
  112. if (!at_end_)
  113. ++begin_remainder_;
  114. }
  115. // Copy constructor.
  116. consuming_buffers(const consuming_buffers& other)
  117. : buffers_(other.buffers_),
  118. at_end_(other.at_end_),
  119. first_(other.first_),
  120. begin_remainder_(buffers_.begin()),
  121. max_size_(other.max_size_)
  122. {
  123. typename Buffers::const_iterator first = other.buffers_.begin();
  124. typename Buffers::const_iterator second = other.begin_remainder_;
  125. std::advance(begin_remainder_, std::distance(first, second));
  126. }
  127. // Assignment operator.
  128. consuming_buffers& operator=(const consuming_buffers& other)
  129. {
  130. buffers_ = other.buffers_;
  131. at_end_ = other.at_end_;
  132. first_ = other.first_;
  133. begin_remainder_ = buffers_.begin();
  134. typename Buffers::const_iterator first = other.buffers_.begin();
  135. typename Buffers::const_iterator second = other.begin_remainder_;
  136. std::advance(begin_remainder_, std::distance(first, second));
  137. max_size_ = other.max_size_;
  138. return *this;
  139. }
  140. // Get a forward-only iterator to the first element.
  141. const_iterator begin() const
  142. {
  143. return const_iterator(at_end_, first_,
  144. begin_remainder_, buffers_.end(), max_size_);
  145. }
  146. // Get a forward-only iterator for one past the last element.
  147. const_iterator end() const
  148. {
  149. return const_iterator();
  150. }
  151. // Set the maximum size for a single transfer.
  152. void set_max_size(std::size_t max_size)
  153. {
  154. max_size_ = max_size;
  155. }
  156. // Consume the specified number of bytes from the buffers.
  157. void consume(std::size_t size)
  158. {
  159. // Remove buffers from the start until the specified size is reached.
  160. while (size > 0 && !at_end_)
  161. {
  162. if (buffer_size(first_) <= size)
  163. {
  164. size -= buffer_size(first_);
  165. if (begin_remainder_ == buffers_.end())
  166. at_end_ = true;
  167. else
  168. first_ = *begin_remainder_++;
  169. }
  170. else
  171. {
  172. first_ = first_ + size;
  173. size = 0;
  174. }
  175. }
  176. // Remove any more empty buffers at the start.
  177. while (!at_end_ && buffer_size(first_) == 0)
  178. {
  179. if (begin_remainder_ == buffers_.end())
  180. at_end_ = true;
  181. else
  182. first_ = *begin_remainder_++;
  183. }
  184. }
  185. private:
  186. Buffers buffers_;
  187. bool at_end_;
  188. Buffer first_;
  189. typename Buffers::const_iterator begin_remainder_;
  190. std::size_t max_size_;
  191. };
  192. // Specialisation for null_buffers to ensure that the null_buffers type is
  193. // always passed through to the underlying read or write operation.
  194. template <typename Buffer>
  195. class consuming_buffers<Buffer, boost::asio::null_buffers>
  196. : public boost::asio::null_buffers
  197. {
  198. public:
  199. consuming_buffers(const boost::asio::null_buffers&)
  200. {
  201. // No-op.
  202. }
  203. void set_max_size(std::size_t)
  204. {
  205. // No-op.
  206. }
  207. void consume(std::size_t)
  208. {
  209. // No-op.
  210. }
  211. };
  212. } // namespace detail
  213. } // namespace asio
  214. } // namespace boost
  215. #include <boost/asio/detail/pop_options.hpp>
  216. #endif // BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP