diff options
Diffstat (limited to 'boost/histogram/detail/iterator_adaptor.hpp')
-rw-r--r-- | boost/histogram/detail/iterator_adaptor.hpp | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/boost/histogram/detail/iterator_adaptor.hpp b/boost/histogram/detail/iterator_adaptor.hpp new file mode 100644 index 0000000000..345a4abb19 --- /dev/null +++ b/boost/histogram/detail/iterator_adaptor.hpp @@ -0,0 +1,162 @@ +// Copyright 2019 Hans Dembinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Uses code segments from boost/iterator/iterator_adaptor.hpp +// and boost/iterator/iterator_fascade.hpp + +#ifndef BOOST_HISTOGRAM_DETAIL_ITERATOR_ADAPTOR_HPP +#define BOOST_HISTOGRAM_DETAIL_ITERATOR_ADAPTOR_HPP + +#include <iterator> +#include <memory> +#include <type_traits> +#include <utility> + +namespace boost { +namespace histogram { +namespace detail { + +// operator->() needs special support for input iterators to strictly meet the +// standard's requirements. If *i is not a reference type, we must still +// produce an lvalue to which a pointer can be formed. We do that by +// returning a proxy object containing an instance of the reference object. +template <class Reference> +struct operator_arrow_dispatch_t // proxy references +{ + struct proxy { + explicit proxy(Reference const& x) noexcept : m_ref(x) {} + Reference* operator->() noexcept { return std::addressof(m_ref); } + Reference m_ref; + }; + + using result_type = proxy; + static result_type apply(Reference const& x) noexcept { return proxy(x); } +}; + +template <class T> +struct operator_arrow_dispatch_t<T&> // "real" references +{ + using result_type = T*; + static result_type apply(T& x) noexcept { return std::addressof(x); } +}; + +// only for random access Base +template <class Derived, class Base, class Reference = std::remove_pointer_t<Base>&, + class Value = std::decay_t<Reference>> +class iterator_adaptor { + using operator_arrow_dispatch = operator_arrow_dispatch_t<Reference>; + +public: + using base_type = Base; + + using reference = Reference; + using value_type = std::remove_const_t<Value>; + using pointer = typename operator_arrow_dispatch::result_type; + using difference_type = std::ptrdiff_t; + using iterator_category = std::random_access_iterator_tag; + + iterator_adaptor() = default; + + explicit iterator_adaptor(base_type const& iter) : iter_(iter) {} + + pointer operator->() const noexcept { + return operator_arrow_dispatch::apply(this->derived().operator*()); + } + reference operator[](difference_type n) const { return *(this->derived() + n); } + + Derived& operator++() { + ++iter_; + return this->derived(); + } + + Derived& operator--() { + --iter_; + return this->derived(); + } + + Derived operator++(int) { + Derived tmp(this->derived()); + ++iter_; + return tmp; + } + + Derived operator--(int) { + Derived tmp(this->derived()); + --iter_; + return tmp; + } + + Derived& operator+=(difference_type n) { + iter_ += n; + return this->derived(); + } + + Derived& operator-=(difference_type n) { + iter_ -= n; + return this->derived(); + } + + Derived operator+(difference_type n) const { + Derived tmp(this->derived()); + tmp += n; + return tmp; + } + + Derived operator-(difference_type n) const { return operator+(-n); } + + template <class... Ts> + difference_type operator-(const iterator_adaptor<Ts...>& x) const noexcept { + return iter_ - x.iter_; + } + + template <class... Ts> + bool operator==(const iterator_adaptor<Ts...>& x) const noexcept { + return iter_ == x.iter_; + } + template <class... Ts> + bool operator!=(const iterator_adaptor<Ts...>& x) const noexcept { + return !this->derived().operator==(x); // equal operator may be overridden in derived + } + template <class... Ts> + bool operator<(const iterator_adaptor<Ts...>& x) const noexcept { + return iter_ < x.iter_; + } + template <class... Ts> + bool operator>(const iterator_adaptor<Ts...>& x) const noexcept { + return iter_ > x.iter_; + } + template <class... Ts> + bool operator<=(const iterator_adaptor<Ts...>& x) const noexcept { + return iter_ <= x.iter_; + } + template <class... Ts> + bool operator>=(const iterator_adaptor<Ts...>& x) const noexcept { + return iter_ >= x.iter_; + } + + friend Derived operator+(difference_type n, const Derived& x) { return x + n; } + + Base const& base() const noexcept { return iter_; } + +protected: + // for convenience in derived classes + using iterator_adaptor_ = iterator_adaptor; + +private: + Derived& derived() noexcept { return *static_cast<Derived*>(this); } + const Derived& derived() const noexcept { return *static_cast<Derived const*>(this); } + + Base iter_; + + template <class, class, class, class> + friend class iterator_adaptor; +}; + +} // namespace detail +} // namespace histogram +} // namespace boost + +#endif |