Sam Jaffe 2 роки тому
батько
коміт
20176764a0

+ 1 - 1
include/iterator/detail/recursive_traits.h

@@ -2,7 +2,7 @@
 
 #include <iterator>
 
-#include "traits.h"
+#include <iterator/detail/traits.h>
 
 namespace iterator::recursive {
 // Type deduction guides for constructing recursive iterators.

+ 8 - 0
include/iterator/detail/traits.h

@@ -3,6 +3,8 @@
 #define _val(type) std::declval<type>()
 #define exists(expr) void_t<decltype(expr)>
 
+#include <iterator/iterator_fwd.hpp>
+
 namespace iterator::detail {
 template <typename> using void_t = void;
 
@@ -25,4 +27,10 @@ struct value_type_helper<T, void_t<typename T::value_type>> {
 
 template <typename T> using value_type = typename value_type_helper<T>::type;
 template <typename T> using reference = typename reference_helper<T>::type;
+
+template <typename C, typename = void> struct is_container : std::false_type {};
+template <typename C>
+struct is_container<C, void_t<iter<C>>> : std::true_type {};
+
+template <typename C> constexpr bool is_container_v = is_container<C>{};
 }

+ 11 - 13
include/iterator/end_aware_iterator.hpp

@@ -7,9 +7,9 @@
 
 #pragma once
 
-#include "iterator_fwd.hpp"
-
-#include "facade.h"
+#include <iterator/detail/traits.h>
+#include <iterator/facade.h>
+#include <iterator/iterator_fwd.hpp>
 
 namespace iterator {
 /**
@@ -28,7 +28,13 @@ public:
 public:
   end_aware_iterator() = default;
   end_aware_iterator(It it, It end) : curr_(it), end_(end) {}
-  end_aware_iterator(It end) : curr_(end), end_(end) {}
+
+  template <typename C, typename = std::enable_if_t<detail::is_container_v<C>>>
+  end_aware_iterator(C && container)
+      : curr_(std::begin(container)), end_(std::end(container)) {
+    static_assert(std::is_reference_v<C>,
+                  "Cannot access iterator of a temporary");
+  }
 
   template <typename I>
   end_aware_iterator(end_aware_iterator<I> const & other)
@@ -47,16 +53,8 @@ private:
   It curr_, end_;
 };
 
-template <typename It> end_aware_iterator(It) -> end_aware_iterator<It>;
+template <typename C> end_aware_iterator(C &&) -> end_aware_iterator<iter<C>>;
 template <typename It> end_aware_iterator(It, It) -> end_aware_iterator<It>;
 }
 
 MAKE_ITERATOR_FACADE_TYPEDEFS_T(::iterator::end_aware_iterator);
-
-template <typename C> auto make_end_aware_iterator(C & collect) {
-  return iterator::end_aware_iterator(std::begin(collect), std::end(collect));
-}
-
-template <typename C> auto make_end_aware_iterator(C const & collect) {
-  return iterator::end_aware_iterator(std::begin(collect), std::end(collect));
-}

+ 2 - 2
include/iterator/facade.h

@@ -3,8 +3,8 @@
 #include <iterator>
 #include <type_traits>
 
-#include "detail/arrow_proxy.h"
-#include "detail/traits.h"
+#include <iterator/detail/arrow_proxy.h>
+#include <iterator/detail/traits.h>
 
 namespace iterator::detail {
 template <typename, typename = void> struct has_equal_to : std::false_type {};

+ 5 - 9
include/iterator/filter_iterator.hpp

@@ -9,20 +9,16 @@
 
 #include <functional>
 
-#include "end_aware_iterator.hpp"
-#include "facade.h"
-
-template <typename C> using iter = decltype(std::begin(std::declval<C>()));
+#include <iterator/detail/traits.h>
+#include <iterator/end_aware_iterator.hpp>
+#include <iterator/facade.h>
+#include <iterator/iterator_fwd.hpp>
 
 namespace iterator {
 template <typename Iter>
 class filter_iterator : public facade<filter_iterator<Iter>> {
 public:
-  using super = end_aware_iterator<Iter>;
-  using reference = decltype(*std::declval<super>());
-  using value_type = std::remove_cv_t<std::remove_reference_t<reference>>;
-  using difference_type = std::ptrdiff_t;
-  using iterator_category = std::forward_iterator_tag;
+  using value_type = std::decay_t<decltype(*std::declval<Iter>())>;
   using predicate_t = std::function<bool(value_type const &)>;
 
 public:

+ 2 - 1
include/iterator/indexed_iterator.hpp

@@ -9,7 +9,8 @@
 
 #include <iterator>
 
-#include "iterator/facade.h"
+#include <iterator/facade.h>
+#include <iterator/iterator_fwd.hpp>
 
 namespace iterator {
 template <typename It>

+ 14 - 6
include/iterator/iterator_fwd.hpp

@@ -8,21 +8,29 @@
 #pragma once
 
 #include <cstdlib>
+#include <iterator>
 
 namespace iterator::recursive {
 struct unbounded;
 template <size_t N, size_t I = 1> struct bounded;
-template <typename Iter, typename = unbounded> class rimpl;
+template <typename, typename = unbounded> class rimpl;
 }
 
 namespace iterator {
-template <typename Iter> class end_aware_iterator;
-template <typename Iter> class filter_iterator;
-template <typename Iter> class joining_iterator;
-template <typename Iter> class unkeyed_iterator;
-template <typename... Iters> class zip_iterator;
+template <typename> class end_aware_iterator;
+template <typename> class filter_iterator;
+template <typename> class joining_iterator;
+template <typename> class unkeyed_iterator;
+template <typename...> class zip_iterator;
 
 template <typename Iter> using recursive_iterator = recursive::rimpl<Iter>;
 template <typename Iter, std::size_t N>
 using recursive_iterator_n = recursive::rimpl<Iter, recursive::bounded<N>>;
+
+template <typename> class facade;
+template <typename Iter, typename,
+          typename = typename std::iterator_traits<Iter>::iterator_category>
+class proxy;
+
+template <typename C> using iter = decltype(std::begin(std::declval<C>()));
 }

+ 11 - 5
include/iterator/join_iterator.hpp

@@ -7,12 +7,12 @@
 
 #pragma once
 
-#include "end_aware_iterator.hpp"
-
 #include <iterator>
 #include <utility>
 
-#include "facade.h"
+#include <iterator/end_aware_iterator.hpp>
+#include <iterator/facade.h>
+#include <iterator/iterator_fwd.hpp>
 
 namespace iterator {
 template <typename MetaIterator>
@@ -36,8 +36,13 @@ public:
   joining_iterator(joining_iterator<I> const & other)
       : joiner_(other.join_iterator()), iterator_(other.element_iterator()) {}
 
+  template <typename C, typename = std::enable_if_t<detail::is_container_v<C>>>
+  joining_iterator(C && container)
+      : joining_iterator(end_aware_iterator(std::forward<C>(container))) {}
+
   joining_iterator(end_aware_iterator<join_iter> join)
       : joining_iterator(join, {}, true) {}
+
   joining_iterator(end_aware_iterator<join_iter> join,
                    end_aware_iterator<iter_type> elem, bool update = false)
       : joiner_(join), iterator_(elem) {
@@ -62,16 +67,17 @@ public:
 
 private:
   void update_iterator() {
-    while (!joiner_.at_end() && make_end_aware_iterator(*joiner_).at_end()) {
+    while (!joiner_.at_end() && end_aware_iterator(*joiner_).at_end()) {
       ++joiner_;
     }
-    if (!joiner_.at_end()) { iterator_ = make_end_aware_iterator(*joiner_); }
+    if (!joiner_.at_end()) { iterator_ = end_aware_iterator(*joiner_); }
   }
 
   end_aware_iterator<join_iter> joiner_;
   end_aware_iterator<iter_type> iterator_;
 };
 
+template <typename C> joining_iterator(C &&) -> joining_iterator<iter<C>>;
 template <typename JI>
 joining_iterator(end_aware_iterator<JI>) -> joining_iterator<JI>;
 template <typename JI, typename IT>

+ 2 - 8
include/iterator/proxy.h

@@ -1,15 +1,9 @@
 #pragma once
 
-#include <iterator>
-
-#include "facade.h"
+#include <iterator/facade.h>
+#include <iterator/iterator_fwd.hpp>
 
 namespace iterator {
-template <typename Iter, typename Self,
-          typename Category =
-              typename std::iterator_traits<Iter>::iterator_category>
-class proxy;
-
 template <typename Iter, typename Self>
 class proxy<Iter, Self, std::input_iterator_tag> : public facade<Self> {
 public:

+ 9 - 29
include/iterator/recursive_iterator.hpp

@@ -7,15 +7,14 @@
 
 #pragma once
 
-#include "iterator_fwd.hpp"
-
 #include <string>
 #include <tuple>
 #include <utility>
 
-#include "detail/recursive_traits.h"
-#include "end_aware_iterator.hpp"
-#include "facade.h"
+#include <iterator/detail/recursive_traits.h>
+#include <iterator/end_aware_iterator.hpp>
+#include <iterator/facade.h>
+#include <iterator/iterator_fwd.hpp>
 
 namespace iterator::recursive {
 template <size_t N, size_t I> struct bounded {
@@ -157,7 +156,7 @@ private:
   }
 
   template <size_t I, typename C> void assign(C && collection) {
-    assign<I>(make_end_aware_iterator(std::forward<C>(collection)));
+    assign<I>(end_aware_iterator(std::forward<C>(collection)));
   }
 
   template <size_t I, typename K, typename V>
@@ -186,30 +185,11 @@ auto get(::iterator::recursive_iterator_n<It, N> const & iter) {
 }
 }
 
-template <typename C>
-auto make_recursive_iterator(C & collect)
-    -> iterator::recursive_iterator<decltype(std::begin(collect))> {
-  return iterator::recursive_iterator<decltype(std::begin(collect))>{
-      make_end_aware_iterator(collect)};
-}
-
-template <typename C>
-auto make_recursive_iterator(C const & collect)
-    -> iterator::recursive_iterator<decltype(std::begin(collect))> {
-  return iterator::recursive_iterator<decltype(std::begin(collect))>{
-      make_end_aware_iterator(collect)};
-}
-
-template <std::size_t Max, typename C>
-auto make_recursive_iterator(C & collect)
-    -> iterator::recursive_iterator_n<decltype(std::begin(collect)), Max> {
-  return iterator::recursive_iterator_n<decltype(std::begin(collect)), Max>{
-      make_end_aware_iterator(collect)};
+template <typename C> auto make_recursive_iterator(C && collect) {
+  return iterator::recursive_iterator<iterator::iter<C>>(collect);
 }
 
 template <std::size_t Max, typename C>
-auto make_recursive_iterator(C const & collect)
-    -> iterator::recursive_iterator_n<decltype(std::begin(collect)), Max> {
-  return iterator::recursive_iterator_n<decltype(std::begin(collect)), Max>{
-      make_end_aware_iterator(collect)};
+auto make_recursive_iterator(C && collect) {
+  return iterator::recursive_iterator_n<iterator::iter<C>, Max>(collect);
 }

+ 2 - 1
include/iterator/unkeyed_iterator.hpp

@@ -7,7 +7,8 @@
 
 #pragma once
 
-#include "proxy.h"
+#include <iterator/iterator_fwd.hpp>
+#include <iterator/proxy.h>
 
 namespace iterator {
 /**

+ 2 - 1
include/iterator/zip_iterator.hpp

@@ -3,7 +3,8 @@
 #include <iterator>
 #include <tuple>
 
-#include "facade.h"
+#include <iterator/facade.h>
+#include <iterator/iterator_fwd.hpp>
 
 namespace iterator::detail {
 template <typename Tuple, typename IS> class zip_iterator_impl;

+ 4 - 2
iterator.xcodeproj/project.pbxproj

@@ -439,7 +439,8 @@
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = macosx;
-				USER_HEADER_SEARCH_PATHS = include/;
+				SYSTEM_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
+				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
 			};
 			name = Debug;
 		};
@@ -488,7 +489,8 @@
 				MACOSX_DEPLOYMENT_TARGET = 10.10;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = macosx;
-				USER_HEADER_SEARCH_PATHS = include/;
+				SYSTEM_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
+				USER_HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/include";
 			};
 			name = Release;
 		};

+ 0 - 5
test/end_aware_iterator_test.cxx

@@ -34,11 +34,6 @@ TEST(EndAwareIteratorTest, CanTellYouThatItsReachedEnd) {
   EXPECT_TRUE(it.at_end());
 }
 
-TEST(EndAwareIteratorTest, SingleArgIsEnd) {
-  std::vector<int> v{1, 2, 3, 4, 5};
-  EXPECT_TRUE(end_aware_iterator(v.begin()).at_end());
-}
-
 TEST(EndAwareIteratorTest, EmptyIteratorIsEnd) {
   EXPECT_TRUE(end_aware_iterator().at_end());
 }

+ 1 - 1
test/indexed_iterator_test.cxx

@@ -40,7 +40,7 @@ TEST(IndexedIteratorTest, DoesNotTrackByIndex) {
 
 TEST(IndexedIteratorTest, IteratorPropagatesAtEnd) {
   std::vector<int> vec{5, 3, 2, 8, 9, 11, 2, 4};
-  indexed_iterator end(end_aware_iterator(vec.end()));
+  indexed_iterator end(end_aware_iterator(vec.end(), vec.end()));
   EXPECT_THAT(decltype(end){}, end);
 }
 

+ 16 - 17
test/join_iterator_test.cxx

@@ -11,53 +11,52 @@ using testing::Ne;
 
 TEST(JoinIteratorTest, FirstDereferencedElemIsTheFirstInTheChain) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  EXPECT_THAT(*joining_iterator(make_end_aware_iterator(mv)), mv[0][0]);
+  EXPECT_THAT(*joining_iterator(mv), mv[0][0]);
 }
 
 TEST(JoinIteratorTest, HoldsReferenceToContainedElements) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  EXPECT_THAT(joining_iterator(make_end_aware_iterator(mv)).operator->(),
-              &mv[0][0]);
+  EXPECT_THAT(joining_iterator(mv).operator->(), &mv[0][0]);
 }
 
 TEST(JoinIteratorTest, DefaultCtorIsEnd) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  joining_iterator it(make_end_aware_iterator(mv));
+  joining_iterator it(mv);
   EXPECT_THAT(it, Ne(decltype(it)()));
   mv.clear();
-  EXPECT_THAT(joining_iterator(make_end_aware_iterator(mv)), decltype(it)());
+  EXPECT_THAT(joining_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}};
-  joining_iterator it(make_end_aware_iterator(mv));
+  joining_iterator it(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);
+  auto eai = end_aware_iterator(mv);
   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}};
-  joining_iterator it(make_end_aware_iterator(mv));
-  EXPECT_THAT(it.element_iterator(), make_end_aware_iterator(mv[0]));
+  joining_iterator it(mv);
+  EXPECT_THAT(it.element_iterator(), end_aware_iterator(mv[0]));
 }
 
 TEST(JoinIteratorTest, EmptyConstructorEqualsEnd) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  joining_iterator it(end_aware_iterator(mv.end()),
-                      end_aware_iterator(mv.back().end()));
+  joining_iterator it(end_aware_iterator(mv.end(), mv.end()),
+                      end_aware_iterator(mv.back().end(), mv.back().end()));
   EXPECT_THAT(it, decltype(it)());
 }
 
 TEST(JoinIteratorTest, PreIncrementAdvancesIterator) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  joining_iterator it(make_end_aware_iterator(mv));
+  joining_iterator it(mv);
   EXPECT_THAT(*it, 1);
   EXPECT_THAT(*++it, 2);
   EXPECT_THAT(*it, 2);
@@ -65,7 +64,7 @@ TEST(JoinIteratorTest, PreIncrementAdvancesIterator) {
 
 TEST(JoinIteratorTest, PostIncrementReturnsCopyOfPrev) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  joining_iterator it(make_end_aware_iterator(mv));
+  joining_iterator it(mv);
   EXPECT_THAT(*it, 1);
   EXPECT_THAT(*it++, 1);
   EXPECT_THAT(*it, 2);
@@ -73,22 +72,22 @@ TEST(JoinIteratorTest, PostIncrementReturnsCopyOfPrev) {
 
 TEST(JoinIteratorTest, MovesFromListToListWhenReachingEnd) {
   std::vector<std::vector<int>> mv{{1, 2, 3}, {4, 5, 6}};
-  joining_iterator it(make_end_aware_iterator(mv));
+  joining_iterator it(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}};
-  joining_iterator it(make_end_aware_iterator(mv));
+  joining_iterator it(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}};
-  joining_iterator it(end_aware_iterator(mv.end()),
-                      end_aware_iterator(mv.back().end()));
+  joining_iterator it(end_aware_iterator(mv.end(), mv.end()),
+                      end_aware_iterator(mv.back().end(), mv.back().end()));
   joining_iterator const cp = it;
   ++it;
   EXPECT_NE(it, cp);

+ 7 - 5
test/recursive_iterator_accessors_test.cxx

@@ -7,6 +7,8 @@
 
 #include "xcode_gtest_helper.h"
 
+using iterator::end_aware_iterator;
+
 TEST(RecursiveIteratorTest, DoesNotUnwrapString) {
   std::vector<std::string> obj{"A", "B", "C", "D"};
   auto rit = make_recursive_iterator(obj);
@@ -65,9 +67,9 @@ TEST(RecursiveIteratorTest, CanAccessInternalIteratorsWithGet) {
       {2, {{{3, 3}, {4, 4}}}}    // 1 2-element map
   };
   auto rit = make_recursive_iterator(obj);
-  EXPECT_THAT(std::get<0>(rit), make_end_aware_iterator(obj));
-  EXPECT_THAT(std::get<1>(rit), make_end_aware_iterator(obj[1]));
-  EXPECT_THAT(std::get<2>(rit), make_end_aware_iterator(obj[1][0]));
+  EXPECT_THAT(std::get<0>(rit), end_aware_iterator(obj));
+  EXPECT_THAT(std::get<1>(rit), end_aware_iterator(obj[1]));
+  EXPECT_THAT(std::get<2>(rit), end_aware_iterator(obj[1][0]));
 }
 
 // TODO: This ought to be implemented as a compiles-test
@@ -114,8 +116,8 @@ TEST(BoundedRecursiveIteratorTest, CanAccessInternalIteratorsWithGet) {
       {2, {{{3, 3}, {4, 4}}}}    // 1 2-element map
   };
   auto rit = make_recursive_iterator<2>(obj);
-  EXPECT_THAT(std::get<0>(rit), make_end_aware_iterator(obj));
-  EXPECT_THAT(std::get<1>(rit), make_end_aware_iterator(obj[1]));
+  EXPECT_THAT(std::get<0>(rit), end_aware_iterator(obj));
+  EXPECT_THAT(std::get<1>(rit), end_aware_iterator(obj[1]));
 }
 
 // TODO: This ought to be implemented as a compiles-test

+ 1 - 1
test/unkeyed_iterator_test.cxx

@@ -74,7 +74,7 @@ TEST(UnkeyedIteratorTest, DoesNotGenerateAtEnd) {
 
 TEST(UnkeyedIteratorTest, PropagatesAtEnd) {
   std::map<int, int> map{{1, 2}, {2, 3}};
-  unkeyed_iterator end(end_aware_iterator(map.end()));
+  unkeyed_iterator end(end_aware_iterator(map.end(), map.end()));
   EXPECT_THAT(decltype(end)(), end);
 }