فهرست منبع

Add a C++17 version of iterator_facade using type deduction.
TODO: Testing.

Sam Jaffe 4 سال پیش
والد
کامیت
4165d56213
2فایلهای تغییر یافته به همراه246 افزوده شده و 0 حذف شده
  1. 3 0
      include/iterator/detail/arrow_proxy.h
  2. 243 0
      include/iterator/facade.h

+ 3 - 0
include/iterator/detail/arrow_proxy.h

@@ -5,7 +5,10 @@
 
 namespace iterator { namespace detail {
   template <typename Reference> struct arrow_proxy {
+    arrow_proxy(Reference r) : r(std::move(r)) {}
     Reference r;
     Reference * operator->() { return std::addressof(r); }
   };
+
+  template <typename R> arrow_proxy(R r) -> arrow_proxy<R>;
 }}

+ 243 - 0
include/iterator/facade.h

@@ -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>>> {};                \
+  }