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.
 
 
 

228 lines
7.8 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. namespace tbx {
  36. template<typename Iter_t, size_t N>
  37. class ring_iterator {
  38. //! \name STL iterator traits "forwarding"
  39. //! @{
  40. protected:
  41. using traits_type = std::iterator_traits<Iter_t>;
  42. public:
  43. using iterator_type = Iter_t;
  44. using iterator_category = typename traits_type::iterator_category;
  45. using value_type = typename traits_type::value_type;
  46. using difference_type = typename traits_type::difference_type;
  47. using reference = typename traits_type::reference;
  48. using pointer = typename traits_type::pointer;
  49. //! @}
  50. //! \name Constructor / Destructor
  51. //! @{
  52. public:
  53. ring_iterator(const Iter_t base =nullptr) noexcept :
  54. base_(base), iter_(base) { }
  55. ring_iterator(const Iter_t base, size_t elem) noexcept :
  56. base_(base), iter_(base + elem) { }
  57. ring_iterator(const ring_iterator& it) noexcept :
  58. base_(it.base_), iter_(it.iter_) { }
  59. ring_iterator& operator= (const ring_iterator& it) noexcept {
  60. base_ = it.base_;
  61. iter_ = it.iter_;
  62. return *this;
  63. }
  64. //! @}
  65. //! \name Forward iterator requirements
  66. //! @{
  67. public:
  68. reference operator*() const noexcept {
  69. return *iter_;
  70. }
  71. pointer operator->() const noexcept {
  72. return iter_;
  73. }
  74. ring_iterator& operator++() noexcept {
  75. if (static_cast<size_t>(++iter_ - base_) >= N)
  76. iter_ = base_;
  77. return *this;
  78. }
  79. ring_iterator operator++(int) noexcept {
  80. ring_iterator it = *this;
  81. if (static_cast<size_t>(++iter_ - base_) >= N)
  82. iter_ = base_;
  83. return it;
  84. }
  85. //! @}
  86. //! \name Bidirectional iterator requirements
  87. //! @{
  88. public:
  89. ring_iterator& operator--() noexcept {
  90. if (--iter_ < base_)
  91. iter_ = base_ + N -1;
  92. return *this;
  93. }
  94. ring_iterator operator--(int) noexcept {
  95. ring_iterator it = *this;
  96. if (--iter_ < base_)
  97. iter_ = base_ + N -1;
  98. return it;
  99. }
  100. //! @}
  101. //! \name Random access iterator requirements
  102. //! @{
  103. reference operator[](difference_type n) const noexcept {
  104. difference_type k = iter_ - base_; // ptrdiff from base_
  105. return (static_cast<size_t>(k + n) < N) ?
  106. base_[k + n] : // on range
  107. base_[k + n - N]; // out of range, loop
  108. }
  109. ring_iterator& operator+=(difference_type n) noexcept {
  110. difference_type k = iter_ - base_; // ptrdiff from base_
  111. iter_ += (static_cast<size_t>(k + n) < N) ?
  112. n : // on range
  113. n - N; // out of range, loop
  114. return *this;
  115. }
  116. ring_iterator operator+(difference_type n) const noexcept {
  117. difference_type k = iter_ - base_; // ptrdiff from base_
  118. return (static_cast<size_t>(k + n) < N) ?
  119. ring_iterator(base_, k + n) : // on range
  120. ring_iterator(base_, k + n - N); // out of range, loop
  121. }
  122. ring_iterator& operator-=(difference_type n) noexcept {
  123. difference_type k = iter_ - base_; // ptrdiff from base_
  124. iter_ -= ((k - n) < 0)?
  125. n - N: // out of range, loop
  126. n; // on range
  127. return *this;
  128. }
  129. ring_iterator operator-(difference_type n) const noexcept {
  130. difference_type k = iter_ - base_; // ptrdiff from base_
  131. return ((k - n) < 0) ?
  132. ring_iterator(base_, k - n + N) : // out of range, loop
  133. ring_iterator(base_, k - n); // on range
  134. }
  135. //! @}
  136. //! \name Data members and access
  137. //! @{
  138. const Iter_t& base() const noexcept {
  139. return base_;
  140. }
  141. const Iter_t& iter() const noexcept {
  142. return iter_;
  143. }
  144. size_t size() noexcept {
  145. return N;
  146. }
  147. protected:
  148. Iter_t base_;
  149. Iter_t iter_;
  150. //! @}
  151. };
  152. // Forward iterator requirements
  153. template<typename Iter_L, typename Iter_R, size_t N>
  154. inline bool operator==(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  155. noexcept {
  156. return lhs.iter() == rhs.iter();
  157. }
  158. template<typename Iter_L, typename Iter_R, size_t N>
  159. inline bool operator!=(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  160. noexcept {
  161. return lhs.iter() != rhs.iter();
  162. }
  163. // Random access iterator requirements
  164. template<typename Iter_L, typename Iter_R, size_t N>
  165. inline bool operator<(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  166. noexcept {
  167. return lhs.iter() < rhs.iter();
  168. }
  169. template<typename Iter_L, typename Iter_R, size_t N>
  170. inline bool operator<=(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  171. noexcept {
  172. return lhs.iter() <= rhs.iter();
  173. }
  174. template<typename Iter_L, typename Iter_R, size_t N>
  175. inline bool operator>(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  176. noexcept {
  177. return lhs.iter() > rhs.iter();
  178. }
  179. template<typename Iter_L, typename Iter_R, size_t N>
  180. inline bool operator>=(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  181. noexcept {
  182. return lhs.iter() >= rhs.iter();
  183. }
  184. template<typename Iter_L, typename Iter_R, size_t N>
  185. inline auto operator-(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs)
  186. noexcept
  187. -> decltype(lhs.iter() - rhs.iter()) {
  188. auto diff = lhs.iter() - rhs.iter();
  189. return diff < 0 ?
  190. diff + N : // loop
  191. diff; // no loop
  192. }
  193. template<typename Iter, size_t N>
  194. inline ring_iterator<Iter, N> operator+(std::ptrdiff_t lhs, const ring_iterator<Iter, N>& rhs)
  195. noexcept {
  196. ring_iterator<Iter, N> it(rhs.iter());
  197. return it += lhs;
  198. }
  199. } //namespace tbx;
  200. #endif /* TBX_CORE_RING_ITERATOR_H_ */