Browse Source

refactor: add more type deduction guides

Sam Jaffe 3 years ago
parent
commit
f6809add08

+ 18 - 21
include/iterator/filter_iterator.hpp

@@ -12,6 +12,8 @@
 #include "end_aware_iterator.hpp"
 #include "facade.h"
 
+template <typename C> using iter = decltype(std::begin(std::declval<C>()));
+
 namespace iterator {
   template <typename Iter>
   class filter_iterator : public facade<filter_iterator<Iter>> {
@@ -25,12 +27,18 @@ namespace iterator {
 
   public:
     filter_iterator() = default;
+
+    template <typename C>
+    filter_iterator(predicate_t pred, C && c)
+        : filter_iterator(std::move(pred), std::begin(c), std::end(c)) {}
+
     filter_iterator(predicate_t pred, Iter curr, Iter end)
-        : base_(curr, end), pred_(std::move(pred)) {
+        : filter_iterator(std::move(pred), end_aware_iterator(curr, end)) {}
+
+    filter_iterator(predicate_t pred, end_aware_iterator<Iter> curr)
+        : base_(curr), pred_(std::move(pred)) {
       if (should_advance()) { increment(); }
     }
-    filter_iterator(predicate_t pred, Iter end)
-        : filter_iterator(end, end, std::move(pred)) {}
 
     decltype(auto) dereference() const { return base_.dereference(); }
     void increment() {
@@ -48,24 +56,13 @@ namespace iterator {
     end_aware_iterator<Iter> base_;
     predicate_t pred_;
   };
-}
 
-MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::filter_iterator);
-
-template <typename Pred, typename Iter>
-iterator::filter_iterator<Iter> make_filter_iterator(Pred && p, Iter it,
-                                                     Iter end) {
-  return {p, it, end};
-}
-
-template <typename Pred, typename C>
-auto make_filter_iterator(Pred && p, C & collect)
-    -> iterator::filter_iterator<decltype(std::begin(collect))> {
-  return {p, std::begin(collect), std::end(collect)};
+  template <typename P, typename C>
+  filter_iterator(P, C &&) -> filter_iterator<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 Pred, typename C>
-auto make_filter_iterator(Pred && p, C const & collect)
-    -> iterator::filter_iterator<decltype(std::begin(collect))> {
-  return {p, std::begin(collect), std::end(collect)};
-}
+MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::filter_iterator);

+ 13 - 10
include/iterator/indexed_iterator.hpp

@@ -21,34 +21,37 @@ namespace iterator {
 
   public:
     indexed_iterator() = default;
-    explicit indexed_iterator(It base, size_t idx = 0)
-        : _base(base), _index(idx) {}
+    indexed_iterator(It base) : base_(base) {}
+    indexed_iterator(It base, size_t idx) : base_(base), index_(idx) {}
 
     template <typename O>
     indexed_iterator(indexed_iterator<O> const & oiter)
-        : _base(oiter._base), _index(oiter._index) {}
+        : base_(oiter.base_), index_(oiter.index_) {}
 
-    reference dereference() const { return {_index, *_base}; }
+    reference dereference() const { return {index_, *base_}; }
 
     void advance(difference_type off) {
-      _base += off;
-      _index += 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
     bool equal_to(indexed_iterator const & other) const {
-      return _base == other._base;
+      return base_ == other.base_;
     }
     difference_type distance_to(indexed_iterator const & other) const {
-      return other._base - _base;
+      return other.base_ - base_;
     }
 
   private:
     template <typename O> friend class indexed_iterator;
-    It _base;
-    size_t _index{0};
+    It base_;
+    size_t index_{0};
   };
+
+  template <typename It> indexed_iterator(It) -> indexed_iterator<It>;
+  template <typename It> indexed_iterator(It, size_t) -> indexed_iterator<It>;
 }
 
 MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::indexed_iterator);

+ 6 - 0
include/iterator/join_iterator.hpp

@@ -71,6 +71,12 @@ namespace iterator {
     end_aware_iterator<join_iter> joiner_;
     end_aware_iterator<iter_type> iterator_;
   };
+
+  template <typename JI>
+  joining_iterator(end_aware_iterator<JI>) -> joining_iterator<JI>;
+  template <typename JI, typename IT>
+  joining_iterator(end_aware_iterator<JI>, end_aware_iterator<IT>)
+      -> joining_iterator<JI>;
 }
 
 MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::joining_iterator);

+ 2 - 0
include/iterator/unkeyed_iterator.hpp

@@ -35,6 +35,8 @@ namespace iterator {
       return std::get<index>(*this->impl());
     }
   };
+
+  template <typename It> unkeyed_iterator(It) -> unkeyed_iterator<It>;
 }
 
 MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::unkeyed_iterator);

+ 0 - 5
include/iterator/zip_iterator.hpp

@@ -71,8 +71,3 @@ struct std::iterator_traits<::iterator::zip_iterator<T...>>
   using iterator_category =
       common_type_t<typename iterator_traits<T>::iterator_category...>;
 };
-
-template <typename... Is>
-iterator::zip_iterator<Is...> make_zip_iterator(Is &&... iters) {
-  return {std::forward<Is>(iters)...};
-}

+ 7 - 5
test/filter_iterator_test.cxx

@@ -4,10 +4,12 @@
 
 #include "xcode_gtest_helper.h"
 
+using iterator::filter_iterator;
+
 TEST(FilterIteratorTest, CanPerformSkipsOnData) {
   std::vector<int> const data = {1, 2, 3, 4, 5};
   auto pred = [](int i) { return i % 2 == 0; };
-  auto it = make_filter_iterator(pred, data);
+  filter_iterator it(pred, data);
   decltype(it) end = {};
   EXPECT_THAT(std::distance(it, end), 2);
   EXPECT_THAT(*it++, 2);
@@ -18,7 +20,7 @@ TEST(FilterIteratorTest, CanPerformSkipsOnData) {
 TEST(FilterIteratorTest, MutatingContainerDoesNotMoveIterator) {
   std::vector<int> data = {1, 2, 3, 4, 5};
   auto pred = [](int i) { return i % 2 == 0; };
-  auto it = make_filter_iterator(pred, data);
+  filter_iterator it(pred, data);
   decltype(it) end = {};
   EXPECT_THAT(std::distance(it, end), 2);
   *it = 1;
@@ -29,7 +31,7 @@ TEST(FilterIteratorTest, MutatingContainerDoesNotMoveIterator) {
 TEST(FilterIteratorTest, CanConstructFilterFromSubRange) {
   std::vector<int> data = {1, 2, 3, 4, 5};
   auto pred = [](int i) { return i % 2 == 0; };
-  auto it = make_filter_iterator(pred, data.begin(), data.begin() + 3);
+  filter_iterator it(pred, data.begin(), data.begin() + 3);
   decltype(it) end = {};
   EXPECT_THAT(std::distance(it, end), 1);
 }
@@ -37,7 +39,7 @@ TEST(FilterIteratorTest, CanConstructFilterFromSubRange) {
 TEST(FilterIteratorTest, IfNonMatchThenStartIsEnd) {
   std::vector<int> const data = {1, 3, 5};
   auto pred = [](int i) { return i % 2 == 0; };
-  auto it = make_filter_iterator(pred, data);
+  filter_iterator it(pred, data);
   decltype(it) end = {};
   EXPECT_THAT(it, end);
 }
@@ -45,7 +47,7 @@ TEST(FilterIteratorTest, IfNonMatchThenStartIsEnd) {
 TEST(FilterIteratorTest, IncrementOnEndIsUnsafe) {
   std::vector<int> const data = {1, 2, 3, 4, 5};
   auto pred = [](int i) { return i % 2 == 0; };
-  auto it = make_filter_iterator(pred, data);
+  filter_iterator it(pred, data);
   decltype(it) end = {};
   ++ ++it;
   EXPECT_THAT(it, end);

+ 36 - 28
test/indexed_iterator_test.cxx

@@ -7,40 +7,47 @@
 
 #include "iterator/end_aware_iterator.hpp"
 
-using idx_iterator = iterator::indexed_iterator<std::vector<int>::iterator>;
+using iterator::end_aware_iterator;
+using iterator::indexed_iterator;
+
+using testing::Ne;
 
 // TODO: This ought to be implemented as a compiles-test
 TEST(IndexedIteratorTest, CanCastCompatibleIterators) {
   std::vector<int> v{1, 2, 3, 4, 5};
-  idx_iterator eai(v.begin());
+  indexed_iterator eai(v.begin());
   ::iterator::indexed_iterator<std::vector<int>::const_iterator>{eai};
 }
 
 TEST(IndexedIteratorTest, CanLieAboutIndex) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  idx_iterator it(vec.begin(), 3);
+  indexed_iterator it(vec.begin(), 3);
   EXPECT_THAT(it->first, 3);
 }
 
 TEST(IndexedIteratorTest, FakeIndexDoesntEffectEqualityCheck) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  EXPECT_THAT(idx_iterator(vec.begin()), idx_iterator(vec.begin(), 3));
-  EXPECT_THAT(idx_iterator(vec.begin()) + 3,
-              testing::Ne(idx_iterator(vec.begin(), 3)));
+  EXPECT_THAT(indexed_iterator(vec.begin()), indexed_iterator(vec.begin(), 3));
+  EXPECT_THAT(indexed_iterator(vec.begin()) + 3,
+              testing::Ne(indexed_iterator(vec.begin(), 3)));
+}
+
+TEST(IndexedIteratorTest, DoesNotTrackByIndex) {
+  std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
+  indexed_iterator end(vec.end());
+  EXPECT_THAT(decltype(end){}, Ne(end));
 }
 
-TEST(IndexedIteratorTest, IffBaseIteratorEmptyIsEndThenEmptyIsEnd) {
+TEST(IndexedIteratorTest, IteratorPropagatesAtEnd) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  EXPECT_THAT(idx_iterator(), testing::Ne(idx_iterator(vec.end())));
-  iterator::end_aware_iterator<decltype(vec.end())> end(vec.end());
-  EXPECT_THAT(iterator::indexed_iterator<decltype(end)>(),
-              iterator::indexed_iterator<decltype(end)>(end));
+  indexed_iterator end(end_aware_iterator(vec.end()));
+  EXPECT_THAT(decltype(end){}, end);
 }
 
 TEST(IndexedIteratorTest, CanCompareIteratorOrder) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  idx_iterator const begin(vec.begin());
-  idx_iterator const it = begin + 3;
+  indexed_iterator const begin(vec.begin());
+  indexed_iterator const it = begin + 3;
   EXPECT_THAT(begin, testing::Lt(it));
   EXPECT_THAT(begin, testing::Le(it));
   EXPECT_THAT(it, testing::Le(it));
@@ -51,7 +58,7 @@ TEST(IndexedIteratorTest, CanCompareIteratorOrder) {
 
 TEST(IndexedIteratorTest, PreIncrementAdvancesIterator) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  idx_iterator it(vec.begin() + 1);
+  indexed_iterator it(vec.begin() + 1);
   EXPECT_THAT(it->second, 3);
   EXPECT_THAT((++it)->second, 2);
   EXPECT_THAT(it->second, 2);
@@ -59,7 +66,7 @@ TEST(IndexedIteratorTest, PreIncrementAdvancesIterator) {
 
 TEST(IndexedIteratorTest, PostIncrementReturnsCopyOfPrev) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  idx_iterator it(vec.begin() + 1);
+  indexed_iterator it(vec.begin() + 1);
   EXPECT_THAT(it->second, 3);
   EXPECT_THAT((it++)->second, 3);
   EXPECT_THAT(it->second, 2);
@@ -67,7 +74,7 @@ TEST(IndexedIteratorTest, PostIncrementReturnsCopyOfPrev) {
 
 TEST(IndexedIteratorTest, PreDecrementAdvancesIterator) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  idx_iterator it(vec.begin() + 1);
+  indexed_iterator it(vec.begin() + 1);
   EXPECT_THAT(it->second, 3);
   EXPECT_THAT((--it)->second, 5);
   EXPECT_THAT(it->second, 5);
@@ -75,7 +82,7 @@ TEST(IndexedIteratorTest, PreDecrementAdvancesIterator) {
 
 TEST(IndexedIteratorTest, PostDecrementReturnsCopyOfPrev) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  idx_iterator it(vec.begin() + 1);
+  indexed_iterator it(vec.begin() + 1);
   EXPECT_THAT(it->second, 3);
   EXPECT_THAT((it--)->second, 3);
   EXPECT_THAT(it->second, 5);
@@ -83,24 +90,25 @@ TEST(IndexedIteratorTest, PostDecrementReturnsCopyOfPrev) {
 
 TEST(IndexedIteratorTest, CanWalkNStepsForward) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  idx_iterator const begin(vec.begin());
-  idx_iterator it = begin;
+  indexed_iterator const begin(vec.begin());
+  indexed_iterator it = begin;
   it += 4;
   EXPECT_THAT(std::distance(begin, it), 4);
 }
 
 TEST(IndexedIteratorTest, CanWalkNStepsBackwards) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  idx_iterator const end(vec.end());
-  idx_iterator it = end;
+  indexed_iterator const end(vec.end());
+  indexed_iterator it = end;
   it -= 4;
   EXPECT_THAT(std::distance(it, end), 4);
 }
 
 TEST(IndexedIteratorTest, RandomAccessIsPassthrough) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  EXPECT_THAT(idx_iterator(vec.begin()) + 4, idx_iterator(vec.begin() + 4));
-  EXPECT_THAT(idx_iterator(vec.end()) - 4, idx_iterator(vec.end() - 4));
+  EXPECT_THAT(indexed_iterator(vec.begin()) + 4,
+              indexed_iterator(vec.begin() + 4));
+  EXPECT_THAT(indexed_iterator(vec.end()) - 4, indexed_iterator(vec.end() - 4));
 }
 
 TEST(IndexedIteratorTest, TreatsVectorIteratorAsPairIdxValue) {
@@ -108,8 +116,8 @@ TEST(IndexedIteratorTest, TreatsVectorIteratorAsPairIdxValue) {
   std::vector<std::pair<int, int>> const expected{
       {0, 5}, {1, 3}, {2, 2}, {3, 8}, {4, 9}, {5, 11}, {6, 2}, {7, 4}};
 
-  std::vector<std::pair<int, int>> const result(idx_iterator(vec.begin()),
-                                                idx_iterator(vec.end()));
+  std::vector<std::pair<int, int>> const result(indexed_iterator(vec.begin()),
+                                                indexed_iterator(vec.end()));
   EXPECT_THAT(result, expected);
 }
 
@@ -118,13 +126,13 @@ TEST(IndexedIteratorTest, TreatsVectorIteratorAsMapIdxToValue) {
   std::map<int, int> const expected{{0, 5}, {1, 3},  {2, 2}, {3, 8},
                                     {4, 9}, {5, 11}, {6, 2}, {7, 4}};
 
-  std::map<int, int> const result(idx_iterator(vec.begin()),
-                                  idx_iterator(vec.end()));
+  std::map<int, int> const result(indexed_iterator(vec.begin()),
+                                  indexed_iterator(vec.end()));
   EXPECT_THAT(result, expected);
 }
 
 TEST(IndexedIteratorTest, CanMutatePointedToData) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  idx_iterator(vec.begin() + 4, 4)->second = -1;
+  indexed_iterator(vec.begin() + 4, 4)->second = -1;
   EXPECT_THAT(vec[4], -1);
 }

+ 22 - 18
test/join_iterator_test.cxx

@@ -4,57 +4,60 @@
 
 #include "xcode_gtest_helper.h"
 
-using join_iterator =
-    iterator::joining_iterator<std::vector<std::vector<int>>::iterator>;
+using iterator::end_aware_iterator;
+using iterator::joining_iterator;
+
+using testing::Ne;
 
 TEST(JoinIteratorTest, FirstDereferencedElemIsTheFirstInTheChain) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  EXPECT_THAT(*join_iterator(make_end_aware_iterator(mv)), mv[0][0]);
+  EXPECT_THAT(*joining_iterator(make_end_aware_iterator(mv)), mv[0][0]);
 }
 
 TEST(JoinIteratorTest, HoldsReferenceToContainedElements) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  EXPECT_THAT(join_iterator(make_end_aware_iterator(mv)).operator->(),
+  EXPECT_THAT(joining_iterator(make_end_aware_iterator(mv)).operator->(),
               &mv[0][0]);
 }
 
 TEST(JoinIteratorTest, DefaultCtorIsEnd) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  EXPECT_THAT(join_iterator(make_end_aware_iterator(mv)),
-              testing::Ne(join_iterator()));
+  joining_iterator it(make_end_aware_iterator(mv));
+  EXPECT_THAT(it, Ne(decltype(it)()));
   mv.clear();
-  EXPECT_THAT(join_iterator(make_end_aware_iterator(mv)), join_iterator());
+  EXPECT_THAT(joining_iterator(make_end_aware_iterator(mv)), decltype(it)());
 }
 
 // TODO: This ought to be implemented as a compiles-test
 TEST(JoinIteratorTest, CanCastCompatibleIterators) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  join_iterator it(make_end_aware_iterator(mv));
+  joining_iterator it(make_end_aware_iterator(mv));
   iterator::joining_iterator<decltype(mv)::const_iterator>{it};
 }
 
 TEST(JoinIteratorTest, CanAccessInternalIterator) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
   auto eai = make_end_aware_iterator(mv);
-  join_iterator it(eai);
+  joining_iterator it(eai);
   EXPECT_THAT(it.join_iterator(), eai);
 }
 
 TEST(JoinIteratorTest, CanAccessChildIterator) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  join_iterator it(make_end_aware_iterator(mv));
+  joining_iterator it(make_end_aware_iterator(mv));
   EXPECT_THAT(it.element_iterator(), make_end_aware_iterator(mv[0]));
 }
 
 TEST(JoinIteratorTest, EmptyConstructorEqualsEnd) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  join_iterator it({mv.end(), mv.end()}, {mv.back().end(), mv.back().end()});
-  EXPECT_THAT(it, join_iterator());
+  joining_iterator it(end_aware_iterator(mv.end()),
+                      end_aware_iterator(mv.back().end()));
+  EXPECT_THAT(it, decltype(it)());
 }
 
 TEST(JoinIteratorTest, PreIncrementAdvancesIterator) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  join_iterator it(make_end_aware_iterator(mv));
+  joining_iterator it(make_end_aware_iterator(mv));
   EXPECT_THAT(*it, 1);
   EXPECT_THAT(*++it, 2);
   EXPECT_THAT(*it, 2);
@@ -62,7 +65,7 @@ TEST(JoinIteratorTest, PreIncrementAdvancesIterator) {
 
 TEST(JoinIteratorTest, PostIncrementReturnsCopyOfPrev) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  join_iterator it(make_end_aware_iterator(mv));
+  joining_iterator it(make_end_aware_iterator(mv));
   EXPECT_THAT(*it, 1);
   EXPECT_THAT(*it++, 1);
   EXPECT_THAT(*it, 2);
@@ -70,22 +73,23 @@ TEST(JoinIteratorTest, PostIncrementReturnsCopyOfPrev) {
 
 TEST(JoinIteratorTest, MovesFromListToListWhenReachingEnd) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  join_iterator it(make_end_aware_iterator(mv));
+  joining_iterator it(make_end_aware_iterator(mv));
   std::advance(it, 3);
   EXPECT_THAT(*++it, mv[1][0]);
 }
 
 TEST(JoinIteratorTest, SkipsOverEmptyElements) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {}, {4, 5, 6}};
-  join_iterator it(make_end_aware_iterator(mv));
+  joining_iterator it(make_end_aware_iterator(mv));
   std::advance(it, 3);
   EXPECT_THAT(*++it, mv[2][0]);
 }
 
 TEST(JoinIteratorTest, IncrementEndIsUnsafe) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  join_iterator it({mv.end(), mv.end()}, {mv.back().end(), mv.back().end()});
-  join_iterator const cp = it;
+  joining_iterator it(end_aware_iterator(mv.end()),
+                      end_aware_iterator(mv.back().end()));
+  joining_iterator const cp = it;
   ++it;
   EXPECT_NE(it, cp);
 }

+ 25 - 17
test/unkeyed_iterator_test.cxx

@@ -7,26 +7,29 @@
 
 #include "iterator/end_aware_iterator.hpp"
 
-using value_iterator = iterator::unkeyed_iterator<std::map<int, int>::iterator>;
+using iterator::end_aware_iterator;
+using iterator::unkeyed_iterator;
+
+using testing::Ne;
 
 TEST(UnkeyedIteratorTest, IteratorOnlyReturnsValues) {
   std::map<int, int> map{{1, 2}, {2, 3}};
   std::vector<int> const expected{2, 3};
-  std::vector<int> const result{value_iterator{map.begin()},
-                                value_iterator{map.end()}};
+  std::vector<int> const result{unkeyed_iterator{map.begin()},
+                                unkeyed_iterator{map.end()}};
   EXPECT_THAT(result, expected);
 }
 
 TEST(UnkeyedIteratorTest, CanModifyIteratedCollectionValues) {
   std::map<int, int> map{{1, 2}, {2, 3}};
-  value_iterator uit{map.begin()};
+  unkeyed_iterator uit{map.begin()};
   *uit = 4;
   EXPECT_THAT(map[1], 4);
 }
 
 TEST(UnkeyedIteratorTest, PreIncrementAdvancesIterator) {
   std::map<int, int> map{{1, 2}, {2, 3}};
-  value_iterator it(map.begin());
+  unkeyed_iterator it(map.begin());
   EXPECT_THAT(*it, 2);
   EXPECT_THAT(*++it, 3);
   EXPECT_THAT(*it, 3);
@@ -34,7 +37,7 @@ TEST(UnkeyedIteratorTest, PreIncrementAdvancesIterator) {
 
 TEST(UnkeyedIteratorTest, PostIncrementReturnsCopyOfPrev) {
   std::map<int, int> map{{1, 2}, {2, 3}};
-  value_iterator it(map.begin());
+  unkeyed_iterator it(map.begin());
   EXPECT_THAT(*it, 2);
   EXPECT_THAT(*it++, 2);
   EXPECT_THAT(*it, 3);
@@ -42,7 +45,7 @@ TEST(UnkeyedIteratorTest, PostIncrementReturnsCopyOfPrev) {
 
 TEST(UnkeyedIteratorTest, PreDecrementAdvancesIterator) {
   std::map<int, int> map{{1, 2}, {2, 3}};
-  value_iterator it(++map.begin());
+  unkeyed_iterator it(++map.begin());
   EXPECT_THAT(*it, 3);
   EXPECT_THAT(*--it, 2);
   EXPECT_THAT(*it, 2);
@@ -50,7 +53,7 @@ TEST(UnkeyedIteratorTest, PreDecrementAdvancesIterator) {
 
 TEST(UnkeyedIteratorTest, PostDecrementReturnsCopyOfPrev) {
   std::map<int, int> map{{1, 2}, {2, 3}};
-  value_iterator it(++map.begin());
+  unkeyed_iterator it(++map.begin());
   EXPECT_THAT(*it, 3);
   EXPECT_THAT(*it--, 3);
   EXPECT_THAT(*it, 2);
@@ -58,20 +61,25 @@ TEST(UnkeyedIteratorTest, PostDecrementReturnsCopyOfPrev) {
 
 TEST(UnkeyedIteratorTest, EqualityIsPassthrough) {
   std::map<int, int> map{{1, 2}, {2, 3}};
-  EXPECT_THAT(++value_iterator(map.begin()), value_iterator(++map.begin()));
-  EXPECT_THAT(value_iterator(map.begin()),
-              testing::Ne(value_iterator(++map.begin())));
+  EXPECT_THAT(++unkeyed_iterator(map.begin()), unkeyed_iterator(++map.begin()));
+  EXPECT_THAT(unkeyed_iterator(map.begin()),
+              Ne(unkeyed_iterator(++map.begin())));
+}
+
+TEST(UnkeyedIteratorTest, DoesNotGenerateAtEnd) {
+  std::map<int, int> map{{1, 2}, {2, 3}};
+  unkeyed_iterator end(map.end());
+  EXPECT_THAT(decltype(end)(), Ne(end));
 }
 
-TEST(UnkeyedIteratorTest, IffBaseIteratorEmptyIsEndThenEmptyIsEnd) {
+TEST(UnkeyedIteratorTest, PropagatesAtEnd) {
   std::map<int, int> map{{1, 2}, {2, 3}};
-  EXPECT_THAT(value_iterator(), testing::Ne(value_iterator(map.end())));
-  iterator::end_aware_iterator<decltype(map.end())> end(map.end());
-  EXPECT_THAT(iterator::unkeyed_iterator<decltype(end)>(),
-              iterator::unkeyed_iterator<decltype(end)>(end));
+  unkeyed_iterator end(end_aware_iterator(map.end()));
+  EXPECT_THAT(decltype(end)(), end);
 }
 
 TEST(UnkeyedIteratorTest, CanPointToObject) {
   std::map<int, int> map{{1, 2}, {2, 3}};
-  EXPECT_THAT(value_iterator(map.begin()).operator->(), &(map.begin()->second));
+  EXPECT_THAT(unkeyed_iterator(map.begin()).operator->(),
+              &(map.begin()->second));
 }

+ 16 - 14
test/zip_iterator_test.cxx

@@ -14,31 +14,33 @@
 
 #include "xcode_gtest_helper.h"
 
+using iterator::zip_iterator;
+
 TEST(ZipIteratorTest, CategoryIsMostRestrictiveOfTypes) {
   std::vector<int> rnd{1, 2, 3};
   std::vector<std::string> ss{"A", "B", "C"};
   std::list<int> bid{1, 2, 3};
   std::forward_list<int> fwd{1, 2, 3};
   {
-    auto zit = make_zip_iterator(rnd.begin(), ss.begin());
+    zip_iterator zit(rnd.begin(), ss.begin());
     testing::StaticAssertTypeEq<
         std::iterator_traits<decltype(zit)>::iterator_category,
         std::random_access_iterator_tag>();
   }
   {
-    auto zit = make_zip_iterator(rnd.begin(), bid.begin());
+    zip_iterator zit(rnd.begin(), bid.begin());
     testing::StaticAssertTypeEq<
         std::iterator_traits<decltype(zit)>::iterator_category,
         std::bidirectional_iterator_tag>();
   }
   {
-    auto zit = make_zip_iterator(rnd.begin(), fwd.begin());
+    zip_iterator zit(rnd.begin(), fwd.begin());
     testing::StaticAssertTypeEq<
         std::iterator_traits<decltype(zit)>::iterator_category,
         std::forward_iterator_tag>();
   }
   {
-    auto zit = make_zip_iterator(bid.begin(), fwd.begin());
+    zip_iterator zit(bid.begin(), fwd.begin());
     testing::StaticAssertTypeEq<
         std::iterator_traits<decltype(zit)>::iterator_category,
         std::forward_iterator_tag>();
@@ -55,7 +57,7 @@ TEST(ZipIteratorTest, CategoryIsMostRestrictiveOfTypes) {
 TEST(ZipIteratorTest, CanCombineParallelObjects) {
   std::vector<int> is{1, 2, 3};
   std::vector<std::string> ss{"A", "B", "C"};
-  auto zit = make_zip_iterator(is.begin(), ss.begin());
+  zip_iterator zit(is.begin(), ss.begin());
   EXPECT_THAT(std::get<0>(*zit), 1);
   EXPECT_THAT(std::get<1>(*zit), "A");
 }
@@ -63,7 +65,7 @@ TEST(ZipIteratorTest, CanCombineParallelObjects) {
 TEST(ZipIteratorTest, AdvancingMovesAllElements) {
   std::vector<int> is{1, 2, 3};
   std::vector<std::string> ss{"A", "B", "C"};
-  auto zit = make_zip_iterator(is.begin(), ss.begin());
+  zip_iterator zit(is.begin(), ss.begin());
   zit++;
   EXPECT_THAT(std::get<0>(*zit), 2);
   EXPECT_THAT(std::get<1>(*zit), "B");
@@ -72,7 +74,7 @@ TEST(ZipIteratorTest, AdvancingMovesAllElements) {
 TEST(ZipIteratorTest, CanDecrement) {
   std::vector<int> is{1, 2, 3};
   std::vector<std::string> ss{"A", "B", "C"};
-  auto zit = make_zip_iterator(is.begin(), ss.begin());
+  zip_iterator zit(is.begin(), ss.begin());
   ++zit;
   zit--;
   EXPECT_THAT(std::get<0>(*zit), 1);
@@ -82,7 +84,7 @@ TEST(ZipIteratorTest, CanDecrement) {
 TEST(ZipIteratorTest, CanMoveByAnyAmount) {
   std::vector<int> is{1, 2, 3};
   std::vector<std::string> ss{"A", "B", "C"};
-  auto zit = make_zip_iterator(is.begin(), ss.begin());
+  zip_iterator zit(is.begin(), ss.begin());
   zit = 2 + zit;
   EXPECT_THAT(std::get<0>(*zit), 3);
   EXPECT_THAT(std::get<1>(*zit), "C");
@@ -94,15 +96,15 @@ TEST(ZipIteratorTest, CanMoveByAnyAmount) {
 TEST(ZipIteratorTest, CanMarkDistance) {
   std::vector<int> is{1, 2, 3};
   std::vector<std::string> ss{"A", "B", "C"};
-  auto zit = make_zip_iterator(is.begin(), ss.begin());
-  auto zend = make_zip_iterator(is.end(), ss.end());
+  zip_iterator zit(is.begin(), ss.begin());
+  zip_iterator zend(is.end(), ss.end());
   EXPECT_THAT(zend - zit, 3);
 }
 
 TEST(ZipIteratorTest, CanRandomAccess) {
   std::vector<int> is{1, 2, 3};
   std::vector<std::string> ss{"A", "B", "C"};
-  auto zit = make_zip_iterator(is.begin(), ss.begin());
+  zip_iterator zit(is.begin(), ss.begin());
   EXPECT_THAT(std::get<0>(zit[1]), 2);
   EXPECT_THAT(std::get<1>(zit[1]), "B");
 }
@@ -110,9 +112,9 @@ TEST(ZipIteratorTest, CanRandomAccess) {
 TEST(ZipIteratorTest, CanCompareIterators) {
   std::vector<int> is{1, 2, 3};
   std::vector<std::string> ss{"A", "B", "C"};
-  auto const zit = make_zip_iterator(is.begin(), ss.begin());
-  auto const zend = make_zip_iterator(is.end(), ss.end());
-  EXPECT_THAT(zit, testing::Eq(make_zip_iterator(is.begin(), ss.begin())));
+  zip_iterator const zit(is.begin(), ss.begin());
+  zip_iterator const zend(is.end(), ss.end());
+  EXPECT_THAT(zit, testing::Eq(zip_iterator(is.begin(), ss.begin())));
   EXPECT_THAT(zit, testing::Ne(zend));
   EXPECT_THAT(zit, testing::Lt(zend));
   EXPECT_THAT(zit, testing::Le(zend));