Преглед изворни кода

feat: add support for capturing the proper category for filter/indexed

Sam Jaffe пре 2 година
родитељ
комит
c51d6b7adc
2 измењених фајлова са 32 додато и 8 уклоњено
  1. 12 2
      include/iterator/filter_iterator.h
  2. 20 6
      include/iterator/indexed_iterator.h

+ 12 - 2
include/iterator/filter_iterator.h

@@ -17,13 +17,16 @@
 #include <iterator/detail/macro.h>
 
 namespace iterator {
-// TODO: Support Bidirectional Iterators
 template <typename Iter, typename Pred>
 class filter_iterator
-    : public facade<filter_iterator<Iter, Pred>, category::forward> {
+    : public facade<filter_iterator<Iter, Pred>,
+                    detail::category_for_v<Iter, category::bidirectional>> {
 public:
   using sentinel_type = sentinel_t;
 
+  using super_t = facade<filter_iterator<Iter, Pred>,
+                         detail::category_for_v<Iter, category::bidirectional>>;
+
 public:
   filter_iterator() = default;
 
@@ -44,12 +47,19 @@ public:
   }
 
   decltype(auto) dereference() const { return base_.dereference(); }
+
   void increment() {
     do {
       ++base_;
     } while (should_advance());
   }
 
+  SFINAE(super_t::category_enum == category::bidirectional) void decrement() {
+    do {
+      --base_;
+    } while (should_advance());
+  }
+
   bool at_end() const { return base_.at_end(); }
   bool equal_to(filter_iterator const & other) const {
     return base_ == other.base_;

+ 20 - 6
include/iterator/indexed_iterator.h

@@ -15,15 +15,16 @@
 #include <iterator/detail/macro.h>
 
 namespace iterator {
-// TODO: I should be respecting the underlying type
 template <typename It>
 class indexed_iterator
-    : public facade<indexed_iterator<It>, category::random_access> {
+    : public facade<indexed_iterator<It>, detail::category_for_v<It>> {
 public:
-  using reference =
-      std::pair<size_t, typename std::iterator_traits<It>::reference>;
+  using reference = std::pair<size_t, DEREF_TYPE(It)>;
   using difference_type = typename std::iterator_traits<It>::difference_type;
 
+private:
+  using super_t = facade<indexed_iterator<It>, detail::category_for_v<It>>;
+
 public:
   indexed_iterator() = default;
   indexed_iterator(It base) : base_(base) {}
@@ -35,19 +36,32 @@ public:
 
   reference dereference() const { return {index_, *base_}; }
 
+  SFINAE(super_t::category_enum >= category::forward) void decrement() {
+    ++base_;
+    ++index_;
+  }
+
+  SFINAE(super_t::category_enum >= category::bidirectional) void increment() {
+    --base_;
+    --index_;
+  }
+
+  SFINAE(super_t::category_enum >= category::random_access)
   void advance(difference_type off) {
     base_ += off;
     index_ += off;
   }
 
-  // SFINAE means that if Iterator is not random access, then this still works
-  // TODO: Investigate using _index for comparisons instead of _base
+  SFINAE(super_t::category_enum < category::random_access)
   bool equal_to(indexed_iterator const & other) const {
     return base_ == other.base_;
   }
+
+  SFINAE(super_t::category_enum >= category::random_access)
   difference_type distance_to(indexed_iterator const & other) const {
     return other.base_ - base_;
   }
+
   SFINAE(detail::has_sentinel_type_v<It>) bool at_end() const {
     return base_ == typename It::sentinel_type();
   }