Browse Source

Add a proxy helper for iterators that implement only small QoL changes to a wrapped iterator type.

Sam Jaffe 4 years ago
parent
commit
707d29ab2c
2 changed files with 95 additions and 18 deletions
  1. 88 0
      include/iterator/proxy.h
  2. 7 18
      include/iterator/unkeyed_iterator.hpp

+ 88 - 0
include/iterator/proxy.h

@@ -0,0 +1,88 @@
+#pragma once
+
+#include <iterator>
+
+#include "facade.h"
+
+namespace iterator {
+  template <typename Iter, typename Self,
+            typename Category =
+                typename std::iterator_traits<Iter>::iterator_category>
+  class proxy;
+
+  template <typename Iter, typename Self>
+  class proxy<Iter, Self, std::input_iterator_tag> : public facade<Self> {
+  public:
+    using single_pass_iterator = void;
+
+  private:
+    Iter impl_;
+
+  public:
+    proxy(Iter impl = {}) : impl_(impl) {}
+
+    decltype(auto) dereference() const { return *impl_; }
+    void increment() { ++impl_; }
+    bool equal_to(proxy const & other) const { return impl_ == other.impl_; }
+
+  protected:
+    auto & impl() const { return impl_; }
+  };
+
+  template <typename Iter, typename Self>
+  class proxy<Iter, Self, std::forward_iterator_tag> : public facade<Self> {
+  private:
+    Iter impl_;
+
+  public:
+    proxy(Iter impl = {}) : impl_(impl) {}
+
+    decltype(auto) dereference() const { return *impl_; }
+    void increment() { ++impl_; }
+    bool equal_to(proxy const & other) const { return impl_ == other.impl_; }
+
+  protected:
+    auto & impl() const { return impl_; }
+  };
+
+  template <typename Iter, typename Self>
+  class proxy<Iter, Self, std::bidirectional_iterator_tag>
+      : public facade<Self> {
+  private:
+    Iter impl_;
+
+  public:
+    proxy(Iter impl = {}) : impl_(impl) {}
+
+    decltype(auto) dereference() const { return *impl_; }
+    void increment() { ++impl_; }
+    void decrement() { --impl_; }
+    bool equal_to(proxy const & other) const { return impl_ == other.impl_; }
+
+  protected:
+    auto & impl() const { return impl_; }
+  };
+
+  template <typename Iter, typename Self>
+  class proxy<Iter, Self, std::random_access_iterator_tag>
+      : public facade<Self> {
+  public:
+    using difference_type =
+        typename std::iterator_traits<Iter>::difference_type;
+
+  private:
+    Iter impl_;
+
+  public:
+    proxy(Iter impl = {}) : impl_(impl) {}
+
+    decltype(auto) dereference() const { return *impl_; }
+    void advance(difference_type off) { impl_ += off; }
+    difference_type distance_to(proxy const & other) const {
+      return impl_ - other.impl_;
+    }
+
+  protected:
+    auto & impl() const { return impl_; }
+  };
+}

+ 7 - 18
include/iterator/unkeyed_iterator.hpp

@@ -7,8 +7,7 @@
 
 #pragma once
 
-#include "facade.h"
-#include <iterator>
+#include "proxy.h"
 
 namespace iterator {
   /**
@@ -27,24 +26,14 @@ namespace iterator {
    * \endcode
    */
   template <typename Iterator>
-  class unkeyed_iterator : public facade<unkeyed_iterator<Iterator>> {
-  private:
-    static constexpr std::size_t const value_index =
-        std::tuple_size<typename Iterator::value_type>::value - 1;
-
+  class unkeyed_iterator : public proxy<Iterator, unkeyed_iterator<Iterator>> {
   public:
-    unkeyed_iterator() = default;
-    unkeyed_iterator(Iterator it) : base(it) {}
-
-    decltype(auto) dereference() const { return std::get<value_index>(*base); }
-    void increment() { ++base; }
-    void decrement() { --base; }
-    bool equal_to(unkeyed_iterator const & other) const {
-      return base == other.base;
+    using proxy<Iterator, unkeyed_iterator<Iterator>>::proxy;
+    decltype(auto) dereference() const {
+      using value_type = typename Iterator::value_type;
+      constexpr auto index = std::tuple_size<value_type>::value - 1;
+      return std::get<index>(*this->impl());
     }
-
-  private:
-    Iterator base;
   };
 }