Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

buffers_iterator.hpp 12KB

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