buffers_iterator.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. //
  2. // buffers_iterator.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2018 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/config.hpp>
  16. #include <cstddef>
  17. #include <iterator>
  18. #include <boost/asio/buffer.hpp>
  19. #include <boost/asio/detail/assert.hpp>
  20. #include <boost/asio/detail/type_traits.hpp>
  21. #include <boost/asio/detail/push_options.hpp>
  22. namespace boost {
  23. namespace asio {
  24. namespace detail
  25. {
  26. template <bool IsMutable>
  27. struct buffers_iterator_types_helper;
  28. template <>
  29. struct buffers_iterator_types_helper<false>
  30. {
  31. typedef const_buffer buffer_type;
  32. template <typename ByteType>
  33. struct byte_type
  34. {
  35. typedef typename add_const<ByteType>::type type;
  36. };
  37. };
  38. template <>
  39. struct buffers_iterator_types_helper<true>
  40. {
  41. typedef mutable_buffer buffer_type;
  42. template <typename ByteType>
  43. struct byte_type
  44. {
  45. typedef ByteType type;
  46. };
  47. };
  48. template <typename BufferSequence, typename ByteType>
  49. struct buffers_iterator_types
  50. {
  51. enum
  52. {
  53. is_mutable = is_convertible<
  54. typename BufferSequence::value_type,
  55. mutable_buffer>::value
  56. };
  57. typedef buffers_iterator_types_helper<is_mutable> helper;
  58. typedef typename helper::buffer_type buffer_type;
  59. typedef typename helper::template byte_type<ByteType>::type byte_type;
  60. typedef typename BufferSequence::const_iterator const_iterator;
  61. };
  62. template <typename ByteType>
  63. struct buffers_iterator_types<mutable_buffer, ByteType>
  64. {
  65. typedef mutable_buffer buffer_type;
  66. typedef ByteType byte_type;
  67. typedef const mutable_buffer* const_iterator;
  68. };
  69. template <typename ByteType>
  70. struct buffers_iterator_types<const_buffer, ByteType>
  71. {
  72. typedef const_buffer buffer_type;
  73. typedef typename add_const<ByteType>::type byte_type;
  74. typedef const const_buffer* const_iterator;
  75. };
  76. #if !defined(BOOST_ASIO_NO_DEPRECATED)
  77. template <typename ByteType>
  78. struct buffers_iterator_types<mutable_buffers_1, ByteType>
  79. {
  80. typedef mutable_buffer buffer_type;
  81. typedef ByteType byte_type;
  82. typedef const mutable_buffer* const_iterator;
  83. };
  84. template <typename ByteType>
  85. struct buffers_iterator_types<const_buffers_1, ByteType>
  86. {
  87. typedef const_buffer buffer_type;
  88. typedef typename add_const<ByteType>::type byte_type;
  89. typedef const const_buffer* const_iterator;
  90. };
  91. #endif // !defined(BOOST_ASIO_NO_DEPRECATED)
  92. }
  93. /// A random access iterator over the bytes in a buffer sequence.
  94. template <typename BufferSequence, typename ByteType = char>
  95. class buffers_iterator
  96. {
  97. private:
  98. typedef typename detail::buffers_iterator_types<
  99. BufferSequence, ByteType>::buffer_type buffer_type;
  100. typedef typename detail::buffers_iterator_types<BufferSequence,
  101. ByteType>::const_iterator buffer_sequence_iterator_type;
  102. public:
  103. /// The type used for the distance between two iterators.
  104. typedef std::ptrdiff_t difference_type;
  105. /// The type of the value pointed to by the iterator.
  106. typedef ByteType value_type;
  107. #if defined(GENERATING_DOCUMENTATION)
  108. /// The type of the result of applying operator->() to the iterator.
  109. /**
  110. * If the buffer sequence stores buffer objects that are convertible to
  111. * mutable_buffer, this is a pointer to a non-const ByteType. Otherwise, a
  112. * pointer to a const ByteType.
  113. */
  114. typedef const_or_non_const_ByteType* pointer;
  115. #else // defined(GENERATING_DOCUMENTATION)
  116. typedef typename detail::buffers_iterator_types<
  117. BufferSequence, ByteType>::byte_type* pointer;
  118. #endif // defined(GENERATING_DOCUMENTATION)
  119. #if defined(GENERATING_DOCUMENTATION)
  120. /// The type of the result of applying operator*() to the iterator.
  121. /**
  122. * If the buffer sequence stores buffer objects that are convertible to
  123. * mutable_buffer, this is a reference to a non-const ByteType. Otherwise, a
  124. * reference to a const ByteType.
  125. */
  126. typedef const_or_non_const_ByteType& reference;
  127. #else // defined(GENERATING_DOCUMENTATION)
  128. typedef typename detail::buffers_iterator_types<
  129. BufferSequence, ByteType>::byte_type& reference;
  130. #endif // defined(GENERATING_DOCUMENTATION)
  131. /// The iterator category.
  132. typedef std::random_access_iterator_tag iterator_category;
  133. /// Default constructor. Creates an iterator in an undefined state.
  134. buffers_iterator()
  135. : current_buffer_(),
  136. current_buffer_position_(0),
  137. begin_(),
  138. current_(),
  139. end_(),
  140. position_(0)
  141. {
  142. }
  143. /// Construct an iterator representing the beginning of the buffers' data.
  144. static buffers_iterator begin(const BufferSequence& buffers)
  145. #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
  146. __attribute__ ((__noinline__))
  147. #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
  148. {
  149. buffers_iterator new_iter;
  150. new_iter.begin_ = boost::asio::buffer_sequence_begin(buffers);
  151. new_iter.current_ = boost::asio::buffer_sequence_begin(buffers);
  152. new_iter.end_ = boost::asio::buffer_sequence_end(buffers);
  153. while (new_iter.current_ != new_iter.end_)
  154. {
  155. new_iter.current_buffer_ = *new_iter.current_;
  156. if (new_iter.current_buffer_.size() > 0)
  157. break;
  158. ++new_iter.current_;
  159. }
  160. return new_iter;
  161. }
  162. /// Construct an iterator representing the end of the buffers' data.
  163. static buffers_iterator end(const BufferSequence& buffers)
  164. #if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
  165. __attribute__ ((__noinline__))
  166. #endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
  167. {
  168. buffers_iterator new_iter;
  169. new_iter.begin_ = boost::asio::buffer_sequence_begin(buffers);
  170. new_iter.current_ = boost::asio::buffer_sequence_begin(buffers);
  171. new_iter.end_ = boost::asio::buffer_sequence_end(buffers);
  172. while (new_iter.current_ != new_iter.end_)
  173. {
  174. buffer_type buffer = *new_iter.current_;
  175. new_iter.position_ += buffer.size();
  176. ++new_iter.current_;
  177. }
  178. return new_iter;
  179. }
  180. /// Dereference an iterator.
  181. reference operator*() const
  182. {
  183. return dereference();
  184. }
  185. /// Dereference an iterator.
  186. pointer operator->() const
  187. {
  188. return &dereference();
  189. }
  190. /// Access an individual element.
  191. reference operator[](std::ptrdiff_t difference) const
  192. {
  193. buffers_iterator tmp(*this);
  194. tmp.advance(difference);
  195. return *tmp;
  196. }
  197. /// Increment operator (prefix).
  198. buffers_iterator& operator++()
  199. {
  200. increment();
  201. return *this;
  202. }
  203. /// Increment operator (postfix).
  204. buffers_iterator operator++(int)
  205. {
  206. buffers_iterator tmp(*this);
  207. ++*this;
  208. return tmp;
  209. }
  210. /// Decrement operator (prefix).
  211. buffers_iterator& operator--()
  212. {
  213. decrement();
  214. return *this;
  215. }
  216. /// Decrement operator (postfix).
  217. buffers_iterator operator--(int)
  218. {
  219. buffers_iterator tmp(*this);
  220. --*this;
  221. return tmp;
  222. }
  223. /// Addition operator.
  224. buffers_iterator& operator+=(std::ptrdiff_t difference)
  225. {
  226. advance(difference);
  227. return *this;
  228. }
  229. /// Subtraction operator.
  230. buffers_iterator& operator-=(std::ptrdiff_t difference)
  231. {
  232. advance(-difference);
  233. return *this;
  234. }
  235. /// Addition operator.
  236. friend buffers_iterator operator+(const buffers_iterator& iter,
  237. std::ptrdiff_t difference)
  238. {
  239. buffers_iterator tmp(iter);
  240. tmp.advance(difference);
  241. return tmp;
  242. }
  243. /// Addition operator.
  244. friend buffers_iterator operator+(std::ptrdiff_t difference,
  245. const buffers_iterator& iter)
  246. {
  247. buffers_iterator tmp(iter);
  248. tmp.advance(difference);
  249. return tmp;
  250. }
  251. /// Subtraction operator.
  252. friend buffers_iterator operator-(const buffers_iterator& iter,
  253. std::ptrdiff_t difference)
  254. {
  255. buffers_iterator tmp(iter);
  256. tmp.advance(-difference);
  257. return tmp;
  258. }
  259. /// Subtraction operator.
  260. friend std::ptrdiff_t operator-(const buffers_iterator& a,
  261. const buffers_iterator& b)
  262. {
  263. return b.distance_to(a);
  264. }
  265. /// Test two iterators for equality.
  266. friend bool operator==(const buffers_iterator& a, const buffers_iterator& b)
  267. {
  268. return a.equal(b);
  269. }
  270. /// Test two iterators for inequality.
  271. friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b)
  272. {
  273. return !a.equal(b);
  274. }
  275. /// Compare two iterators.
  276. friend bool operator<(const buffers_iterator& a, const buffers_iterator& b)
  277. {
  278. return a.distance_to(b) > 0;
  279. }
  280. /// Compare two iterators.
  281. friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b)
  282. {
  283. return !(b < a);
  284. }
  285. /// Compare two iterators.
  286. friend bool operator>(const buffers_iterator& a, const buffers_iterator& b)
  287. {
  288. return b < a;
  289. }
  290. /// Compare two iterators.
  291. friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b)
  292. {
  293. return !(a < b);
  294. }
  295. private:
  296. // Dereference the iterator.
  297. reference dereference() const
  298. {
  299. return static_cast<pointer>(
  300. current_buffer_.data())[current_buffer_position_];
  301. }
  302. // Compare two iterators for equality.
  303. bool equal(const buffers_iterator& other) const
  304. {
  305. return position_ == other.position_;
  306. }
  307. // Increment the iterator.
  308. void increment()
  309. {
  310. BOOST_ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
  311. ++position_;
  312. // Check if the increment can be satisfied by the current buffer.
  313. ++current_buffer_position_;
  314. if (current_buffer_position_ != current_buffer_.size())
  315. return;
  316. // Find the next non-empty buffer.
  317. ++current_;
  318. current_buffer_position_ = 0;
  319. while (current_ != end_)
  320. {
  321. current_buffer_ = *current_;
  322. if (current_buffer_.size() > 0)
  323. return;
  324. ++current_;
  325. }
  326. }
  327. // Decrement the iterator.
  328. void decrement()
  329. {
  330. BOOST_ASIO_ASSERT(position_ > 0 && "iterator out of bounds");
  331. --position_;
  332. // Check if the decrement can be satisfied by the current buffer.
  333. if (current_buffer_position_ != 0)
  334. {
  335. --current_buffer_position_;
  336. return;
  337. }
  338. // Find the previous non-empty buffer.
  339. buffer_sequence_iterator_type iter = current_;
  340. while (iter != begin_)
  341. {
  342. --iter;
  343. buffer_type buffer = *iter;
  344. std::size_t buffer_size = buffer.size();
  345. if (buffer_size > 0)
  346. {
  347. current_ = iter;
  348. current_buffer_ = buffer;
  349. current_buffer_position_ = buffer_size - 1;
  350. return;
  351. }
  352. }
  353. }
  354. // Advance the iterator by the specified distance.
  355. void advance(std::ptrdiff_t n)
  356. {
  357. if (n > 0)
  358. {
  359. BOOST_ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
  360. for (;;)
  361. {
  362. std::ptrdiff_t current_buffer_balance
  363. = current_buffer_.size() - current_buffer_position_;
  364. // Check if the advance can be satisfied by the current buffer.
  365. if (current_buffer_balance > n)
  366. {
  367. position_ += n;
  368. current_buffer_position_ += n;
  369. return;
  370. }
  371. // Update position.
  372. n -= current_buffer_balance;
  373. position_ += current_buffer_balance;
  374. // Move to next buffer. If it is empty then it will be skipped on the
  375. // next iteration of this loop.
  376. if (++current_ == end_)
  377. {
  378. BOOST_ASIO_ASSERT(n == 0 && "iterator out of bounds");
  379. current_buffer_ = buffer_type();
  380. current_buffer_position_ = 0;
  381. return;
  382. }
  383. current_buffer_ = *current_;
  384. current_buffer_position_ = 0;
  385. }
  386. }
  387. else if (n < 0)
  388. {
  389. std::size_t abs_n = -n;
  390. BOOST_ASIO_ASSERT(position_ >= abs_n && "iterator out of bounds");
  391. for (;;)
  392. {
  393. // Check if the advance can be satisfied by the current buffer.
  394. if (current_buffer_position_ >= abs_n)
  395. {
  396. position_ -= abs_n;
  397. current_buffer_position_ -= abs_n;
  398. return;
  399. }
  400. // Update position.
  401. abs_n -= current_buffer_position_;
  402. position_ -= current_buffer_position_;
  403. // Check if we've reached the beginning of the buffers.
  404. if (current_ == begin_)
  405. {
  406. BOOST_ASIO_ASSERT(abs_n == 0 && "iterator out of bounds");
  407. current_buffer_position_ = 0;
  408. return;
  409. }
  410. // Find the previous non-empty buffer.
  411. buffer_sequence_iterator_type iter = current_;
  412. while (iter != begin_)
  413. {
  414. --iter;
  415. buffer_type buffer = *iter;
  416. std::size_t buffer_size = buffer.size();
  417. if (buffer_size > 0)
  418. {
  419. current_ = iter;
  420. current_buffer_ = buffer;
  421. current_buffer_position_ = buffer_size;
  422. break;
  423. }
  424. }
  425. }
  426. }
  427. }
  428. // Determine the distance between two iterators.
  429. std::ptrdiff_t distance_to(const buffers_iterator& other) const
  430. {
  431. return other.position_ - position_;
  432. }
  433. buffer_type current_buffer_;
  434. std::size_t current_buffer_position_;
  435. buffer_sequence_iterator_type begin_;
  436. buffer_sequence_iterator_type current_;
  437. buffer_sequence_iterator_type end_;
  438. std::size_t position_;
  439. };
  440. /// Construct an iterator representing the beginning of the buffers' data.
  441. template <typename BufferSequence>
  442. inline buffers_iterator<BufferSequence> buffers_begin(
  443. const BufferSequence& buffers)
  444. {
  445. return buffers_iterator<BufferSequence>::begin(buffers);
  446. }
  447. /// Construct an iterator representing the end of the buffers' data.
  448. template <typename BufferSequence>
  449. inline buffers_iterator<BufferSequence> buffers_end(
  450. const BufferSequence& buffers)
  451. {
  452. return buffers_iterator<BufferSequence>::end(buffers);
  453. }
  454. } // namespace asio
  455. } // namespace boost
  456. #include <boost/asio/detail/pop_options.hpp>
  457. #endif // BOOST_ASIO_BUFFERS_ITERATOR_HPP