Skip to content

Commit

Permalink
Use recursive lambda pattern to improve result_type_helper and expand
Browse files Browse the repository at this point in the history
  • Loading branch information
nickpdemarco committed Feb 22, 2024
1 parent addebe0 commit d51befc
Showing 1 changed file with 35 additions and 37 deletions.
72 changes: 35 additions & 37 deletions test/initial_draft.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,50 +100,51 @@ using segment_result_type =
simplify this code by handing the multi-argument case earlier (somehow).
*/

#define STLAB_FWD(x) std::forward<decltype(x)>(x)

template <class Tail, class Applicator, class... Fs>
class chain {
Tail _tail;
segment<Applicator, Fs...> _head;

template <class Index>
/// Apply a recursive lambda to each element in _tail, followed by _head.
template <class F>
auto fold_over(F fold) && {
return std::apply([fold](auto&&... links) {
return fold(fold, STLAB_FWD(links)...);
}, std::tuple_cat(std::move(_tail), std::tuple(std::move(_head))));
}

Check warning on line 116 in test/initial_draft.cpp

View check run for this annotation

Codecov / codecov/patch

test/initial_draft.cpp#L116

Added line #L116 was not covered by tests

/// Return a lambda with the signature of
/// head( tail<n>( tail<1>( tail<0>( auto&& args... ) ) ) )
/// for computing the result type of this chain.
auto result_type_helper() && {
if constexpr (Index::value == std::tuple_size_v<Tail>) {
return [_segment = std::move(_head)](auto&&... args) mutable {
return std::move(_segment).result_type_helper(
std::forward<decltype(args)>(args)...);
return std::move(*this).fold_over([](auto fold, auto&& first, auto&&... rest) {
if constexpr (sizeof...(rest) == 0) {
return [_segment = STLAB_FWD(first)](auto&&... args) mutable {
return std::move(_segment).result_type_helper(STLAB_FWD(args)...);

Check warning on line 125 in test/initial_draft.cpp

View check run for this annotation

Codecov / codecov/patch

test/initial_draft.cpp#L124-L125

Added lines #L124 - L125 were not covered by tests
};
} else {
return [_segment = STLAB_FWD(first).append(fold(fold, STLAB_FWD(rest)...))] (auto&&... args) mutable {
return std::move(_segment).result_type_helper(STLAB_FWD(args)...);
};
} else {
return
[_segment =
std::move(std::get<Index::value>(_tail))
.append(std::move(*this)
.template result_type_helper<
std::integral_constant<std::size_t, Index::value + 1>>())](
auto&&... args) mutable {
return std::move(_segment).result_type_helper(
std::forward<decltype(args)>(args)...);
};
}
}
});
}

template <class Index, class R>
template <class R>
auto expand(const R& receiver) && {
if constexpr (Index::value == std::tuple_size_v<Tail>) {
return [_segment = std::move(_head).append(receiver),
_receiver = receiver](auto&&... args) mutable {
return std::move(_segment).invoke(_receiver, std::forward<decltype(args)>(args)...);
return std::move(*this).fold_over([receiver](auto fold, auto&& first, auto&&... rest) {
if constexpr (sizeof...(rest) == 0) {
return [receiver, _segment = STLAB_FWD(first).append(receiver)](auto&&... args) mutable {
return std::move(_segment).invoke(receiver, STLAB_FWD(args)...);
};
} else {
return [_segment =
std::move(std::get<Index::value>(_tail))
.append(std::move(*this)
.template expand<
std::integral_constant<std::size_t, Index::value + 1>>(
receiver)),
_receiver = receiver](auto&&... args) mutable {
return std::move(_segment).invoke(_receiver, std::forward<decltype(args)>(args)...);
} else {
return [receiver, _segment = STLAB_FWD(first).append(fold(fold, STLAB_FWD(rest)...))] (auto&&... args) mutable {
return std::move(_segment).invoke(receiver, STLAB_FWD(args)...);
};
}
}
});
}

public:
Expand Down Expand Up @@ -175,13 +176,10 @@ class chain {
template <class... Args>
auto operator()(Args&&... args) && {
using result_type =
decltype(std::move(*this)
.template result_type_helper<std::integral_constant<std::size_t, 0>>()(
std::forward<Args>(args)...));
decltype(std::move(*this).result_type_helper()(std::forward<Args>(args)...));
auto [receiver, future] =
stlab::package<result_type(result_type)>(stlab::immediate_executor, std::identity{});
(void)std::move(*this).template expand<std::integral_constant<std::size_t, 0>>(receiver)(
std::forward<Args>(args)...);
(void) std::move(*this).expand(receiver)(std::forward<Args>(args)...);
return std::move(future);
}

Expand Down

0 comments on commit d51befc

Please sign in to comment.