瀏覽代碼

refactor: re-implement joining_iterator using capture_iterator as needed

Sam Jaffe 2 年之前
父節點
當前提交
4b4492af6a
共有 2 個文件被更改,包括 58 次插入86 次删除
  1. 56 84
      include/iterator/join_iterator.h
  2. 2 2
      test/join_iterator_test.cxx

+ 56 - 84
include/iterator/join_iterator.h

@@ -11,119 +11,91 @@
 #include <memory>
 #include <utility>
 
+#include <iterator/capture_iterator.h>
 #include <iterator/end_aware_iterator.h>
 #include <iterator/facade.h>
 #include <iterator/forwards.h>
 
 #include <iterator/detail/macro.h>
 
-namespace iterator::joining {
-template <typename Iter, typename = void> class iterator {
-protected:
-  using inner_t = DEREF_TYPE(Iter);
+namespace iterator {
+template <typename It>
+class joining_iterator : public facade<joining_iterator<It>> {
+private:
+  template <typename Ot> friend class joining_iterator;
+  constexpr static bool requires_caching = detail::is_rvalue_iterator_v<It>;
 
 public:
-  iterator() = default;
-
-  template <typename I>
-  iterator(iterator<I> const & other)
-      : iterator(other.joiner_, other.element_) {}
-
-  template <typename C, typename = std::enable_if_t<detail::is_container_v<C>>>
-  iterator(C && container)
-      : iterator(end_aware_iterator(std::forward<C>(container))) {}
+  using sentinel_type = sentinel_t;
+  using outer_iterator_t =
+      std::conditional_t<requires_caching,
+                         capture_iterator<end_aware_iterator<It>>,
+                         end_aware_iterator<It>>;
+  using inner_iterator_t =
+      end_aware_iterator<detail::iter<DEREF_TYPE(outer_iterator_t)>>;
 
-  iterator(end_aware_iterator<Iter> join) : iterator(join, {}, true) {}
+private:
+  outer_iterator_t outer_;
+  inner_iterator_t inner_;
 
-  iterator(end_aware_iterator<Iter> join,
-           end_aware_iterator<detail::iter<inner_t>> elem, bool update = false)
-      : joiner_(join), element_(elem) {
-    if (update) { update_iterator(); }
-  }
+public:
+  joining_iterator() = default;
 
-protected:
-  void update_iterator() {
-    while (!joiner_.at_end() &&
-           (element_ = end_aware_iterator(*joiner_)).at_end()) {
-      ++joiner_;
-    }
+  template <typename Ot>
+  joining_iterator(joining_iterator<Ot> const & other) : outer_(other.outer_) {
+    safely_init_inner_iterator(other.outer_, other.inner_);
   }
 
-protected:
-  template <typename, typename> friend class iterator;
-  end_aware_iterator<Iter> joiner_;
-  end_aware_iterator<detail::iter<inner_t>> element_;
-};
-
-template <typename Iter>
-class iterator<Iter, std::enable_if_t<detail::is_rvalue_iterator_v<Iter>>> {
-protected:
-  using inner_t = DEREF_TYPE(Iter);
-
-public:
-  iterator() = default;
   template <typename C, typename = std::enable_if_t<detail::is_container_v<C>>>
-  iterator(C && container) : joiner_(std::forward<C>(container)) {
+  joining_iterator(C && container) : outer_(std::forward<C>(container)) {
     update_iterator();
   }
 
-  iterator(end_aware_iterator<Iter> join) : joiner_(join) { update_iterator(); }
-
-protected:
-  void update_iterator() {
-    while (!joiner_.at_end() && sync().at_end()) {
-      ++joiner_;
-    }
+  joining_iterator(outer_iterator_t outer) : outer_(outer) {
+    update_iterator();
   }
 
-private:
-  end_aware_iterator<detail::iter<inner_t>> const & sync() {
-    if (joiner_.at_end()) { return element_ = {}; }
-    cache_ = std::make_shared<inner_t>(*joiner_);
-    element_ = end_aware_iterator(*cache_);
-    return element_;
+  joining_iterator(outer_iterator_t const & outer,
+                   inner_iterator_t const & inner)
+      : outer_(outer) {
+    safely_init_inner_iterator(outer, inner);
   }
 
-protected:
-  end_aware_iterator<Iter> joiner_;
-  std::shared_ptr<inner_t> cache_;
-  end_aware_iterator<detail::iter<inner_t>> element_;
-};
-}
-
-namespace iterator {
-template <typename Iter>
-class joining_iterator : public facade<joining_iterator<Iter>>,
-                         public joining::iterator<Iter> {
-public:
-  using super_t = joining::iterator<Iter>;
-  using sentinel_type = sentinel_t;
-
-public:
-  using super_t::super_t;
-
-  template <typename C, typename = std::enable_if_t<detail::is_container_v<C>>>
-  joining_iterator(C && container) : super_t(std::forward<C>(container)) {}
-
-  joining_iterator(end_aware_iterator<Iter> join) : super_t(join) {}
-
   void increment() {
-    if ((++super_t::element_).at_end()) {
-      ++super_t::joiner_;
-      super_t::update_iterator();
+    if ((++inner_).at_end()) {
+      ++outer_;
+      update_iterator();
     }
   }
 
-  decltype(auto) dereference() const { return *super_t::element_; }
+  decltype(auto) dereference() const { return *inner_; }
 
-  bool at_end() const { return join_iterator().at_end(); }
+  bool at_end() const { return outer_iterator().at_end(); }
   bool equal_to(joining_iterator const & other) const {
-    return join_iterator() == other.join_iterator() &&
-           element_iterator() == other.element_iterator();
+    return outer_iterator() == other.outer_iterator() &&
+           inner_iterator() == other.inner_iterator();
+  }
+
+  auto const & outer_iterator() const { return outer_; }
+  auto const & inner_iterator() const { return inner_; }
+
+private:
+  template <typename OuterIt, typename InnerIt>
+  void safely_init_inner_iterator(OuterIt const & outer,
+                                  InnerIt const & inner) {
+    if constexpr (requires_caching) {
+      inner_ = *outer_;
+      std::advance(inner_, std::distance(InnerIt(*outer), inner));
+    } else {
+      inner_ = inner;
+    }
   }
 
-  auto const & join_iterator() const { return super_t::joiner_; }
-  auto const & element_iterator() const { return super_t::element_; }
+  void update_iterator() {
+    while (!outer_.at_end() && (inner_ = *outer_).at_end()) {
+      ++outer_;
+    }
+  }
 };
 
 template <typename C>

+ 2 - 2
test/join_iterator_test.cxx

@@ -39,13 +39,13 @@ TEST(JoinIteratorTest, CanAccessInternalIterator) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
   auto eai = end_aware_iterator(mv);
   joining_iterator it(eai);
-  EXPECT_EQ(it.join_iterator(), eai);
+  EXPECT_EQ(it.outer_iterator(), eai);
 }
 
 TEST(JoinIteratorTest, CanAccessChildIterator) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
   joining_iterator it(mv);
-  EXPECT_EQ(it.element_iterator(), end_aware_iterator(mv[0]));
+  EXPECT_EQ(it.inner_iterator(), end_aware_iterator(mv[0]));
 }
 
 TEST(JoinIteratorTest, PreIncrementAdvancesIterator) {