Sfoglia il codice sorgente

refactor: clean up filter_iterator, allow non std::function predicates

Sam Jaffe 2 anni fa
parent
commit
1c7c47b542

+ 21 - 18
include/iterator/filter_iterator.h

@@ -15,25 +15,26 @@
 #include <iterator/forwards.h>
 
 namespace iterator {
-template <typename Iter>
-class filter_iterator : public facade<filter_iterator<Iter>> {
+template <typename Iter, typename Pred>
+class filter_iterator : public facade<filter_iterator<Iter, Pred>> {
 public:
   using sentinel_type = sentinel_t;
 
-  using reference = typename std::iterator_traits<Iter>::reference;
-  using predicate_t = std::function<bool(reference)>;
-
 public:
   filter_iterator() = default;
 
   template <typename C, typename = std::enable_if_t<detail::is_container_v<C>>>
-  filter_iterator(predicate_t pred, C && c)
-      : filter_iterator(std::move(pred), std::begin(c), std::end(c)) {}
+  filter_iterator(C && c, Pred pred)
+      : base_(std::forward<C>(c)), pred_(std::move(pred)) {
+    if (should_advance()) { increment(); }
+  }
 
-  filter_iterator(predicate_t pred, Iter curr, Iter end)
-      : filter_iterator(std::move(pred), end_aware_iterator(curr, end)) {}
+  filter_iterator(Iter curr, Iter end, Pred pred)
+      : base_(end_aware_iterator(curr, end)), pred_(std::move(pred)) {
+    if (should_advance()) { increment(); }
+  }
 
-  filter_iterator(predicate_t pred, end_aware_iterator<Iter> curr)
+  filter_iterator(end_aware_iterator<Iter> curr, Pred pred)
       : base_(curr), pred_(std::move(pred)) {
     if (should_advance()) { increment(); }
   }
@@ -51,18 +52,20 @@ public:
   }
 
 public:
-  bool should_advance() { return !base_.at_end() && !pred_(dereference()); }
+  bool should_advance() {
+    return !base_.at_end() && !std::invoke(pred_, dereference());
+  }
 
   end_aware_iterator<Iter> base_;
-  predicate_t pred_;
+  Pred pred_;
 };
 
-template <typename P, typename C>
-filter_iterator(P, C &&) -> filter_iterator<detail::iter<C>>;
-template <typename P, typename It>
-filter_iterator(P, end_aware_iterator<It>) -> filter_iterator<It>;
-template <typename P, typename It>
-filter_iterator(P, It, It) -> filter_iterator<It>;
+template <typename C, typename P>
+filter_iterator(C &&, P) -> filter_iterator<detail::iter<C>, P>;
+template <typename It, typename P>
+filter_iterator(P, end_aware_iterator<It>, P) -> filter_iterator<It, P>;
+template <typename It, typename P>
+filter_iterator(It, It, P) -> filter_iterator<It, P>;
 }
 
 MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::filter_iterator);

+ 1 - 1
include/iterator/forwards.h

@@ -23,7 +23,7 @@ struct sentinel_t;
 template <typename> class end_aware_iterator;
 template <typename It, typename = typename It::sentinel_type>
 class sentinel_iterator;
-template <typename> class filter_iterator;
+template <typename, typename> class filter_iterator;
 template <typename> class joining_iterator;
 template <typename> class unkeyed_iterator;
 template <typename...> class zip_iterator;

+ 6 - 6
test/filter_iterator_test.cxx

@@ -11,7 +11,7 @@ bool is_even(int i) { return i % 2 == 0; }
 
 TEST(FilterIterator, CanPerformSkipsOnData) {
   std::vector<int> const data = {1, 2, 3, 4, 5};
-  filter_iterator it(is_even, data);
+  filter_iterator it(data, is_even);
 
   EXPECT_EQ(ranges::distance(it, iterator::sentinel), 2);
   EXPECT_EQ(*it++, 2);
@@ -21,7 +21,7 @@ TEST(FilterIterator, CanPerformSkipsOnData) {
 // TODO: Maybe this should actually move
 TEST(FilterIterator, MutatingContainerDoesNotMoveIterator) {
   std::vector<int> data = {1, 2, 3, 4, 5};
-  filter_iterator it(is_even, data);
+  filter_iterator it(data, is_even);
 
   EXPECT_EQ(ranges::distance(it, iterator::sentinel), 2);
 
@@ -32,21 +32,21 @@ TEST(FilterIterator, MutatingContainerDoesNotMoveIterator) {
 
 TEST(FilterIterator, CanConstructFilterFromSubRange) {
   std::vector<int> data = {1, 2, 3, 4, 5};
-  filter_iterator it(is_even, data.begin(), data.begin() + 3);
+  filter_iterator it(data.begin(), data.begin() + 3, is_even);
 
   EXPECT_EQ(ranges::distance(it, iterator::sentinel), 1);
 }
 
 TEST(FilterIterator, IfNonMatchThenStartIsEnd) {
   std::vector<int> const data = {1, 3, 5};
-  filter_iterator it(is_even, data);
+  filter_iterator it(data, is_even);
 
   EXPECT_EQ(it, iterator::sentinel);
 }
 
 TEST(FilterIterator, CapsIterationAtEnd) {
   std::vector<int> const data = {1, 2, 3, 4, 5};
-  filter_iterator it(is_even, data);
+  filter_iterator it(data, is_even);
 
   ++ ++it;
   EXPECT_EQ(it, iterator::sentinel);
@@ -58,7 +58,7 @@ TEST(FilterIterator, CapsIterationAtEnd) {
 TEST(FilterIterator, CanIterateWithSentinel) {
   std::vector<int> v{1, 2, 3, 4, 5};
   size_t count{0};
-  for (filter_iterator it(is_even, v); it != iterator::sentinel; ++it) {
+  for (filter_iterator it(v, is_even); it != iterator::sentinel; ++it) {
     ++count;
   }