A C++ toolbox repo until the pair uTL/dTL arives
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.

ring_iterator.h 16 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. /*!
  2. * \file cont/ring_iterator.h
  3. * \brief
  4. * A ring/circular iterator.
  5. *
  6. * \copyright Copyright (C) 2021 Christos Choutouridis <christos@choutouridis.net>
  7. *
  8. * <dl class=\"section copyright\"><dt>License</dt><dd>
  9. * The MIT License (MIT)
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in all
  19. * copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  27. * SOFTWARE.
  28. * </dd></dl>
  29. */
  30. #ifndef TBX_CORE_RING_ITERATOR_H_
  31. #define TBX_CORE_RING_ITERATOR_H_
  32. #include <core/core.h>
  33. #include <iterator>
  34. #include <type_traits>
  35. #include <atomic>
  36. namespace tbx {
  37. template<typename Iter_t, size_t N, bool Atomic=false>
  38. class ring_iterator {
  39. //! \name STL iterator traits "forwarding"
  40. //! @{
  41. protected:
  42. using traits_type = std::iterator_traits<Iter_t>;
  43. public:
  44. using iterator_type = Iter_t;
  45. using iterator_category = typename traits_type::iterator_category;
  46. using value_type = typename traits_type::value_type;
  47. using difference_type = typename traits_type::difference_type;
  48. using reference = typename traits_type::reference;
  49. using pointer = typename traits_type::pointer;
  50. //! @}
  51. //! \name Constructor / Destructor
  52. //! @{
  53. public:
  54. constexpr ring_iterator(const Iter_t base =nullptr) noexcept :
  55. base_(base), iter_(base) { }
  56. constexpr ring_iterator(const Iter_t base, size_t elem) noexcept :
  57. base_(base), iter_(base + elem) { }
  58. constexpr ring_iterator(const ring_iterator& it) noexcept :
  59. base_(it.base_), iter_(it.iter_) { }
  60. constexpr ring_iterator& operator= (const ring_iterator& it) noexcept {
  61. base_ = it.base_;
  62. iter_ = it.iter_;
  63. return *this;
  64. }
  65. //! @}
  66. //! \name Forward iterator requirements
  67. //! @{
  68. public:
  69. constexpr reference operator*() const noexcept {
  70. return *iter_;
  71. }
  72. constexpr pointer operator->() const noexcept {
  73. return iter_;
  74. }
  75. constexpr ring_iterator& operator++() noexcept {
  76. if (static_cast<size_t>(++iter_ - base_) >= N)
  77. iter_ = base_;
  78. return *this;
  79. }
  80. constexpr ring_iterator operator++(int) noexcept {
  81. ring_iterator it = *this;
  82. if (static_cast<size_t>(++iter_ - base_) >= N)
  83. iter_ = base_;
  84. return it;
  85. }
  86. //! @}
  87. //! \name Bidirectional iterator requirements
  88. //! @{
  89. public:
  90. constexpr ring_iterator& operator--() noexcept {
  91. if (--iter_ < base_)
  92. iter_ = base_ + N -1;
  93. return *this;
  94. }
  95. constexpr ring_iterator operator--(int) noexcept {
  96. ring_iterator it = *this;
  97. if (--iter_ < base_)
  98. iter_ = base_ + N -1;
  99. return it;
  100. }
  101. //! @}
  102. //! \name Random access iterator requirements
  103. //! @{
  104. constexpr reference operator[](difference_type n) const noexcept {
  105. difference_type k = iter_ - base_; // ptrdiff from base_
  106. return (static_cast<size_t>(k + n) < N) ?
  107. base_[k + n] : // on range
  108. base_[k + n - N]; // out of range, loop
  109. }
  110. constexpr ring_iterator& operator+=(difference_type n) noexcept {
  111. difference_type k = iter_ - base_; // ptrdiff from base_
  112. iter_ += (static_cast<size_t>(k + n) < N) ?
  113. n : // on range
  114. n - N; // out of range, loop
  115. return *this;
  116. }
  117. constexpr ring_iterator operator+(difference_type n) const noexcept {
  118. difference_type k = iter_ - base_; // ptrdiff from base_
  119. return (static_cast<size_t>(k + n) < N) ?
  120. ring_iterator(base_, k + n) : // on range
  121. ring_iterator(base_, k + n - N); // out of range, loop
  122. }
  123. constexpr ring_iterator& operator-=(difference_type n) noexcept {
  124. difference_type k = iter_ - base_; // ptrdiff from base_
  125. iter_ -= ((k - n) < 0)?
  126. n - N: // out of range, loop
  127. n; // on range
  128. return *this;
  129. }
  130. constexpr ring_iterator operator-(difference_type n) const noexcept {
  131. difference_type k = iter_ - base_; // ptrdiff from base_
  132. return ((k - n) < 0) ?
  133. ring_iterator(base_, k - n + N) : // out of range, loop
  134. ring_iterator(base_, k - n); // on range
  135. }
  136. //! @}
  137. //! \name Data members and access
  138. //! @{
  139. constexpr const Iter_t& base() const noexcept {
  140. return base_;
  141. }
  142. constexpr const Iter_t& iter() const noexcept {
  143. return iter_;
  144. }
  145. constexpr size_t size() noexcept {
  146. return N;
  147. }
  148. constexpr operator Iter_t() noexcept { return iter_; }
  149. constexpr operator const Iter_t() const noexcept { return iter_; }
  150. protected:
  151. Iter_t base_;
  152. Iter_t iter_;
  153. //! @}
  154. };
  155. // Forward iterator requirements
  156. template<typename Iter_L, typename Iter_R, size_t N>
  157. inline bool operator==(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  158. noexcept {
  159. return lhs.iter() == rhs.iter();
  160. }
  161. template<typename Iter_L, typename Iter_R, size_t N>
  162. inline bool operator!=(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  163. noexcept {
  164. return lhs.iter() != rhs.iter();
  165. }
  166. // Random access iterator requirements
  167. template<typename Iter_L, typename Iter_R, size_t N>
  168. inline bool operator<(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  169. noexcept {
  170. return lhs.iter() < rhs.iter();
  171. }
  172. template<typename Iter_L, typename Iter_R, size_t N>
  173. inline bool operator<=(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  174. noexcept {
  175. return lhs.iter() <= rhs.iter();
  176. }
  177. template<typename Iter_L, typename Iter_R, size_t N>
  178. inline bool operator>(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  179. noexcept {
  180. return lhs.iter() > rhs.iter();
  181. }
  182. template<typename Iter_L, typename Iter_R, size_t N>
  183. inline bool operator>=(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  184. noexcept {
  185. return lhs.iter() >= rhs.iter();
  186. }
  187. template<typename Iter_L, typename Iter_R, size_t N>
  188. inline auto operator-(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  189. noexcept
  190. -> decltype(lhs.iter() - rhs.iter()) {
  191. auto diff = lhs.iter() - rhs.iter();
  192. return diff < 0 ?
  193. diff + N : // loop
  194. diff; // no loop
  195. }
  196. template<typename Iter, size_t N>
  197. inline ring_iterator<Iter, N> operator+(std::ptrdiff_t lhs, const ring_iterator<Iter, N>& rhs)
  198. noexcept {
  199. ring_iterator<Iter, N> it(rhs.iter());
  200. return it += lhs;
  201. }
  202. template<typename Iter_t, size_t N>
  203. class ring_iterator<Iter_t, N, true> {
  204. //! \name STL iterator traits "forwarding"
  205. //! @{
  206. protected:
  207. using traits_type = std::iterator_traits<Iter_t>;
  208. public:
  209. using iterator_type = Iter_t;
  210. using iterator_category = typename traits_type::iterator_category;
  211. using value_type = typename traits_type::value_type;
  212. using difference_type = typename traits_type::difference_type;
  213. using reference = typename traits_type::reference;
  214. using pointer = typename traits_type::pointer;
  215. //! @}
  216. //! \name Constructor / Destructor
  217. //! @{
  218. public:
  219. constexpr ring_iterator(const Iter_t base =nullptr) noexcept :
  220. base_(base), iter_(base) { }
  221. constexpr ring_iterator(const Iter_t base, size_t elem) noexcept :
  222. base_(base), iter_(base + elem) { }
  223. constexpr ring_iterator(const ring_iterator& it) noexcept :
  224. base_(it.base_) {
  225. iter_ = it.iter_.load(std::memory_order_acquire);
  226. }
  227. constexpr ring_iterator& operator= (const ring_iterator& it) noexcept {
  228. base_ = it.base_;
  229. iter_ = it.iter_.load(std::memory_order_acquire);
  230. return *this;
  231. }
  232. //! @}
  233. //! \name Forward iterator requirements
  234. //! @{
  235. public:
  236. constexpr reference operator*() const noexcept {
  237. return *iter_.load(std::memory_order_acquire);
  238. }
  239. constexpr pointer operator->() const noexcept {
  240. return iter_.load(std::memory_order_acquire);
  241. }
  242. constexpr ring_iterator& operator++() noexcept {
  243. Iter_t itnew, it = iter_.load(std::memory_order_acquire);
  244. do {
  245. itnew = it;
  246. if (static_cast<size_t>(++itnew - base_) >= N)
  247. itnew = base_;
  248. } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acq_rel));
  249. return *this;
  250. }
  251. constexpr ring_iterator operator++(int) noexcept {
  252. ring_iterator it = *this;
  253. this->operator ++();
  254. return it;
  255. }
  256. //! @}
  257. //! \name Bidirectional iterator requirements
  258. //! @{
  259. public:
  260. constexpr ring_iterator& operator--() noexcept {
  261. Iter_t itnew, it = iter_.load(std::memory_order_acquire);
  262. do {
  263. itnew = it;
  264. if (--itnew < base_)
  265. itnew = base_ + N -1;
  266. } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acq_rel));
  267. return *this;
  268. }
  269. constexpr ring_iterator operator--(int) noexcept {
  270. ring_iterator it = *this;
  271. this->operator --();
  272. return it;
  273. }
  274. //! @}
  275. //! \name Random access iterator requirements
  276. //! @{
  277. constexpr reference operator[](difference_type n) const noexcept {
  278. difference_type k = iter_.load(std::memory_order_acquire) - base_; // ptrdiff from base_
  279. return (static_cast<size_t>(k + n) < N) ?
  280. base_[k + n] : // on range
  281. base_[k + n - N]; // out of range, loop
  282. }
  283. constexpr ring_iterator& operator+=(difference_type n) noexcept {
  284. Iter_t itnew, it = iter_.load(std::memory_order_acquire);
  285. do {
  286. itnew = it;
  287. difference_type k = it - base_; // ptrdiff from base_
  288. itnew += (static_cast<size_t>(k + n) < N) ?
  289. n : // on range
  290. n - N; // out of range, loop
  291. } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acquire));
  292. return *this;
  293. }
  294. constexpr ring_iterator operator+(difference_type n) const noexcept {
  295. difference_type k = iter_.load(std::memory_order_acquire) - base_; // ptrdiff from base_
  296. return (static_cast<size_t>(k + n) < N) ?
  297. ring_iterator(base_, k + n) : // on range
  298. ring_iterator(base_, k + n - N); // out of range, loop
  299. }
  300. constexpr ring_iterator& operator-=(difference_type n) noexcept {
  301. Iter_t itnew, it = iter_.load(std::memory_order_acquire);
  302. do {
  303. itnew = it;
  304. difference_type k = it - base_; // ptrdiff from base_
  305. itnew -= ((k - n) < 0)?
  306. n - N: // out of range, loop
  307. n; // on range
  308. } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acquire));
  309. return *this;
  310. }
  311. constexpr ring_iterator operator-(difference_type n) const noexcept {
  312. difference_type k = iter_.load(std::memory_order_acquire) - base_; // ptrdiff from base_
  313. return ((k - n) < 0) ?
  314. ring_iterator(base_, k - n + N) : // out of range, loop
  315. ring_iterator(base_, k - n); // on range
  316. }
  317. //! @}
  318. //! \name Data members and access
  319. //! @{
  320. constexpr const Iter_t& base() const noexcept {
  321. return base_;
  322. }
  323. constexpr const Iter_t iter() const noexcept {
  324. return iter_.load(std::memory_order_acquire);
  325. }
  326. constexpr size_t size() noexcept {
  327. return N;
  328. }
  329. constexpr operator Iter_t() noexcept { return iter_.load(std::memory_order_acquire); }
  330. constexpr operator const Iter_t() const noexcept { return iter_.load(std::memory_order_acquire); }
  331. protected:
  332. Iter_t base_;
  333. std::atomic<Iter_t> iter_;
  334. //! @}
  335. };
  336. // Forward iterator requirements
  337. template<typename Iter_L, typename Iter_R, size_t N>
  338. inline bool operator==(const ring_iterator<Iter_L, N, true>& lhs, const ring_iterator<Iter_R, N, true>& rhs)
  339. noexcept {
  340. return lhs.iter() == rhs.iter();
  341. }
  342. template<typename Iter_L, typename Iter_R, size_t N>
  343. inline bool operator!=(const ring_iterator<Iter_L, N, true>& lhs, const ring_iterator<Iter_R, N, true>& rhs)
  344. noexcept {
  345. return lhs.iter() != rhs.iter();
  346. }
  347. // Random access iterator requirements
  348. template<typename Iter_L, typename Iter_R, size_t N>
  349. inline bool operator<(const ring_iterator<Iter_L, N, true>& lhs, const ring_iterator<Iter_R, N, true>& rhs)
  350. noexcept {
  351. return lhs.iter() < rhs.iter();
  352. }
  353. template<typename Iter_L, typename Iter_R, size_t N>
  354. inline bool operator<=(const ring_iterator<Iter_L, N, true>& lhs, const ring_iterator<Iter_R, N, true>& rhs)
  355. noexcept {
  356. return lhs.iter() <= rhs.iter();
  357. }
  358. template<typename Iter_L, typename Iter_R, size_t N>
  359. inline bool operator>(const ring_iterator<Iter_L, N, true>& lhs, const ring_iterator<Iter_R, N, true>& rhs)
  360. noexcept {
  361. return lhs.iter() > rhs.iter();
  362. }
  363. template<typename Iter_L, typename Iter_R, size_t N>
  364. inline bool operator>=(const ring_iterator<Iter_L, N, true>& lhs, const ring_iterator<Iter_R, N, true>& rhs)
  365. noexcept {
  366. return lhs.iter() >= rhs.iter();
  367. }
  368. template<typename Iter_L, typename Iter_R, size_t N>
  369. inline auto operator-(const ring_iterator<Iter_L, N, true>& lhs, const ring_iterator<Iter_R, N, true>& rhs)
  370. noexcept
  371. -> decltype(lhs.iter() - rhs.iter()) {
  372. auto diff = lhs.iter() - rhs.iter();
  373. return diff < 0 ?
  374. diff + N : // loop
  375. diff; // no loop
  376. }
  377. template<typename Iter, size_t N>
  378. inline ring_iterator<Iter, N, true> operator+(std::ptrdiff_t lhs, const ring_iterator<Iter, N, true>& rhs)
  379. noexcept {
  380. ring_iterator<Iter, N, true> it(rhs.iter());
  381. return it += lhs;
  382. }
  383. } //namespace tbx;
  384. #endif /* TBX_CORE_RING_ITERATOR_H_ */