|
|
@@ -4,15 +4,35 @@
|
|
|
#include <type_traits>
|
|
|
|
|
|
#include <iterator/detail/arrow_proxy.h>
|
|
|
-#include <iterator/detail/facade_traits.h>
|
|
|
#include <iterator/detail/traits.h>
|
|
|
|
|
|
+#include <iterator/detail/macro.h>
|
|
|
+
|
|
|
+namespace iterator::detail {
|
|
|
+template <typename, typename = void> struct distance_to {
|
|
|
+ using type = std::ptrdiff_t;
|
|
|
+};
|
|
|
+
|
|
|
+template <typename T>
|
|
|
+struct distance_to<T, EXISTS(VAL(T).distance_to(VAL(T)))> {
|
|
|
+ using type = decltype(VAL(T).distance_to(VAL(T)));
|
|
|
+};
|
|
|
+
|
|
|
+template <typename T> using distance_to_t = typename distance_to<T>::type;
|
|
|
+}
|
|
|
+
|
|
|
namespace iterator {
|
|
|
template <typename D, typename T>
|
|
|
using difference_type_arg_t =
|
|
|
std::enable_if_t<std::is_convertible_v<D, detail::distance_to_t<T>>>;
|
|
|
|
|
|
-template <typename self_type> class facade {
|
|
|
+template <typename CRTP, category C> class facade {
|
|
|
+private:
|
|
|
+ using self_type = CRTP;
|
|
|
+
|
|
|
+public:
|
|
|
+ constexpr static auto category_enum = C;
|
|
|
+
|
|
|
public:
|
|
|
decltype(auto) operator*() const { return self().dereference(); }
|
|
|
|
|
|
@@ -24,13 +44,14 @@ public:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- template <typename D, typename = difference_type_arg_t<D, self_type>>
|
|
|
+ template <typename D, typename = difference_type_arg_t<D, self_type>,
|
|
|
+ REQUIRES(DEFER(D) && C == category::random_access)>
|
|
|
decltype(auto) operator[](D off) const {
|
|
|
return *(self() + off);
|
|
|
}
|
|
|
|
|
|
self_type & operator++() {
|
|
|
- if constexpr (detail::is_advanceable_iterator_v<self_type>) {
|
|
|
+ if constexpr (C == category::random_access) {
|
|
|
self() += 1;
|
|
|
} else {
|
|
|
self().increment();
|
|
|
@@ -39,7 +60,7 @@ public:
|
|
|
}
|
|
|
|
|
|
auto operator++(int) {
|
|
|
- if constexpr (detail::is_single_pass_iterator_v<self_type>) {
|
|
|
+ if constexpr (C == category::single_pass) {
|
|
|
++*this;
|
|
|
} else {
|
|
|
auto tmp = self();
|
|
|
@@ -48,8 +69,9 @@ public:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ SFINAE(C >= category::bidirectional)
|
|
|
self_type & operator--() {
|
|
|
- if constexpr (detail::is_advanceable_iterator_v<self_type>) {
|
|
|
+ if constexpr (C == category::random_access) {
|
|
|
self() -= 1;
|
|
|
} else {
|
|
|
self().decrement();
|
|
|
@@ -57,55 +79,52 @@ public:
|
|
|
return self();
|
|
|
}
|
|
|
|
|
|
+ SFINAE(C >= category::bidirectional)
|
|
|
self_type operator--(int) {
|
|
|
auto tmp = self();
|
|
|
--*this;
|
|
|
return tmp;
|
|
|
}
|
|
|
|
|
|
- template <typename D, typename = difference_type_arg_t<D, self_type>>
|
|
|
+ template <typename D, typename = difference_type_arg_t<D, self_type>,
|
|
|
+ REQUIRES(DEFER(D) && C == category::random_access)>
|
|
|
friend self_type & operator+=(self_type & self, D off) {
|
|
|
- static_assert(detail::is_advanceable_iterator_v<self_type>,
|
|
|
- "must be advancable");
|
|
|
self.advance(off);
|
|
|
return self;
|
|
|
}
|
|
|
|
|
|
- template <typename D, typename = difference_type_arg_t<D, self_type>>
|
|
|
+ template <typename D, typename = difference_type_arg_t<D, self_type>,
|
|
|
+ REQUIRES(DEFER(D) && C == category::random_access)>
|
|
|
friend self_type & operator-=(self_type & self, D off) {
|
|
|
- static_assert(detail::is_advanceable_iterator_v<self_type>,
|
|
|
- "must be advancable");
|
|
|
self.advance(-off);
|
|
|
return self;
|
|
|
}
|
|
|
|
|
|
- template <typename D, typename = difference_type_arg_t<D, self_type>>
|
|
|
+ template <typename D, typename = difference_type_arg_t<D, self_type>,
|
|
|
+ REQUIRES(DEFER(D) && C == category::random_access)>
|
|
|
friend auto operator+(self_type self, D off) {
|
|
|
- static_assert(detail::is_advanceable_iterator_v<self_type>,
|
|
|
- "must be advancable");
|
|
|
return self += off;
|
|
|
}
|
|
|
|
|
|
- template <typename D, typename = difference_type_arg_t<D, self_type>>
|
|
|
+ template <typename D, typename = difference_type_arg_t<D, self_type>,
|
|
|
+ REQUIRES(DEFER(D) && C == category::random_access)>
|
|
|
friend auto operator+(D off, self_type self) {
|
|
|
- static_assert(detail::is_advanceable_iterator_v<self_type>,
|
|
|
- "must be advancable");
|
|
|
return self += off;
|
|
|
}
|
|
|
|
|
|
- template <typename D, typename = difference_type_arg_t<D, self_type>>
|
|
|
+ template <typename D, typename = difference_type_arg_t<D, self_type>,
|
|
|
+ REQUIRES(DEFER(D) && C == category::random_access)>
|
|
|
friend auto operator-(self_type self, D off) {
|
|
|
- static_assert(detail::is_advanceable_iterator_v<self_type>,
|
|
|
- "must be advancable");
|
|
|
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 (detail::has_distance_to_v<self_type>) {
|
|
|
+ if constexpr (C == category::random_access) {
|
|
|
return (left - right) == 0;
|
|
|
} else {
|
|
|
return left.equal_to(right);
|
|
|
@@ -116,18 +135,22 @@ public:
|
|
|
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;
|
|
|
}
|
|
|
@@ -140,26 +163,16 @@ protected:
|
|
|
};
|
|
|
}
|
|
|
|
|
|
-#include <iterator/detail/macro.h>
|
|
|
-
|
|
|
// In C++20, a concept/requires could be used to eschew the need for the below
|
|
|
// macros.
|
|
|
-template <typename I> struct std::iterator_traits<::iterator::facade<I>> {
|
|
|
- using reference = DEREF_TYPE(I);
|
|
|
- using value_type = std::remove_cv_t<std::remove_reference_t<reference>>;
|
|
|
- using pointer = TYPE(I, operator->());
|
|
|
- using difference_type = ::iterator::detail::distance_to_t<I>;
|
|
|
- using iterator_category = ::iterator::detail::facade_category_t<I>;
|
|
|
-};
|
|
|
-
|
|
|
-#define MAKE_ITERATOR_FACADE_TYPEDEFS(type) \
|
|
|
- template <> \
|
|
|
- struct std::iterator_traits<type> \
|
|
|
- : std::iterator_traits<::iterator::facade<type>> {}
|
|
|
-
|
|
|
-#define MAKE_ITERATOR_FACADE_TYPEDEFS_T(type) \
|
|
|
- template <typename... T> \
|
|
|
- struct std::iterator_traits<type<T...>> \
|
|
|
- : std::iterator_traits<::iterator::facade<type<T...>>> {}
|
|
|
+#define MAKE_ITERATOR_FACADE_TYPEDEFS_T(Iter) \
|
|
|
+ template <typename... T> struct std::iterator_traits<Iter<T...>> { \
|
|
|
+ using type = Iter<T...>; \
|
|
|
+ using reference = decltype(*std::declval<type>()); \
|
|
|
+ using value_type = std::decay_t<reference>; \
|
|
|
+ using pointer = decltype(std::declval<type>().operator->()); \
|
|
|
+ using difference_type = ::iterator::detail::distance_to_t<type>; \
|
|
|
+ using iterator_category = ::iterator::detail::tag_for_t<type>; \
|
|
|
+ }
|
|
|
|
|
|
#include <iterator/detail/undef.h>
|