// // immer: immutable data structures for C++ // Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente // // This software is distributed under the Boost Software License, Version 1.0. // See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt // #pragma once #include #include #include namespace immer { namespace detail { struct iterator_core_access { template static decltype(auto) dereference(T&& x) { return x.dereference(); } template static decltype(auto) increment(T&& x) { return x.increment(); } template static decltype(auto) decrement(T&& x) { return x.decrement(); } template static decltype(auto) equal(T1&& x1, T2&& x2) { return x1.equal(x2); } template static decltype(auto) advance(T&& x, D d) { return x.advance(d); } template static decltype(auto) distance_to(T1&& x1, T2&& x2) { return x1.distance_to(x2); } }; /*! * Minimalistic reimplementation of boost::iterator_facade */ template class iterator_facade { public: using iterator_category = IteratorCategoryT; using value_type = T; using difference_type = DifferenceTypeT; using pointer = PointerT; using reference = ReferenceT; protected: using access_t = iterator_core_access; constexpr static auto is_random_access = std::is_base_of::value; constexpr static auto is_bidirectional = std::is_base_of::value; class reference_proxy { friend iterator_facade; DerivedT iter_; reference_proxy(DerivedT iter) : iter_{std::move(iter)} {} public: operator ReferenceT() const { return *iter_; } }; const DerivedT& derived() const { static_assert(std::is_base_of::value, "must pass a derived thing"); return *static_cast(this); } DerivedT& derived() { static_assert(std::is_base_of::value, "must pass a derived thing"); return *static_cast(this); } public: ReferenceT operator*() const { return access_t::dereference(derived()); } PointerT operator->() const { return &access_t::dereference(derived()); } reference_proxy operator[](DifferenceTypeT n) const { static_assert(is_random_access, ""); return derived() + n; } bool operator==(const DerivedT& rhs) const { return access_t::equal(derived(), rhs); } bool operator!=(const DerivedT& rhs) const { return !access_t::equal(derived(), rhs); } DerivedT& operator++() { access_t::increment(derived()); return derived(); } DerivedT operator++(int) { auto tmp = derived(); access_t::increment(derived()); return tmp; } DerivedT& operator--() { static_assert(is_bidirectional || is_random_access, ""); access_t::decrement(derived()); return derived(); } DerivedT operator--(int) { static_assert(is_bidirectional || is_random_access, ""); auto tmp = derived(); access_t::decrement(derived()); return tmp; } DerivedT& operator+=(DifferenceTypeT n) { access_t::advance(derived(), n); return derived(); } DerivedT& operator-=(DifferenceTypeT n) { access_t::advance(derived(), -n); return derived(); } DerivedT operator+(DifferenceTypeT n) const { static_assert(is_random_access, ""); auto tmp = derived(); return tmp += n; } friend DerivedT operator+(DifferenceTypeT n, const DerivedT& i) { static_assert(is_random_access, ""); return i + n; } DerivedT operator-(DifferenceTypeT n) const { static_assert(is_random_access, ""); auto tmp = derived(); return tmp -= n; } DifferenceTypeT operator-(const DerivedT& rhs) const { static_assert(is_random_access, ""); return access_t::distance_to(rhs, derived()); } bool operator<(const DerivedT& rhs) const { static_assert(is_random_access, ""); return access_t::distance_to(derived(), rhs) > 0; } bool operator<=(const DerivedT& rhs) const { static_assert(is_random_access, ""); return access_t::distance_to(derived(), rhs) >= 0; } bool operator>(const DerivedT& rhs) const { static_assert(is_random_access, ""); return access_t::distance_to(derived(), rhs) < 0; } bool operator>=(const DerivedT& rhs) const { static_assert(is_random_access, ""); return access_t::distance_to(derived(), rhs) <= 0; } }; } // namespace detail } // namespace immer