/*! * \file cont/ring_iterator.h * \brief * A ring/circular iterator. * * \copyright Copyright (C) 2021 Christos Choutouridis * *
License
* The MIT License (MIT) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *
*/ #ifndef TBX_CORE_RING_ITERATOR_H_ #define TBX_CORE_RING_ITERATOR_H_ #include #include #include #include namespace tbx { template class ring_iterator { //! \name STL iterator traits "forwarding" //! @{ protected: using traits_type = std::iterator_traits; public: using iterator_type = Iter_t; using iterator_category = typename traits_type::iterator_category; using value_type = typename traits_type::value_type; using difference_type = typename traits_type::difference_type; using reference = typename traits_type::reference; using pointer = typename traits_type::pointer; //! @} //! \name Constructor / Destructor //! @{ public: constexpr ring_iterator(const Iter_t base =nullptr) noexcept : base_(base), iter_(base) { } constexpr ring_iterator(const Iter_t base, size_t elem) noexcept : base_(base), iter_(base + elem) { } constexpr ring_iterator(const ring_iterator& it) noexcept : base_(it.base_), iter_(it.iter_) { } constexpr ring_iterator& operator= (const ring_iterator& it) noexcept { base_ = it.base_; iter_ = it.iter_; return *this; } //! @} //! \name Forward iterator requirements //! @{ public: constexpr reference operator*() const noexcept { return *iter_; } constexpr pointer operator->() const noexcept { return iter_; } constexpr ring_iterator& operator++() noexcept { if (static_cast(++iter_ - base_) >= N) iter_ = base_; return *this; } constexpr ring_iterator operator++(int) noexcept { ring_iterator it = *this; if (static_cast(++iter_ - base_) >= N) iter_ = base_; return it; } //! @} //! \name Bidirectional iterator requirements //! @{ public: constexpr ring_iterator& operator--() noexcept { if (--iter_ < base_) iter_ = base_ + N -1; return *this; } constexpr ring_iterator operator--(int) noexcept { ring_iterator it = *this; if (--iter_ < base_) iter_ = base_ + N -1; return it; } //! @} //! \name Random access iterator requirements //! @{ constexpr reference operator[](difference_type n) const noexcept { difference_type k = iter_ - base_; // ptrdiff from base_ return (static_cast(k + n) < N) ? base_[k + n] : // on range base_[k + n - N]; // out of range, loop } constexpr ring_iterator& operator+=(difference_type n) noexcept { difference_type k = iter_ - base_; // ptrdiff from base_ iter_ += (static_cast(k + n) < N) ? n : // on range n - N; // out of range, loop return *this; } constexpr ring_iterator operator+(difference_type n) const noexcept { difference_type k = iter_ - base_; // ptrdiff from base_ return (static_cast(k + n) < N) ? ring_iterator(base_, k + n) : // on range ring_iterator(base_, k + n - N); // out of range, loop } constexpr ring_iterator& operator-=(difference_type n) noexcept { difference_type k = iter_ - base_; // ptrdiff from base_ iter_ -= ((k - n) < 0)? n - N: // out of range, loop n; // on range return *this; } constexpr ring_iterator operator-(difference_type n) const noexcept { difference_type k = iter_ - base_; // ptrdiff from base_ return ((k - n) < 0) ? ring_iterator(base_, k - n + N) : // out of range, loop ring_iterator(base_, k - n); // on range } //! @} //! \name Data members and access //! @{ constexpr const Iter_t& base() const noexcept { return base_; } constexpr const Iter_t& iter() const noexcept { return iter_; } constexpr size_t size() noexcept { return N; } constexpr operator Iter_t() noexcept { return iter_; } constexpr operator const Iter_t() const noexcept { return iter_; } protected: Iter_t base_; Iter_t iter_; //! @} }; // Forward iterator requirements template inline bool operator==(const ring_iterator& lhs, const ring_iterator& rhs) noexcept { return lhs.iter() == rhs.iter(); } template inline bool operator!=(const ring_iterator& lhs, const ring_iterator& rhs) noexcept { return lhs.iter() != rhs.iter(); } // Random access iterator requirements template inline bool operator<(const ring_iterator& lhs, const ring_iterator& rhs) noexcept { return lhs.iter() < rhs.iter(); } template inline bool operator<=(const ring_iterator& lhs, const ring_iterator& rhs) noexcept { return lhs.iter() <= rhs.iter(); } template inline bool operator>(const ring_iterator& lhs, const ring_iterator& rhs) noexcept { return lhs.iter() > rhs.iter(); } template inline bool operator>=(const ring_iterator& lhs, const ring_iterator& rhs) noexcept { return lhs.iter() >= rhs.iter(); } template inline auto operator-(const ring_iterator& lhs, const ring_iterator& rhs) noexcept -> decltype(lhs.iter() - rhs.iter()) { auto diff = lhs.iter() - rhs.iter(); return diff < 0 ? diff + N : // loop diff; // no loop } template inline ring_iterator operator+(std::ptrdiff_t lhs, const ring_iterator& rhs) noexcept { ring_iterator it(rhs.iter()); return it += lhs; } template class ring_iterator { //! \name STL iterator traits "forwarding" //! @{ protected: using traits_type = std::iterator_traits; public: using iterator_type = Iter_t; using iterator_category = typename traits_type::iterator_category; using value_type = typename traits_type::value_type; using difference_type = typename traits_type::difference_type; using reference = typename traits_type::reference; using pointer = typename traits_type::pointer; //! @} //! \name Constructor / Destructor //! @{ public: constexpr ring_iterator(const Iter_t base =nullptr) noexcept : base_(base), iter_(base) { } constexpr ring_iterator(const Iter_t base, size_t elem) noexcept : base_(base), iter_(base + elem) { } constexpr ring_iterator(const ring_iterator& it) noexcept : base_(it.base_) { iter_ = it.iter_.load(std::memory_order_acquire); } constexpr ring_iterator& operator= (const ring_iterator& it) noexcept { base_ = it.base_; iter_ = it.iter_.load(std::memory_order_acquire); return *this; } //! @} //! \name Forward iterator requirements //! @{ public: constexpr reference operator*() const noexcept { return *iter_.load(std::memory_order_acquire); } constexpr pointer operator->() const noexcept { return iter_.load(std::memory_order_acquire); } constexpr ring_iterator& operator++() noexcept { Iter_t itnew, it = iter_.load(std::memory_order_acquire); do { itnew = it; if (static_cast(++itnew - base_) >= N) itnew = base_; } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acq_rel)); return *this; } constexpr ring_iterator operator++(int) noexcept { ring_iterator ret = *this; Iter_t itnew, it = iter_.load(std::memory_order_acquire); do { itnew = it; if (static_cast(++itnew - base_) >= N) itnew = base_; } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acq_rel)); return ret; } //! @} //! \name Bidirectional iterator requirements //! @{ public: constexpr ring_iterator& operator--() noexcept { Iter_t itnew, it = iter_.load(std::memory_order_acquire); do { itnew = it; if (--itnew < base_) itnew = base_ + N -1; } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acq_rel)); return *this; } constexpr ring_iterator operator--(int) noexcept { ring_iterator ret = *this; Iter_t itnew, it = iter_.load(std::memory_order_acquire); do { itnew = it; if (--itnew < base_) itnew = base_ + N -1; } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acq_rel)); return ret; } //! @} //! \name Random access iterator requirements //! @{ constexpr reference operator[](difference_type n) const noexcept { difference_type k = iter_.load(std::memory_order_acquire) - base_; // ptrdiff from base_ return (static_cast(k + n) < N) ? base_[k + n] : // on range base_[k + n - N]; // out of range, loop } constexpr ring_iterator& operator+=(difference_type n) noexcept { Iter_t itnew, it = iter_.load(std::memory_order_acquire); do { itnew = it; difference_type k = it - base_; // ptrdiff from base_ itnew += (static_cast(k + n) < N) ? n : // on range n - N; // out of range, loop } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acquire)); return *this; } constexpr ring_iterator operator+(difference_type n) const noexcept { difference_type k = iter_.load(std::memory_order_acquire) - base_; // ptrdiff from base_ return (static_cast(k + n) < N) ? ring_iterator(base_, k + n) : // on range ring_iterator(base_, k + n - N); // out of range, loop } constexpr ring_iterator& operator-=(difference_type n) noexcept { Iter_t itnew, it = iter_.load(std::memory_order_acquire); do { itnew = it; difference_type k = it - base_; // ptrdiff from base_ itnew -= ((k - n) < 0)? n - N: // out of range, loop n; // on range } while (!iter_.compare_exchange_weak(it, itnew, std::memory_order_acquire)); return *this; } constexpr ring_iterator operator-(difference_type n) const noexcept { difference_type k = iter_.load(std::memory_order_acquire) - base_; // ptrdiff from base_ return ((k - n) < 0) ? ring_iterator(base_, k - n + N) : // out of range, loop ring_iterator(base_, k - n); // on range } //! @} //! \name Data members and access //! @{ constexpr const Iter_t& base() const noexcept { return base_; } constexpr const Iter_t iter() const noexcept { return iter_.load(std::memory_order_acquire); } constexpr size_t size() noexcept { return N; } constexpr operator Iter_t() noexcept { return iter_.load(std::memory_order_acquire); } constexpr operator const Iter_t() const noexcept { return iter_.load(std::memory_order_acquire); } protected: Iter_t base_; std::atomic iter_; //! @} }; // Forward iterator requirements template inline bool operator==(const ring_iterator& lhs, const ring_iterator& rhs) noexcept { return lhs.iter() == rhs.iter(); } template inline bool operator!=(const ring_iterator& lhs, const ring_iterator& rhs) noexcept { return lhs.iter() != rhs.iter(); } // Random access iterator requirements template inline bool operator<(const ring_iterator& lhs, const ring_iterator& rhs) noexcept { return lhs.iter() < rhs.iter(); } template inline bool operator<=(const ring_iterator& lhs, const ring_iterator& rhs) noexcept { return lhs.iter() <= rhs.iter(); } template inline bool operator>(const ring_iterator& lhs, const ring_iterator& rhs) noexcept { return lhs.iter() > rhs.iter(); } template inline bool operator>=(const ring_iterator& lhs, const ring_iterator& rhs) noexcept { return lhs.iter() >= rhs.iter(); } template inline auto operator-(const ring_iterator& lhs, const ring_iterator& rhs) noexcept -> decltype(lhs.iter() - rhs.iter()) { auto diff = lhs.iter() - rhs.iter(); return diff < 0 ? diff + N : // loop diff; // no loop } template inline ring_iterator operator+(std::ptrdiff_t lhs, const ring_iterator& rhs) noexcept { ring_iterator it(rhs.iter()); return it += lhs; } } //namespace tbx; #endif /* TBX_CORE_RING_ITERATOR_H_ */