Browse Source

refactor: extract some of the impl of recursive_iterator to support cascade_iterator

Sam Jaffe 2 months ago
parent
commit
520227ecb1

+ 33 - 0
include/iterator/detail/capture_fn.h

@@ -0,0 +1,33 @@
+//
+//  capture.h
+//  iterator
+//
+//  Created by Sam Jaffe on 9/23/25.
+//  Copyright © 2025 Sam Jaffe. All rights reserved.
+//
+
+#pragma once
+
+#include <functional>
+
+namespace iterator::detail {
+template <typename P, typename T> class CaptureFn {
+private:
+  using R = std::invoke_result_t<P, T>;
+
+private:
+  P fn_;
+  void const * key_;
+  mutable R cache_;
+
+public:
+  CaptureFn(P fn) : fn_(fn) {} // NOLINT
+
+  auto const & operator()(T & arg) const {
+    if (key_ != &arg) {
+      new (&cache_) R(std::invoke(fn_, std::forward<T>(arg)));
+    }
+    return cache_;
+  }
+};
+}

+ 69 - 0
include/iterator/detail/projection_tuple.h

@@ -0,0 +1,69 @@
+//
+//  projection_tuple.h
+//  iterator
+//
+//  Created by Sam Jaffe on 9/23/25.
+//  Copyright © 2025 Sam Jaffe. All rights reserved.
+//
+
+#pragma once
+
+#include <functional>
+#include <tuple>
+#include <type_traits>
+
+#include <iterator/concepts.h>
+#include <iterator/detail/capture_fn.h>
+
+namespace iterator::detail {
+template <typename... Projs> class Projections {
+private:
+  std::tuple<Projs...> fns_;
+
+public:
+  Projections(Projs... fns) : fns_(fns...) {}
+  Projections(std::tuple<Projs...> const & fns) : fns_(fns) {}
+
+  template <size_t I, typename T>
+  decltype(auto) operator()(T && arg,
+                            std::integral_constant<size_t, I> = {}) const {
+    if constexpr (I >= sizeof...(Projs)) {
+      return std::forward<T>(arg);
+    } else if constexpr (Assoc<std::decay_t<T>>) {
+      return std::tie(arg.first, std::invoke(std::get<I>(fns_),
+                                             std::forward<T>(arg).second));
+    } else {
+      return std::invoke(std::get<I>(fns_), std::forward<T>(arg));
+    }
+  }
+};
+
+template <typename It, typename Projs, size_t I = 0> struct ProjectionExpander {
+  using type = std::tuple<>;
+};
+
+template <typename It, typename... Projs, size_t I>
+  requires(I < sizeof...(Projs))
+struct ProjectionExpander<It, Projections<Projs...>, I> {
+  using Fn = std::tuple_element_t<I, std::tuple<Projs...>>;
+
+  template <typename T> static decltype(auto) get(T && ref) {
+    if constexpr (Assoc<std::decay_t<T>>) {
+      return std::forward<T>(ref).second;
+    } else {
+      return std::forward<T>(ref);
+    }
+  }
+
+  static std::iter_reference_t<It> _ref;
+
+  using value_type = decltype(get(_ref));
+  using result_type = std::invoke_result_t<Fn, value_type>;
+
+  using type = tuple_cat_t<
+      std::tuple<std::conditional_t<std::is_reference_v<result_type>, Fn,
+                                    CaptureFn<Fn, value_type>>>,
+      typename ProjectionExpander<iterator_t<result_type>,
+                                  Projections<Projs...>, I + 1>::type>;
+};
+}

+ 57 - 0
include/iterator/detail/recursive_expander.h

@@ -0,0 +1,57 @@
+//
+//  RecursiveExpander.h
+//  iterator
+//
+//  Created by Sam Jaffe on 9/23/25.
+//  Copyright © 2025 Sam Jaffe. All rights reserved.
+//
+
+#pragma once
+#include <iterator>
+#include <type_traits>
+
+#include <iterator/concepts.h>
+#include <iterator/detail/projection_tuple.h>
+#include <iterator/end_aware_iterator.h>
+
+namespace iterator::detail {
+template <typename Proj, typename It, size_t I>
+using projection_t = std::invoke_result_t<Proj, std::iter_reference_t<It>,
+                                          std::integral_constant<size_t, I>>;
+
+template <typename It, typename Projs, typename MaxDepth, size_t N = 0,
+          typename V = std::decay_t<projection_t<Projs, It, N>>>
+struct RecursiveExpander {
+  using type = std::tuple<end_aware_iterator<It>>;
+};
+
+template <typename It, typename Projs, size_t N>
+struct RecursiveExpander<It, Projs, bounded<N + 1>, N> {
+  using type = std::tuple<end_aware_iterator<It>>;
+};
+
+template <typename It, typename Projs, typename MaxDepth, size_t N, Range V>
+struct RecursiveExpander<It, Projs, MaxDepth, N, V> {
+  using projected_value_type = projection_t<Projs, It, N>;
+
+  using expand_next = RecursiveExpander<iterator_t<projected_value_type>, Projs,
+                                        MaxDepth, N + 1>;
+
+  using type = tuple_cat_t<std::tuple<end_aware_iterator<It>>,
+                           typename expand_next::type>;
+};
+
+template <typename It, typename Projs, typename MaxDepth, size_t N,
+          AssocRange V>
+struct RecursiveExpander<It, Projs, MaxDepth, N, V> {
+  using projected_value_type =
+      std::tuple_element_t<1,
+                           std::remove_reference_t<projection_t<Projs, It, N>>>;
+
+  using expand_next = RecursiveExpander<iterator_t<projected_value_type>, Projs,
+                                        MaxDepth, N + 1>;
+
+  using type = tuple_cat_t<std::tuple<end_aware_iterator<It>>,
+                           typename expand_next::type>;
+};
+}

+ 11 - 35
include/iterator/recursive_iterator.h

@@ -8,10 +8,12 @@
 #pragma once
 
 #include <ranges>
-#include <string>
 #include <tuple>
 #include <utility>
 
+#include <iterator/concepts.h>
+#include <iterator/detail/projection_tuple.h>
+#include <iterator/detail/recursive_expander.h>
 #include <iterator/end_aware_iterator.h>
 #include <iterator/facade.h>
 #include <iterator/forwards.h>
@@ -19,38 +21,6 @@
 #include <iterator/detail/macro.h>
 
 namespace iterator {
-template <typename It, typename MaxDepth, size_t N = 0,
-          typename V = std::iter_value_t<It>>
-struct tuple_expander {
-  using iterator_tuple = std::tuple<end_aware_iterator<It>>;
-};
-
-template <typename It, size_t N> struct tuple_expander<It, bounded<N + 1>, N> {
-  using iterator_tuple = std::tuple<end_aware_iterator<It>>;
-};
-
-template <typename It, typename MaxDepth, size_t N, Range V>
-struct tuple_expander<It, MaxDepth, N, V> {
-  static It & _it;
-
-  using next_iterator_t = decltype(std::begin(*_it));
-  using expand_next = tuple_expander<next_iterator_t, MaxDepth, N + 1>;
-
-  using iterator_tuple = tuple_cat_t<std::tuple<end_aware_iterator<It>>,
-                                     typename expand_next::iterator_tuple>;
-};
-
-template <typename It, typename MaxDepth, size_t N, AssocRange V>
-struct tuple_expander<It, MaxDepth, N, V> {
-  static It & _it;
-
-  using next_iterator_t = decltype(std::begin(_it->second));
-  using expand_next = tuple_expander<next_iterator_t, MaxDepth, N + 1>;
-
-  using iterator_tuple = tuple_cat_t<std::tuple<end_aware_iterator<It>>,
-                                     typename expand_next::iterator_tuple>;
-};
-
 template <typename Tuple, typename Indices> class recursive_iterator_base;
 template <typename... It, size_t... Is>
 class recursive_iterator_base<std::tuple<It...>, std::index_sequence<Is...>>
@@ -134,8 +104,14 @@ private:
   }
 };
 
-template <typename It, typename MaxDepth> struct recursive_iterator_helper {
-  using iterator_tuple = typename tuple_expander<It, MaxDepth>::iterator_tuple;
+template <typename It, typename MaxDepth,
+          typename Projs = detail::Projections<>>
+struct recursive_iterator_helper {
+  static typename detail::ProjectionExpander<It, Projs>::type const & _projs;
+  using Projections = decltype(detail::Projections(_projs));
+
+  using iterator_tuple =
+      typename detail::RecursiveExpander<It, Projections, MaxDepth>::type;
 
   static constexpr auto extent = std::tuple_size_v<iterator_tuple>;
   using indices = decltype(std::make_index_sequence<extent>());

+ 12 - 0
iterator.xcodeproj/project.pbxproj

@@ -7,6 +7,9 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		CD0AED892E836E4600E8B05D /* recursive_expander.h in Headers */ = {isa = PBXBuildFile; fileRef = CD0AED882E836E4600E8B05D /* recursive_expander.h */; };
+		CD0AED8B2E836E9F00E8B05D /* projection_tuple.h in Headers */ = {isa = PBXBuildFile; fileRef = CD0AED8A2E836E9F00E8B05D /* projection_tuple.h */; };
+		CD0AED8D2E836EF200E8B05D /* capture_fn.h in Headers */ = {isa = PBXBuildFile; fileRef = CD0AED8C2E836EF200E8B05D /* capture_fn.h */; };
 		CD41AFE32E7F13E4004F3E51 /* concepts.h in Headers */ = {isa = PBXBuildFile; fileRef = CD41AFE22E7F0434004F3E51 /* concepts.h */; };
 		CD41AFE42E7F13E4004F3E51 /* forwards.h in Headers */ = {isa = PBXBuildFile; fileRef = CDA2B6122858128C004D5353 /* forwards.h */; };
 		CD41AFE52E7F13E4004F3E51 /* facade.h in Headers */ = {isa = PBXBuildFile; fileRef = CDA2B6132858128C004D5353 /* facade.h */; };
@@ -78,6 +81,9 @@
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
+		CD0AED882E836E4600E8B05D /* recursive_expander.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = recursive_expander.h; sourceTree = "<group>"; };
+		CD0AED8A2E836E9F00E8B05D /* projection_tuple.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = projection_tuple.h; sourceTree = "<group>"; };
+		CD0AED8C2E836EF200E8B05D /* capture_fn.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = capture_fn.h; sourceTree = "<group>"; };
 		CD3C6DDB26238F8F00548B64 /* xcode_gtest_helper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xcode_gtest_helper.h; sourceTree = "<group>"; };
 		CD41AFE22E7F0434004F3E51 /* concepts.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = concepts.h; sourceTree = "<group>"; };
 		CD5A8E7329D7910D008C2A4F /* sentinel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sentinel.h; sourceTree = "<group>"; };
@@ -212,6 +218,9 @@
 				CDA2B61A2858128C004D5353 /* arrow_proxy.h */,
 				CD5AEB3129D8885400A390A4 /* macro.h */,
 				CD5AEB3229D8886200A390A4 /* undef.h */,
+				CD0AED8A2E836E9F00E8B05D /* projection_tuple.h */,
+				CD0AED8C2E836EF200E8B05D /* capture_fn.h */,
+				CD0AED882E836E4600E8B05D /* recursive_expander.h */,
 			);
 			path = detail;
 			sourceTree = "<group>";
@@ -254,13 +263,16 @@
 				CD41AFE42E7F13E4004F3E51 /* forwards.h in Headers */,
 				CD41AFE52E7F13E4004F3E51 /* facade.h in Headers */,
 				CD41AFE62E7F13E4004F3E51 /* proxy.h in Headers */,
+				CD0AED892E836E4600E8B05D /* recursive_expander.h in Headers */,
 				CD41AFE72E7F13E4004F3E51 /* sentinel.h in Headers */,
 				CD41AFE82E7F13E4004F3E51 /* arrow_proxy.h in Headers */,
 				CD41AFE92E7F13E4004F3E51 /* macro.h in Headers */,
 				CD41AFEC2E7F13E4004F3E51 /* undef.h in Headers */,
+				CD0AED8D2E836EF200E8B05D /* capture_fn.h in Headers */,
 				CD41AFED2E7F13E4004F3E51 /* capture_iterator.h in Headers */,
 				CD41AFEE2E7F13E4004F3E51 /* end_aware_iterator.h in Headers */,
 				CD41AFEF2E7F13E4004F3E51 /* filter_iterator.h in Headers */,
+				CD0AED8B2E836E9F00E8B05D /* projection_tuple.h in Headers */,
 				CD41AFF02E7F13E4004F3E51 /* indexed_iterator.h in Headers */,
 				CD41AFF12E7F13E4004F3E51 /* join_iterator.h in Headers */,
 				CD41AFF22E7F13E4004F3E51 /* recursive_iterator.h in Headers */,