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.
 
 
 

454 lines
16 KiB

  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 ret = *this;
  253. Iter_t itnew, it = iter_.load(std::memory_order_acquire);
  254. do {
  255. itnew = it;
  256. if (static_cast<size_t>(++itnew - base_) >= N)
  257. itnew = base_;
  258. } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acq_rel));
  259. return ret;
  260. }
  261. //! @}
  262. //! \name Bidirectional iterator requirements
  263. //! @{
  264. public:
  265. constexpr ring_iterator& operator--() noexcept {
  266. Iter_t itnew, it = iter_.load(std::memory_order_acquire);
  267. do {
  268. itnew = it;
  269. if (--itnew < base_)
  270. itnew = base_ + N -1;
  271. } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acq_rel));
  272. return *this;
  273. }
  274. constexpr ring_iterator operator--(int) noexcept {
  275. ring_iterator ret = *this;
  276. Iter_t itnew, it = iter_.load(std::memory_order_acquire);
  277. do {
  278. itnew = it;
  279. if (--itnew < base_)
  280. itnew = base_ + N -1;
  281. } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acq_rel));
  282. return ret;
  283. }
  284. //! @}
  285. //! \name Random access iterator requirements
  286. //! @{
  287. constexpr reference operator[](difference_type n) const noexcept {
  288. difference_type k = iter_.load(std::memory_order_acquire) - base_; // ptrdiff from base_
  289. return (static_cast<size_t>(k + n) < N) ?
  290. base_[k + n] : // on range
  291. base_[k + n - N]; // out of range, loop
  292. }
  293. constexpr ring_iterator& operator+=(difference_type n) noexcept {
  294. Iter_t itnew, it = iter_.load(std::memory_order_acquire);
  295. do {
  296. itnew = it;
  297. difference_type k = it - base_; // ptrdiff from base_
  298. itnew += (static_cast<size_t>(k + n) < N) ?
  299. n : // on range
  300. n - N; // out of range, loop
  301. } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acquire));
  302. return *this;
  303. }
  304. constexpr ring_iterator operator+(difference_type n) const noexcept {
  305. difference_type k = iter_.load(std::memory_order_acquire) - base_; // ptrdiff from base_
  306. return (static_cast<size_t>(k + n) < N) ?
  307. ring_iterator(base_, k + n) : // on range
  308. ring_iterator(base_, k + n - N); // out of range, loop
  309. }
  310. constexpr ring_iterator& operator-=(difference_type n) noexcept {
  311. Iter_t itnew, it = iter_.load(std::memory_order_acquire);
  312. do {
  313. itnew = it;
  314. difference_type k = it - base_; // ptrdiff from base_
  315. itnew -= ((k - n) < 0)?
  316. n - N: // out of range, loop
  317. n; // on range
  318. } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acquire));
  319. return *this;
  320. }
  321. constexpr ring_iterator operator-(difference_type n) const noexcept {
  322. difference_type k = iter_.load(std::memory_order_acquire) - base_; // ptrdiff from base_
  323. return ((k - n) < 0) ?
  324. ring_iterator(base_, k - n + N) : // out of range, loop
  325. ring_iterator(base_, k - n); // on range
  326. }
  327. //! @}
  328. //! \name Data members and access
  329. //! @{
  330. constexpr const Iter_t& base() const noexcept {
  331. return base_;
  332. }
  333. constexpr const Iter_t iter() const noexcept {
  334. return iter_.load(std::memory_order_acquire);
  335. }
  336. constexpr size_t size() noexcept {
  337. return N;
  338. }
  339. constexpr operator Iter_t() noexcept { return iter_.load(std::memory_order_acquire); }
  340. constexpr operator const Iter_t() const noexcept { return iter_.load(std::memory_order_acquire); }
  341. protected:
  342. Iter_t base_;
  343. std::atomic<Iter_t> iter_;
  344. //! @}
  345. };
  346. // Forward iterator requirements
  347. template<typename Iter_L, typename Iter_R, size_t N>
  348. inline bool operator==(const ring_iterator<Iter_L, N, true>& lhs, const ring_iterator<Iter_R, N, true>& rhs)
  349. noexcept {
  350. return lhs.iter() == rhs.iter();
  351. }
  352. template<typename Iter_L, typename Iter_R, size_t N>
  353. inline bool operator!=(const ring_iterator<Iter_L, N, true>& lhs, const ring_iterator<Iter_R, N, true>& rhs)
  354. noexcept {
  355. return lhs.iter() != rhs.iter();
  356. }
  357. // Random access iterator requirements
  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 bool operator>(const ring_iterator<Iter_L, N, true>& lhs, const ring_iterator<Iter_R, N, true>& rhs)
  370. noexcept {
  371. return lhs.iter() > rhs.iter();
  372. }
  373. template<typename Iter_L, typename Iter_R, size_t N>
  374. inline bool operator>=(const ring_iterator<Iter_L, N, true>& lhs, const ring_iterator<Iter_R, N, true>& rhs)
  375. noexcept {
  376. return lhs.iter() >= rhs.iter();
  377. }
  378. template<typename Iter_L, typename Iter_R, size_t N>
  379. inline auto operator-(const ring_iterator<Iter_L, N, true>& lhs, const ring_iterator<Iter_R, N, true>& rhs)
  380. noexcept
  381. -> decltype(lhs.iter() - rhs.iter()) {
  382. auto diff = lhs.iter() - rhs.iter();
  383. return diff < 0 ?
  384. diff + N : // loop
  385. diff; // no loop
  386. }
  387. template<typename Iter, size_t N>
  388. inline ring_iterator<Iter, N, true> operator+(std::ptrdiff_t lhs, const ring_iterator<Iter, N, true>& rhs)
  389. noexcept {
  390. ring_iterator<Iter, N, true> it(rhs.iter());
  391. return it += lhs;
  392. }
  393. } //namespace tbx;
  394. #endif /* TBX_CORE_RING_ITERATOR_H_ */