Просмотр исходного кода

refactor: make end_aware_iterator a proxy to allow random/bidirectional

refactor: create REQUIRES macro to condense enable_if container ctors

test: remove no longer true guarded end test
Sam Jaffe 2 лет назад
Родитель
Сommit
5ee6fea85e

+ 4 - 1
include/iterator/detail/macro.h

@@ -11,8 +11,11 @@
 
 #define FWD(x) std::forward<decltype(x)>(x)
 
+#define REQUIRES_T(trait, rval, ...) std::enable_if_t<trait, rval>
+#define REQUIRES(trait) typename = REQUIRES_T(trait, void)
+
 #define SFINAE(trait, rval)                                                    \
-  template <bool _ = true> std::enable_if_t<trait && _, rval>
+  template <bool _ = true> REQUIRES_T(trait && _, rval)
 
 #define VAL(X) std::declval<X>()
 #define DEREF_TYPE(X) decltype(*VAL(X))

+ 2 - 0
include/iterator/detail/undef.h

@@ -11,6 +11,8 @@
 
 #undef FWD
 #undef SFINAE
+#undef REQUIRES
+#undef REQUIRES_T
 #undef EXISTS
 #undef TYPE
 #undef DEREF_TYPE

+ 18 - 17
include/iterator/end_aware_iterator.h

@@ -8,10 +8,12 @@
 #pragma once
 
 #include <iterator/detail/traits.h>
-#include <iterator/facade.h>
 #include <iterator/forwards.h>
+#include <iterator/proxy.h>
 #include <iterator/sentinel.h>
 
+#include <iterator/detail/macro.h>
+
 namespace iterator {
 /**
  * @class end_aware_iterator
@@ -20,40 +22,37 @@ namespace iterator {
  * @tparam It The underlying iterator type
  */
 template <typename It>
-class end_aware_iterator : public facade<end_aware_iterator<It>> {
+class end_aware_iterator : public proxy<It, end_aware_iterator<It>> {
 public:
+  using super_t = proxy<It, end_aware_iterator<It>>;
   using sentinel_type = sentinel_t;
 
 public:
   end_aware_iterator() = default;
-  end_aware_iterator(It it, It end) : curr_(it), end_(end) {}
+  end_aware_iterator(It it, It end) : super_t(it), end_(end) {}
 
-  template <typename C, typename = std::enable_if_t<detail::is_container_v<C>>>
+  template <typename C, REQUIRES(detail::is_container_v<C>)>
   end_aware_iterator(C && container)
-      : curr_(std::begin(container)), end_(std::end(container)) {
+      : super_t(std::begin(container)), end_(std::end(container)) {
     static_assert(std::is_reference_v<C>,
                   "Cannot access iterator of a temporary");
   }
 
   template <typename Ot>
   end_aware_iterator(end_aware_iterator<Ot> const & other)
-      : curr_(other.curr_), end_(other.end_) {}
-
-  end_aware_iterator(end_aware_iterator<It> other, end_aware_iterator<It>)
-      : curr_(other.curr_), end_(other.end_) {}
+      : super_t(other.impl()), end_(other.end_) {}
 
-  decltype(auto) dereference() const { return *curr_; }
-  void increment() {
-    if (!at_end()) { ++curr_; }
-  }
-  bool at_end() const { return curr_ == end_; }
-  bool equal_to(end_aware_iterator const & other) const {
-    return curr_ == other.curr_;
+  bool at_end() const {
+    if constexpr (detail::is_random_access_v<It>) {
+      return super_t::impl() >= end_;
+    } else {
+      return super_t::impl() == end_;
+    }
   }
 
 private:
   template <typename O> friend class end_aware_iterator;
-  It curr_, end_;
+  It end_;
 };
 
 template <typename C>
@@ -65,3 +64,5 @@ end_aware_iterator(end_aware_iterator<It>, end_aware_iterator<It>)
 }
 
 MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::end_aware_iterator);
+
+#include <iterator/detail/undef.h>

+ 6 - 2
include/iterator/filter_iterator.h

@@ -15,6 +15,8 @@
 #include <iterator/facade.h>
 #include <iterator/forwards.h>
 
+#include <iterator/detail/macro.h>
+
 namespace iterator {
 template <typename Iter, typename Pred>
 class filter_iterator : public facade<filter_iterator<Iter, Pred>> {
@@ -24,7 +26,7 @@ public:
 public:
   filter_iterator() = default;
 
-  template <typename C, typename = std::enable_if_t<detail::is_container_v<C>>>
+  template <typename C, REQUIRES(detail::is_container_v<C>)>
   filter_iterator(C && c, Pred pred)
       : base_(std::forward<C>(c)), pred_(std::move(pred)) {
     if (should_advance()) { increment(); }
@@ -43,7 +45,7 @@ public:
   decltype(auto) dereference() const { return base_.dereference(); }
   void increment() {
     do {
-      base_.increment();
+      ++base_;
     } while (should_advance());
   }
 
@@ -70,3 +72,5 @@ filter_iterator(It, It, P) -> filter_iterator<It, P>;
 }
 
 MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::filter_iterator);
+
+#include <iterator/detail/undef.h>

+ 1 - 1
include/iterator/join_iterator.h

@@ -46,7 +46,7 @@ public:
     safely_init_inner_iterator(other.outer_, other.inner_);
   }
 
-  template <typename C, typename = std::enable_if_t<detail::is_container_v<C>>>
+  template <typename C, REQUIRES(detail::is_container_v<C>)>
   joining_iterator(C && container) : outer_(FWD(container)) {
     update_iterator();
   }

+ 0 - 10
test/end_aware_iterator_test.cxx

@@ -58,16 +58,6 @@ TEST(EndAwareIterator, PostIncrementReturnsCopyOfPrev) {
   EXPECT_EQ(*eai, 2);
 }
 
-TEST(EndAwareIterator, IncrementOnEndIsGuarded) {
-  std::vector<int> v{1, 2, 3, 4, 5};
-
-  end_aware_iterator it{v.end(), v.end()};
-  end_aware_iterator const cp = it;
-
-  ++it;
-  EXPECT_EQ(it, cp);
-}
-
 TEST(EndAwareIterator, CanIterateWithSentinel) {
   std::vector<int> v{1, 2, 3, 4, 5};
   size_t count{0};