#pragma once #include #include #include #include #include #include namespace iterator { template class facade { private: using self_type = CRTP; 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 (difference_type_arg && random_access) decltype(auto) operator[](D off) const { return *(self() + off); } self_type & operator++() { if constexpr (forward) { self().increment(); } else { static_assert(random_access, "requires .increment() or .advance()"); self() += 1; } return self(); } auto operator++(int) { if constexpr (single_pass) { ++*this; } else { auto tmp = self(); ++*this; return tmp; } } self_type & operator--() { if constexpr (bidirectional) { self().decrement(); } else { static_assert(random_access, "requires .decrement() or .advance()"); self() -= 1; } return self(); } self_type operator--(int) { auto tmp = self(); --*this; return tmp; } template requires (difference_type_arg && random_access) friend self_type & operator+=(self_type & self, D off) { self.advance(off); return self; } template requires (difference_type_arg && random_access) friend self_type & operator-=(self_type & self, D off) { self.advance(-off); return self; } template requires (difference_type_arg && random_access) friend auto operator+(self_type self, D off) { return self += off; } template requires (difference_type_arg && random_access) friend auto operator+(D off, self_type self) { return self += off; } template requires (difference_type_arg && random_access) friend auto operator-(self_type self, D off) { return self -= off; } friend auto operator-(self_type const & left, self_type const & right) requires(random_access) { return right.distance_to(left); } friend bool operator==(self_type const & left, self_type const & right) { return left.equal_to(right); } friend auto operator<=>(self_type const & left, self_type const & right) requires(random_access) { 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 requires std::is_base_of_v, It> struct std::iterator_traits { static const It& _it; using reference = decltype(*_it); using pointer = decltype(_it.operator->()); using value_type = ::iterator::infer_value_type_t; using difference_type = ::iterator::infer_difference_type_t; using iterator_category = std::conditional_t< ::iterator::random_access, random_access_iterator_tag, std::conditional_t< ::iterator::bidirectional, bidirectional_iterator_tag, std::conditional_t<::iterator::single_pass, input_iterator_tag, forward_iterator_tag> > >; }; //template requires(std::derived_from>) //struct std::iterator_traits { // using reference = decltype(std::declval().operator*()); // using value_type = std::decay_t; // using pointer = decltype(std::declval().operator->()); // using difference_type = ::iterator::infer_difference_type_t; // using iterator_category = std::input_iterator_tag; //}; // //template requires(std::derived_from>) //struct std::iterator_traits { // using reference = decltype(std::declval().operator*()); // using value_type = std::decay_t; // using pointer = decltype(std::declval().operator->()); // using difference_type = ::iterator::infer_difference_type_t; // using iterator_category = std::forward_iterator_tag; //}; // //template requires(std::derived_from>) //struct std::iterator_traits { // using reference = decltype(std::declval().operator*()); // using value_type = std::decay_t; // using pointer = decltype(std::declval().operator->()); // using difference_type = ::iterator::infer_difference_type_t; // using iterator_category = std::bidirectional_iterator_tag; //}; // //template requires(std::derived_from>) //struct std::iterator_traits { // using reference = decltype(std::declval().operator*()); // using value_type = std::decay_t; // using pointer = decltype(std::declval().operator->()); // using difference_type = ::iterator::infer_difference_type_t; // using iterator_category = std::random_access_iterator_tag; //}; #include