buffers_iterator.hpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. //
  2. // buffers_iterator.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_BUFFERS_ITERATOR_HPP
  11. #define BOOST_ASIO_BUFFERS_ITERATOR_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 <cstddef>
  18. #include <boost/assert.hpp>
  19. #include <boost/config.hpp>
  20. #include <boost/detail/workaround.hpp>
  21. #include <boost/iterator/iterator_facade.hpp>
  22. #include <boost/type_traits/is_convertible.hpp>
  23. #include <boost/type_traits/add_const.hpp>
  24. #include <boost/asio/detail/pop_options.hpp>
  25. #include <boost/asio/buffer.hpp>
  26. namespace boost {
  27. namespace asio {
  28. namespace detail
  29. {
  30. template <bool IsMutable>
  31. struct buffers_iterator_types_helper;
  32. template <>
  33. struct buffers_iterator_types_helper<false>
  34. {
  35. typedef const_buffer buffer_type;
  36. template <typename ByteType>
  37. struct byte_type
  38. {
  39. typedef typename boost::add_const<ByteType>::type type;
  40. };
  41. };
  42. template <>
  43. struct buffers_iterator_types_helper<true>
  44. {
  45. typedef mutable_buffer buffer_type;
  46. template <typename ByteType>
  47. struct byte_type
  48. {
  49. typedef ByteType type;
  50. };
  51. };
  52. template <typename BufferSequence, typename ByteType>
  53. struct buffers_iterator_types
  54. {
  55. enum
  56. {
  57. is_mutable = boost::is_convertible<
  58. typename BufferSequence::value_type, mutable_buffer>::value
  59. };
  60. typedef buffers_iterator_types_helper<is_mutable> helper;
  61. typedef typename helper::buffer_type buffer_type;
  62. typedef typename helper::template byte_type<ByteType>::type byte_type;
  63. };
  64. }
  65. /// A random access iterator over the bytes in a buffer sequence.
  66. template <typename BufferSequence, typename ByteType = char>
  67. class buffers_iterator
  68. : public boost::iterator_facade<
  69. buffers_iterator<BufferSequence, ByteType>,
  70. typename detail::buffers_iterator_types<
  71. BufferSequence, ByteType>::byte_type,
  72. boost::random_access_traversal_tag>
  73. {
  74. private:
  75. typedef typename detail::buffers_iterator_types<
  76. BufferSequence, ByteType>::buffer_type buffer_type;
  77. typedef typename detail::buffers_iterator_types<
  78. BufferSequence, ByteType>::byte_type byte_type;
  79. public:
  80. /// Default constructor. Creates an iterator in an undefined state.
  81. buffers_iterator()
  82. : current_buffer_(),
  83. current_buffer_position_(0),
  84. begin_(),
  85. current_(),
  86. end_(),
  87. position_(0)
  88. {
  89. }
  90. /// Construct an iterator representing the beginning of the buffers' data.
  91. static buffers_iterator begin(const BufferSequence& buffers)
  92. #if BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3)
  93. __attribute__ ((noinline))
  94. #endif
  95. {
  96. buffers_iterator new_iter;
  97. new_iter.begin_ = buffers.begin();
  98. new_iter.current_ = buffers.begin();
  99. new_iter.end_ = buffers.end();
  100. while (new_iter.current_ != new_iter.end_)
  101. {
  102. new_iter.current_buffer_ = *new_iter.current_;
  103. if (boost::asio::buffer_size(new_iter.current_buffer_) > 0)
  104. break;
  105. ++new_iter.current_;
  106. }
  107. return new_iter;
  108. }
  109. /// Construct an iterator representing the end of the buffers' data.
  110. static buffers_iterator end(const BufferSequence& buffers)
  111. #if BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3)
  112. __attribute__ ((noinline))
  113. #endif
  114. {
  115. buffers_iterator new_iter;
  116. new_iter.begin_ = buffers.begin();
  117. new_iter.current_ = buffers.begin();
  118. new_iter.end_ = buffers.end();
  119. while (new_iter.current_ != new_iter.end_)
  120. {
  121. buffer_type buffer = *new_iter.current_;
  122. new_iter.position_ += boost::asio::buffer_size(buffer);
  123. ++new_iter.current_;
  124. }
  125. return new_iter;
  126. }
  127. private:
  128. friend class boost::iterator_core_access;
  129. // Dereference the iterator.
  130. byte_type& dereference() const
  131. {
  132. return buffer_cast<byte_type*>(current_buffer_)[current_buffer_position_];
  133. }
  134. // Compare two iterators for equality.
  135. bool equal(const buffers_iterator& other) const
  136. {
  137. return position_ == other.position_;
  138. }
  139. // Increment the iterator.
  140. void increment()
  141. {
  142. BOOST_ASSERT(current_ != end_ && "iterator out of bounds");
  143. ++position_;
  144. // Check if the increment can be satisfied by the current buffer.
  145. ++current_buffer_position_;
  146. if (current_buffer_position_ != boost::asio::buffer_size(current_buffer_))
  147. return;
  148. // Find the next non-empty buffer.
  149. ++current_;
  150. current_buffer_position_ = 0;
  151. while (current_ != end_)
  152. {
  153. current_buffer_ = *current_;
  154. if (boost::asio::buffer_size(current_buffer_) > 0)
  155. return;
  156. ++current_;
  157. }
  158. }
  159. // Decrement the iterator.
  160. void decrement()
  161. {
  162. BOOST_ASSERT(position_ > 0 && "iterator out of bounds");
  163. --position_;
  164. // Check if the decrement can be satisfied by the current buffer.
  165. if (current_buffer_position_ != 0)
  166. {
  167. --current_buffer_position_;
  168. return;
  169. }
  170. // Find the previous non-empty buffer.
  171. typename BufferSequence::const_iterator iter = current_;
  172. while (iter != begin_)
  173. {
  174. --iter;
  175. buffer_type buffer = *iter;
  176. std::size_t buffer_size = boost::asio::buffer_size(buffer);
  177. if (buffer_size > 0)
  178. {
  179. current_ = iter;
  180. current_buffer_ = buffer;
  181. current_buffer_position_ = buffer_size - 1;
  182. return;
  183. }
  184. }
  185. }
  186. // Advance the iterator by the specified distance.
  187. void advance(std::ptrdiff_t n)
  188. {
  189. if (n > 0)
  190. {
  191. BOOST_ASSERT(current_ != end_ && "iterator out of bounds");
  192. for (;;)
  193. {
  194. std::ptrdiff_t current_buffer_balance
  195. = boost::asio::buffer_size(current_buffer_)
  196. - current_buffer_position_;
  197. // Check if the advance can be satisfied by the current buffer.
  198. if (current_buffer_balance > n)
  199. {
  200. position_ += n;
  201. current_buffer_position_ += n;
  202. return;
  203. }
  204. // Update position.
  205. n -= current_buffer_balance;
  206. position_ += current_buffer_balance;
  207. // Move to next buffer. If it is empty then it will be skipped on the
  208. // next iteration of this loop.
  209. if (++current_ == end_)
  210. {
  211. BOOST_ASSERT(n == 0 && "iterator out of bounds");
  212. current_buffer_ = buffer_type();
  213. current_buffer_position_ = 0;
  214. return;
  215. }
  216. current_buffer_ = *current_;
  217. current_buffer_position_ = 0;
  218. }
  219. }
  220. else if (n < 0)
  221. {
  222. std::size_t abs_n = -n;
  223. BOOST_ASSERT(position_ >= abs_n && "iterator out of bounds");
  224. for (;;)
  225. {
  226. // Check if the advance can be satisfied by the current buffer.
  227. if (current_buffer_position_ >= abs_n)
  228. {
  229. position_ -= abs_n;
  230. current_buffer_position_ -= abs_n;
  231. return;
  232. }
  233. // Update position.
  234. abs_n -= current_buffer_position_;
  235. position_ -= current_buffer_position_;
  236. // Check if we've reached the beginning of the buffers.
  237. if (current_ == begin_)
  238. {
  239. BOOST_ASSERT(abs_n == 0 && "iterator out of bounds");
  240. current_buffer_position_ = 0;
  241. return;
  242. }
  243. // Find the previous non-empty buffer.
  244. typename BufferSequence::const_iterator iter = current_;
  245. while (iter != begin_)
  246. {
  247. --iter;
  248. buffer_type buffer = *iter;
  249. std::size_t buffer_size = boost::asio::buffer_size(buffer);
  250. if (buffer_size > 0)
  251. {
  252. current_ = iter;
  253. current_buffer_ = buffer;
  254. current_buffer_position_ = buffer_size;
  255. break;
  256. }
  257. }
  258. }
  259. }
  260. }
  261. // Determine the distance between two iterators.
  262. std::ptrdiff_t distance_to(const buffers_iterator& other) const
  263. {
  264. return other.position_ - position_;
  265. }
  266. buffer_type current_buffer_;
  267. std::size_t current_buffer_position_;
  268. typename BufferSequence::const_iterator begin_;
  269. typename BufferSequence::const_iterator current_;
  270. typename BufferSequence::const_iterator end_;
  271. std::size_t position_;
  272. };
  273. /// Construct an iterator representing the beginning of the buffers' data.
  274. template <typename BufferSequence>
  275. inline buffers_iterator<BufferSequence> buffers_begin(
  276. const BufferSequence& buffers)
  277. {
  278. return buffers_iterator<BufferSequence>::begin(buffers);
  279. }
  280. /// Construct an iterator representing the end of the buffers' data.
  281. template <typename BufferSequence>
  282. inline buffers_iterator<BufferSequence> buffers_end(
  283. const BufferSequence& buffers)
  284. {
  285. return buffers_iterator<BufferSequence>::end(buffers);
  286. }
  287. } // namespace asio
  288. } // namespace boost
  289. #include <boost/asio/detail/pop_options.hpp>
  290. #endif // BOOST_ASIO_BUFFERS_ITERATOR_HPP