|
|
@@ -0,0 +1,243 @@
|
|
|
+#pragma once
|
|
|
+
|
|
|
+#include <iterator>
|
|
|
+#include <type_traits>
|
|
|
+
|
|
|
+#include "detail/arrow_proxy.h"
|
|
|
+
|
|
|
+#define _val(type) std::declval<type>()
|
|
|
+#define exists(expr) void_t<decltype(expr)>
|
|
|
+
|
|
|
+namespace iterator::detail {
|
|
|
+ template <typename> using void_t = void;
|
|
|
+
|
|
|
+ template <typename, typename = void> struct has_equal_to : std::false_type {};
|
|
|
+ template <typename T>
|
|
|
+ struct has_equal_to<T, exists(_val(T).equal_to(_val(T)))> : std::true_type {};
|
|
|
+
|
|
|
+ template <typename, typename = void>
|
|
|
+ struct has_distance_to : std::false_type {};
|
|
|
+ template <typename T>
|
|
|
+ struct has_distance_to<T, exists(_val(T).distance_to(_val(T)))>
|
|
|
+ : std::true_type {};
|
|
|
+
|
|
|
+ template <typename, typename = void>
|
|
|
+ struct is_advanceable_iterator : std::false_type {};
|
|
|
+ template <typename T>
|
|
|
+ struct is_advanceable_iterator<T, exists(_val(T).advance({}))>
|
|
|
+ : std::true_type {};
|
|
|
+
|
|
|
+ template <typename, typename = void>
|
|
|
+ struct is_single_pass_iterator : std::false_type {};
|
|
|
+ template <typename T>
|
|
|
+ struct is_single_pass_iterator<T, void_t<typename T::single_pass_iterator>>
|
|
|
+ : std::true_type {};
|
|
|
+
|
|
|
+ template <typename, typename = void>
|
|
|
+ struct has_increment : std::false_type {};
|
|
|
+ template <typename T>
|
|
|
+ struct has_increment<T, exists(_val(T).increment())> : std::true_type {};
|
|
|
+
|
|
|
+ template <typename, typename = void>
|
|
|
+ struct has_decrement : std::false_type {};
|
|
|
+ template <typename T>
|
|
|
+ struct has_decrement<T, exists(_val(T).decrement())> : std::true_type {};
|
|
|
+
|
|
|
+ template <typename, typename = void> struct distance_to {
|
|
|
+ using type = std::ptrdiff_t;
|
|
|
+ };
|
|
|
+
|
|
|
+ template <typename T>
|
|
|
+ struct distance_to<T, std::enable_if_t<has_distance_to<T>{}>> {
|
|
|
+ using type = decltype(_val(T).distance_to(_val(T)));
|
|
|
+ };
|
|
|
+
|
|
|
+ template <typename T> using distance_to_t = typename distance_to<T>::type;
|
|
|
+ template <typename T> constexpr bool has_equal_to_v = has_equal_to<T>{};
|
|
|
+ template <typename T> constexpr bool has_distance_to_v = has_distance_to<T>{};
|
|
|
+ template <typename T> constexpr bool has_increment_v = has_increment<T>{};
|
|
|
+ template <typename T> constexpr bool has_decrement_v = has_decrement<T>{};
|
|
|
+ template <typename T>
|
|
|
+ constexpr bool is_advanceable_iterator_v = is_advanceable_iterator<T>{};
|
|
|
+
|
|
|
+ template <typename T>
|
|
|
+ constexpr bool is_random_access_iterator_v =
|
|
|
+ has_distance_to_v<T> && is_advanceable_iterator_v<T>;
|
|
|
+ template <typename T>
|
|
|
+ constexpr bool is_bidirectional_iterator_v =
|
|
|
+ has_decrement_v<T> && has_increment_v<T> && has_equal_to_v<T>;
|
|
|
+ template <typename T>
|
|
|
+ constexpr bool is_single_pass_iterator_v = is_single_pass_iterator<T>{};
|
|
|
+
|
|
|
+ template <typename T>
|
|
|
+ using iterator_category_t = std::conditional_t<
|
|
|
+ is_random_access_iterator_v<T>, std::random_access_iterator_tag,
|
|
|
+ std::conditional_t<is_bidirectional_iterator_v<T>,
|
|
|
+ std::bidirectional_iterator_tag,
|
|
|
+ std::conditional_t<is_single_pass_iterator_v<T>,
|
|
|
+ std::input_iterator_tag,
|
|
|
+ std::forward_iterator_tag>>>;
|
|
|
+}
|
|
|
+
|
|
|
+#undef _val
|
|
|
+#undef exists
|
|
|
+
|
|
|
+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 {
|
|
|
+ public:
|
|
|
+ decltype(auto) operator*() const { return self().dereference(); }
|
|
|
+
|
|
|
+ decltype(auto) operator->() const {
|
|
|
+ if constexpr (std::is_reference<decltype(**this)>{}) {
|
|
|
+ return std::addressof(**this);
|
|
|
+ } else {
|
|
|
+ return detail::arrow_proxy{**this};
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename D, typename = difference_type_arg_t<D, self_type>>
|
|
|
+ decltype(auto) operator[](D off) const {
|
|
|
+ return *(self() + off);
|
|
|
+ }
|
|
|
+
|
|
|
+ self_type & operator++() {
|
|
|
+ if constexpr (detail::is_advanceable_iterator_v<self_type>) {
|
|
|
+ *this += 1;
|
|
|
+ } else {
|
|
|
+ self().increment();
|
|
|
+ }
|
|
|
+ return self();
|
|
|
+ }
|
|
|
+
|
|
|
+ auto operator++(int) {
|
|
|
+ if constexpr (detail::is_single_pass_iterator_v<self_type>) {
|
|
|
+ ++*this;
|
|
|
+ } else {
|
|
|
+ auto tmp = self();
|
|
|
+ ++*this;
|
|
|
+ return tmp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ self_type & operator--() {
|
|
|
+ if constexpr (detail::is_advanceable_iterator_v<self_type>) {
|
|
|
+ *this -= 1;
|
|
|
+ } else {
|
|
|
+ self().decrement();
|
|
|
+ }
|
|
|
+ return self();
|
|
|
+ }
|
|
|
+
|
|
|
+ self_type operator--(int) {
|
|
|
+ auto tmp = self();
|
|
|
+ --*this;
|
|
|
+ return tmp;
|
|
|
+ }
|
|
|
+
|
|
|
+ template <typename D, typename = difference_type_arg_t<D, self_type>>
|
|
|
+ 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>>
|
|
|
+ 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>>
|
|
|
+ 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>>
|
|
|
+ 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>>
|
|
|
+ friend auto operator-(self_type self, D off) {
|
|
|
+ static_assert(detail::is_advanceable_iterator_v<self_type>,
|
|
|
+ "must be advancable");
|
|
|
+ return self -= off;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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>) {
|
|
|
+ return (left - right) == 0;
|
|
|
+ } else {
|
|
|
+ return left.equal_to(right);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ friend bool operator!=(self_type const & left, self_type const & right) {
|
|
|
+ return !(left == right);
|
|
|
+ }
|
|
|
+
|
|
|
+ friend bool operator<(self_type const & left, self_type const & right) {
|
|
|
+ return (left - right) < 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ friend bool operator<=(self_type const & left, self_type const & right) {
|
|
|
+ return (left - right) <= 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ friend bool operator>(self_type const & left, self_type const & right) {
|
|
|
+ return (left - right) > 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ friend bool operator>=(self_type const & left, self_type const & right) {
|
|
|
+ return (left - right) >= 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ private:
|
|
|
+ self_type & self() { return *static_cast<self_type *>(this); }
|
|
|
+ self_type const & self() const {
|
|
|
+ return *static_cast<self_type const *>(this);
|
|
|
+ }
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+namespace std {
|
|
|
+ // In C++20, a concept/requires could be used to eschew the need for the below
|
|
|
+ // macros.
|
|
|
+ template <typename I> struct iterator_traits<::iterator::facade<I>> {
|
|
|
+ using reference = decltype(*std::declval<I>());
|
|
|
+ using value_type = std::remove_cv_t<std::remove_reference_t<reference>>;
|
|
|
+ using pointer = decltype(std::declval<I>().operator->());
|
|
|
+ using difference_type = ::iterator::detail::distance_to_t<I>;
|
|
|
+ using iterator_category = ::iterator::detail::iterator_category_t<I>;
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+#define MAKE_ITERATOR_FACADE_TYPEDEFS(type) \
|
|
|
+ namespace std { \
|
|
|
+ template <> \
|
|
|
+ struct iterator_traits<type> \
|
|
|
+ : std::iterator_traits<::iterator::facade<type>> {}; \
|
|
|
+ }
|
|
|
+
|
|
|
+#define MAKE_ITERATOR_FACADE_TYPEDEFS_T(type) \
|
|
|
+ namespace std { \
|
|
|
+ template <typename T> \
|
|
|
+ struct iterator_traits<type<T>> \
|
|
|
+ : std::iterator_traits<::iterator::facade<type<T>>> {}; \
|
|
|
+ }
|