// 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 #include #include #include #include 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 struct operator_arrow_dispatch_t { struct pointer { explicit pointer(Reference const& x) noexcept : m_ref(x) {} Reference* operator->() noexcept { return std::addressof(m_ref); } Reference m_ref; }; using result_type = pointer; static result_type apply(Reference const& x) noexcept { return pointer(x); } }; // specialization for "real" references template struct operator_arrow_dispatch_t { using result_type = T*; static result_type apply(T& x) noexcept { return std::addressof(x); } }; // it is ok if void_t is already defined in another header template using void_t = void; template struct get_difference_type_impl : std::make_signed {}; template struct get_difference_type_impl< T, void_t::difference_type>> { using type = typename std::iterator_traits::difference_type; }; template using get_difference_type = typename get_difference_type_impl::type; // adaptor supports only random access Base // Base: underlying base type of the iterator; can be iterator, pointer, integer // Reference: type returned when pointer is dereferenced template &, class Value = std::decay_t> class iterator_adaptor { using operator_arrow_dispatch = operator_arrow_dispatch_t; public: using base_type = Base; using reference = Reference; using value_type = Value; using pointer = typename operator_arrow_dispatch::result_type; using difference_type = get_difference_type; using iterator_category = std::random_access_iterator_tag; iterator_adaptor() = default; explicit iterator_adaptor(base_type const& iter) : iter_(iter) {} // you can override this in derived decltype(auto) operator*() const noexcept { return *iter_; } // you can override this in derived Derived& operator+=(difference_type n) { iter_ += n; return this->derived(); } // you should override this in derived if there is an override for operator+= template difference_type operator-(const iterator_adaptor& x) const noexcept { return iter_ - x.iter_; } // you can override this in derived template bool operator==(const iterator_adaptor& x) const noexcept { return iter_ == x.iter_; } reference operator[](difference_type n) const { return *(this->derived() + n); } pointer operator->() const noexcept { return operator_arrow_dispatch::apply(this->derived().operator*()); } Derived& operator-=(difference_type n) { return this->derived().operator+=(-n); } Derived& operator++() { return this->derived().operator+=(1); } Derived& operator--() { return this->derived().operator+=(-1); } Derived operator++(int) { Derived tmp(this->derived()); operator++(); return tmp; } Derived operator--(int) { Derived tmp(this->derived()); operator--(); return tmp; } Derived operator+(difference_type n) const { return Derived(this->derived()) += n; } Derived operator-(difference_type n) const { return Derived(this->derived()) -= n; } template bool operator!=(const iterator_adaptor& x) const noexcept { return !this->derived().operator==(x); } template bool operator<(const iterator_adaptor& x) const noexcept { return iter_ < x.iter_; } template bool operator>=(const iterator_adaptor& x) const noexcept { return iter_ >= x.iter_; } template bool operator>(const iterator_adaptor& x) const noexcept { return iter_ > x.iter_; } template bool operator<=(const iterator_adaptor& 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: refer to base class in derived class using iterator_adaptor_ = iterator_adaptor; private: Derived& derived() noexcept { return *static_cast(this); } const Derived& derived() const noexcept { return *static_cast(this); } base_type iter_; template friend class iterator_adaptor; }; } // namespace detail } // namespace histogram } // namespace boost #endif