#pragma once #include #include #include #include #include namespace iterator::detail { template struct distance_to { using type = std::ptrdiff_t; }; template struct distance_to { using type = decltype(VAL(T).distance_to(VAL(T))); }; template using distance_to_t = typename distance_to::type; } namespace iterator { template using difference_type_arg_t = std::enable_if_t>>; template class facade { private: using self_type = CRTP; public: constexpr static auto category_enum = C; public: decltype(auto) operator*() const { return self().dereference(); } decltype(auto) operator->() const { if constexpr (std::is_reference{}) { return std::addressof(**this); } else { return detail::arrow_proxy{**this}; } } template , REQUIRES(DEFER(D) && C == category::random_access)> decltype(auto) operator[](D off) const { return *(self() + off); } self_type & operator++() { if constexpr (C == category::random_access) { self() += 1; } else { self().increment(); } return self(); } auto operator++(int) { if constexpr (C == category::single_pass) { ++*this; } else { auto tmp = self(); ++*this; return tmp; } } SFINAE(C >= category::bidirectional) self_type & operator--() { if constexpr (C == category::random_access) { self() -= 1; } else { self().decrement(); } return self(); } SFINAE(C >= category::bidirectional) self_type operator--(int) { auto tmp = self(); --*this; return tmp; } template , REQUIRES(DEFER(D) && C == category::random_access)> friend self_type & operator+=(self_type & self, D off) { self.advance(off); return self; } template , REQUIRES(DEFER(D) && C == category::random_access)> friend self_type & operator-=(self_type & self, D off) { self.advance(-off); return self; } template , REQUIRES(DEFER(D) && C == category::random_access)> friend auto operator+(self_type self, D off) { return self += off; } template , REQUIRES(DEFER(D) && C == category::random_access)> friend auto operator+(D off, self_type self) { return self += off; } template , REQUIRES(DEFER(D) && C == category::random_access)> friend auto operator-(self_type self, D off) { return self -= off; } SFINAE(C == category::random_access) friend auto operator-(self_type const & left, self_type const & right) { return right.distance_to(left); } friend bool operator==(self_type const & left, self_type const & right) { if constexpr (C == category::random_access) { return (left - right) == 0; } else { return left.equal_to(right); } } friend bool operator!=(self_type const & left, self_type const & right) { return !(left == right); } SFINAE(C == category::random_access) friend bool operator<(self_type const & left, self_type const & right) { return (left - right) < 0; } SFINAE(C == category::random_access) friend bool operator<=(self_type const & left, self_type const & right) { return (left - right) <= 0; } SFINAE(C == category::random_access) friend bool operator>(self_type const & left, self_type const & right) { return (left - right) > 0; } SFINAE(C == category::random_access) friend bool operator>=(self_type const & left, self_type const & right) { return (left - right) >= 0; } protected: self_type & self() { return *static_cast(this); } self_type const & self() const { return *static_cast(this); } }; } // In C++20, a concept/requires could be used to eschew the need for the below // macros. #define MAKE_ITERATOR_FACADE_TYPEDEFS_T(Iter) \ template struct std::iterator_traits> { \ using type = Iter; \ using reference = decltype(*std::declval()); \ using value_type = std::decay_t; \ using pointer = decltype(std::declval().operator->()); \ using difference_type = ::iterator::detail::distance_to_t; \ using iterator_category = ::iterator::detail::tag_for_t; \ } #include