projection_tuple.h 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. //
  2. // projection_tuple.h
  3. // iterator
  4. //
  5. // Created by Sam Jaffe on 9/23/25.
  6. // Copyright © 2025 Sam Jaffe. All rights reserved.
  7. //
  8. #pragma once
  9. #include <functional>
  10. #include <tuple>
  11. #include <type_traits>
  12. #include <iterator/concepts.h>
  13. #include <iterator/detail/capture_fn.h>
  14. namespace iterator::detail {
  15. template <typename... Projs> class Projections {
  16. private:
  17. std::tuple<Projs...> fns_;
  18. public:
  19. Projections() = default;
  20. Projections(Projs... fns)
  21. requires(sizeof...(Projs) > 0)
  22. : fns_(fns...) {}
  23. Projections(std::tuple<Projs...> const & fns) : fns_(fns) {}
  24. template <size_t I, typename T>
  25. decltype(auto) operator()(T && arg,
  26. std::integral_constant<size_t, I> = {}) const {
  27. if constexpr (I >= sizeof...(Projs)) {
  28. return std::forward<T>(arg);
  29. } else if constexpr (Assoc<std::decay_t<T>>) {
  30. return std::tie(arg.first, std::invoke(std::get<I>(fns_),
  31. std::forward<T>(arg).second));
  32. } else {
  33. return std::invoke(std::get<I>(fns_), std::forward<T>(arg));
  34. }
  35. }
  36. };
  37. template <typename It, typename Projs, size_t I = 0> struct ProjectionExpander {
  38. using type = std::tuple<>;
  39. };
  40. template <typename It, typename... Projs, size_t I>
  41. requires(I < sizeof...(Projs))
  42. struct ProjectionExpander<It, Projections<Projs...>, I> {
  43. using Fn = std::tuple_element_t<I, std::tuple<Projs...>>;
  44. template <typename T> static decltype(auto) get(T && ref) {
  45. if constexpr (Assoc<std::decay_t<T>>) {
  46. return std::forward<T>(ref).second;
  47. } else {
  48. return std::forward<T>(ref);
  49. }
  50. }
  51. static std::iter_reference_t<It> _ref;
  52. using value_type = decltype(get(_ref));
  53. using result_type = std::invoke_result_t<Fn, value_type>;
  54. using type = tuple_cat_t<
  55. std::tuple<std::conditional_t<std::is_reference_v<result_type>, Fn,
  56. CaptureFn<Fn, value_type>>>,
  57. typename ProjectionExpander<iterator_t<result_type>,
  58. Projections<Projs...>, I + 1>::type>;
  59. };
  60. }