diff --git a/include/continuable/continuable-base.hpp b/include/continuable/continuable-base.hpp index e33e12a..95aca8d 100644 --- a/include/continuable/continuable-base.hpp +++ b/include/continuable/continuable-base.hpp @@ -852,8 +852,8 @@ constexpr auto make_ready_continuable(FirstResult&& first_result, std::forward(second_result), std::forward(rest)...)]( auto&& promise) mutable { - detail::traits::unpack(result, - std::forward(promise)); + detail::traits::unpack(std::forward(promise), + result); }); } diff --git a/include/continuable/detail/base.hpp b/include/continuable/detail/base.hpp index 235baeb..1da0144 100644 --- a/include/continuable/detail/base.hpp +++ b/include/continuable/detail/base.hpp @@ -231,12 +231,14 @@ inline auto sequenced_unpack_invoker() { // the lambda. using Next = decltype(next_callback); - traits::unpack(std::move(result), [&](auto&&... types) { - /// TODO Add inplace resolution here + traits::unpack( + [&](auto&&... types) { + /// TODO Add inplace resolution here - invoke_no_except(std::forward(next_callback), - std::forward(types)...); - }); + invoke_no_except(std::forward(next_callback), + std::forward(types)...); + }, + std::move(result)); CONTINUABLE_BLOCK_TRY_END }; } // namespace decoration @@ -277,12 +279,15 @@ void packed_dispatch(Executor&& executor, Invoker&& invoker, Args&&... args) { invoker = std::forward(invoker), args = std::make_tuple(std::forward(args)...) ]() mutable { - traits::unpack(std::move(args), [&](auto&&... captured_args) { - // Just use the packed dispatch method which dispatches the work on - // the current thread. - packed_dispatch(types::this_thread_executor_tag{}, std::move(invoker), - std::forward(captured_args)...); - }); + traits::unpack( + [&](auto&&... captured_args) { + // Just use the packed dispatch method which dispatches the work on + // the current thread. + packed_dispatch( + types::this_thread_executor_tag{}, std::move(invoker), + std::forward(captured_args)...); + }, + std::move(args)); }; // Pass the work callable object to the executor diff --git a/include/continuable/detail/connection-aggregated.hpp b/include/continuable/detail/connection-aggregated.hpp index 9a6999b..7a9584a 100644 --- a/include/continuable/detail/connection-aggregated.hpp +++ b/include/continuable/detail/connection-aggregated.hpp @@ -149,9 +149,11 @@ public: } auto unbox() && { - return traits::unpack(unpack_lazy(std::move(args_)), [](auto&&... args) { - return spread_this(std::forward(args)...); - }); + return traits::unpack( + [](auto&&... args) { + return spread_this(std::forward(args)...); + }, + unpack_lazy(std::move(args_))); } }; @@ -208,8 +210,8 @@ template constexpr auto finalize_impl(traits::identity>, Callback&& callback, Data&& data) { // Call the final callback with the cleaned result - return traits::unpack(unbox_continuables(std::forward(data)), - std::forward(callback)); + return traits::unpack(std::forward(callback), + unbox_continuables(std::forward(data))); } struct hint_mapper { diff --git a/include/continuable/detail/connection-seq.hpp b/include/continuable/detail/connection-seq.hpp index 9da70e8..718a0bc 100644 --- a/include/continuable/detail/connection-seq.hpp +++ b/include/continuable/detail/connection-seq.hpp @@ -61,7 +61,7 @@ auto sequential_connect(Left&& left, Right&& right) { return std::move(right).then([previous = std::make_tuple( std::forward(args)...)]( auto&&... args) mutable { - return traits::merge( + return std::tuple_cat( std::move(previous), std::make_tuple(std::forward(args)...)); }); diff --git a/include/continuable/detail/connection.hpp b/include/continuable/detail/connection.hpp index 9fa2600..395d92e 100644 --- a/include/continuable/detail/connection.hpp +++ b/include/continuable/detail/connection.hpp @@ -56,7 +56,7 @@ template auto chain_connection(std::tuple leftPack, std::tuple rightPack) { - return traits::merge(std::move(leftPack), std::move(rightPack)); + return std::tuple_cat(std::move(leftPack), std::move(rightPack)); } /// Normalizes a continuation to a tuple holding an arbitrary count of diff --git a/include/continuable/detail/features.hpp b/include/continuable/detail/features.hpp index dc33b3a..399f1a4 100644 --- a/include/continuable/detail/features.hpp +++ b/include/continuable/detail/features.hpp @@ -58,6 +58,8 @@ #define CONTINUABLE_HAS_CXX17_VOID_T #else // Generic feature detection based on __has_feature + // and other preprocessor definitions based on: + // http://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros #if defined(__has_feature) #if !defined(CONTINUABLE_HAS_CXX17_CONSTEXPR_IF) && \ __has_feature(cxx_if_constexpr) diff --git a/include/continuable/detail/promisify.hpp b/include/continuable/detail/promisify.hpp index 3ada8a2..10be92f 100644 --- a/include/continuable/detail/promisify.hpp +++ b/include/continuable/detail/promisify.hpp @@ -77,14 +77,15 @@ struct promisify_helper { auto&& promise) mutable { traits::unpack( - std::move(args), [promise = std::forward(promise)]( - auto&&... args) mutable { + [promise = std::forward(promise)]( + auto&&... args) mutable { Evaluator> evaluator{ std::move(promise)}; util::invoke(std::forward(args)..., std::move(evaluator)); - }); + }, + std::move(args)); }); } }; diff --git a/include/continuable/detail/traits.hpp b/include/continuable/detail/traits.hpp index 7d1363d..ffd91e9 100644 --- a/include/continuable/detail/traits.hpp +++ b/include/continuable/detail/traits.hpp @@ -32,7 +32,6 @@ #define CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED #include -#include #include #include #include @@ -184,108 +183,33 @@ constexpr auto static_if(Type&& type, Check&& check, std::forward(falseCallback)); } -/// Calls the given unpacker with the content of the given sequence -template -constexpr decltype(auto) unpack(std::integer_sequence, - U&& unpacker) { - return std::forward(unpacker)(std::integral_constant{}...); -} - +namespace detail { /// Calls the given unpacker with the content of the given sequenceable -template -constexpr auto unpack(F&& first_sequenceable, U&& unpacker, - std::integer_sequence) +template +constexpr auto unpack_impl(U&& unpacker, F&& first_sequenceable, + std::integer_sequence) -> decltype(std::forward(unpacker)( - get(std::forward(first_sequenceable))...)) { + std::get(std::forward(first_sequenceable))...)) { (void)first_sequenceable; return std::forward(unpacker)( - get(std::forward(first_sequenceable))...); -} -/// Calls the given unpacker with the content of the given sequenceable -template -constexpr auto unpack(F&& first_sequenceable, S&& second_sequenceable, - U&& unpacker, std::integer_sequence, - std::integer_sequence) - -> decltype(std::forward(unpacker)( - get(std::forward(first_sequenceable))..., - get(std::forward(second_sequenceable))...)) { - (void)first_sequenceable; - (void)second_sequenceable; - return std::forward(unpacker)( - get(std::forward(first_sequenceable))..., - get(std::forward(second_sequenceable))...); -} -/// Calls the given unpacker with the content of the given sequenceable -template -constexpr auto unpack(F&& first_sequenceable, U&& unpacker) - -> decltype(unpack(std::forward(first_sequenceable), - std::forward(unpacker), - sequence_of(identify{}))) { - return unpack(std::forward(first_sequenceable), std::forward(unpacker), - sequence_of(identify{})); -} -/// Calls the given unpacker with the content of the given sequenceables -template -constexpr auto unpack(F&& first_sequenceable, S&& second_sequenceable, - U&& unpacker) - -> decltype(unpack(std::forward(first_sequenceable), - std::forward(second_sequenceable), - std::forward(unpacker), - sequence_of(identity_of(first_sequenceable)), - sequence_of(identity_of(second_sequenceable)))) { - return unpack(std::forward(first_sequenceable), - std::forward(second_sequenceable), std::forward(unpacker), - sequence_of(identity_of(first_sequenceable)), - sequence_of(identity_of(second_sequenceable))); + std::get(std::forward(first_sequenceable))...); } +} // namespace detail -/// Adds the given type at the back of the left sequenceable -template -constexpr auto push(Left&& left, Element&& element) { - return unpack(std::forward(left), [&](auto&&... args) { - return std::make_tuple(std::forward(args)..., - std::forward(element)); - }); -} +/// Calls the given callable object with the content of the given sequenceable +/// +/// \note We can't use std::apply here since this implementation is SFINAE +/// aware and the std version not! This would lead to compilation errors. +template >::value>> +constexpr auto unpack(Callable&& obj, TupleLike&& tuple_like) + -> decltype(detail::unpack_impl(std::forward(obj), + std::forward(tuple_like), + Sequence{})) { -/// Adds the element to the back of the identity -template -constexpr auto push(identity, identity) noexcept { - return identity{}; -} - -/// Removes the first element from the identity -template -constexpr auto pop_first(identity) noexcept { - return identity{}; -} - -/// Returns the merged sequence -template -constexpr auto merge(Left&& left) { - return std::forward(left); -} -/// Merges the left sequenceable with the right ones -template -constexpr auto merge(Left&& left, Right&& right, Rest&&... rest) { - // Merge the left with the right sequenceable and - // merge the result with the rest. - return merge(unpack(std::forward(left), std::forward(right), - [&](auto&&... args) { - // Maybe use: template class T, - // typename... Args> - return std::make_tuple( - std::forward(args)...); - }), - std::forward(rest)...); -} -/// Merges the left identity with the right ones -template -constexpr auto merge(identity /*left*/, - identity /*right*/, Rest&&... rest) { - return merge(identity{}, - std::forward(rest)...); + return detail::unpack_impl(std::forward(obj), + std::forward(tuple_like), Sequence{}); } namespace detail { diff --git a/include/continuable/detail/traverse-async.hpp b/include/continuable/detail/traverse-async.hpp index 93a6767..5e05159 100644 --- a/include/continuable/detail/traverse-async.hpp +++ b/include/continuable/detail/traverse-async.hpp @@ -520,7 +520,7 @@ struct resume_state_callable { template void resume_traversal_callable::operator()() { auto hierarchy = std::tuple_cat(std::make_tuple(frame_), state_); - traits::unpack(std::move(hierarchy), resume_state_callable{}); + traits::unpack(resume_state_callable{}, std::move(hierarchy)); } /// Gives access to types related to the traversal frame diff --git a/include/continuable/detail/traverse.hpp b/include/continuable/detail/traverse.hpp index 3d736fc..a94eccc 100644 --- a/include/continuable/detail/traverse.hpp +++ b/include/continuable/detail/traverse.hpp @@ -192,10 +192,10 @@ struct flat_arraylizer { template constexpr auto apply_spread_impl(std::true_type, C&& callable, T&&... args) -> decltype( - traits::unpack(std::tuple_cat(undecorate(std::forward(args))...), - std::forward(callable))) { - return traits::unpack(std::tuple_cat(undecorate(std::forward(args))...), - std::forward(callable)); + traits::unpack(std::forward(callable), + std::tuple_cat(undecorate(std::forward(args))...))) { + return traits::unpack(std::forward(callable), + std::tuple_cat(undecorate(std::forward(args))...)); } /// Use the linear instantiation for variadic packs which don't @@ -630,14 +630,14 @@ struct tuple_like_remapper< /// different types. template auto remap(Strategy, T&& container, M&& mapper) -> decltype(traits::unpack( - std::forward(container), std::declval::type, - typename std::decay::type>>())) { + typename std::decay::type>>(), + std::forward(container))) { return traits::unpack( - std::forward(container), tuple_like_remapper::type, typename std::decay::type>{ - std::forward(mapper)}); + std::forward(mapper)}, + std::forward(container)); } } // end namespace tuple_like_remapping diff --git a/include/continuable/detail/util.hpp b/include/continuable/detail/util.hpp index d46b55a..c03d1a0 100644 --- a/include/continuable/detail/util.hpp +++ b/include/continuable/detail/util.hpp @@ -49,27 +49,27 @@ constexpr void unused(T&&...) noexcept { } namespace detail { +template +auto forward_except_last_impl(T&& tuple, + std::integer_sequence) { + (void)tuple; + return std::forward_as_tuple(std::get(std::forward(tuple))...); +} + /// Forwards every element in the tuple except the last one template auto forward_except_last(T&& sequenceable) { constexpr auto const size = pack_size_of(traits::identify()) - 1U; constexpr auto const sequence = std::make_index_sequence(); - return traits::unpack(std::forward(sequenceable), - [](auto&&... args) { - return std::forward_as_tuple( - std::forward(args)...); - }, - sequence); + return forward_except_last_impl(std::forward(sequenceable), sequence); } /// We are able to call the callable with the arguments given in the tuple template auto partial_invoke_impl(std::true_type, T&& callable, std::tuple args) { - return traits::unpack(std::move(args), [&](auto&&... arg) { - return std::forward(callable)(std::forward(arg)...); - }); + return traits::unpack(std::forward(callable), std::move(args)); } /// We were unable to call the callable with the arguments in the tuple. diff --git a/test/unit-test/multi/test-continuable-regression.cpp b/test/unit-test/multi/test-continuable-regression.cpp index 32c5e71..c0d416b 100644 --- a/test/unit-test/multi/test-continuable-regression.cpp +++ b/test/unit-test/multi/test-continuable-regression.cpp @@ -33,21 +33,18 @@ using namespace cti::detail; TEST(regression_tests, are_multiple_args_mergeable) { { auto tp = std::make_tuple(1, 2, 3); - traits::merge(tp, tp, tp, tp, tp); + std::tuple_cat(tp, tp, tp, tp, tp); } - auto tp2 = traits::merge(std::make_tuple(), std::make_tuple(1), - std::make_tuple(1, 2), std::make_tuple(1, 2, 3), - std::make_tuple(1, 2, 3, 4)); + auto tp2 = std::tuple_cat(std::make_tuple(), std::make_tuple(1), + std::make_tuple(1, 2), std::make_tuple(1, 2, 3), + std::make_tuple(1, 2, 3, 4)); - auto count = traits::unpack(tp2, [](auto... args) { - std::vector v{args...}; - return std::accumulate(v.begin(), v.end(), 0); - }); + auto count = traits::unpack( + [](auto... args) { + std::vector v{args...}; + return std::accumulate(v.begin(), v.end(), 0); + }, + tp2); EXPECT_EQ(count, 20); } - -TEST(recursion_tests, are_noncopyable_mergeable) { - std::tuple nc1, nc2, nc3; - traits::merge(std::move(nc1), std::move(nc2), std::move(nc3)); -} diff --git a/test/unit-test/test-continuable.hpp b/test/unit-test/test-continuable.hpp index 92fcc69..ba78b67 100644 --- a/test/unit-test/test-continuable.hpp +++ b/test/unit-test/test-continuable.hpp @@ -49,9 +49,11 @@ template auto supplier_of(Args&&... args) { return [values = std::make_tuple(std::forward(args)...)]( auto&& promise) mutable { - cti::detail::traits::unpack(std::move(values), [&](auto&&... passed) { - promise.set_value(std::forward(passed)...); - }); + cti::detail::traits::unpack( + [&](auto&&... passed) { + promise.set_value(std::forward(passed)...); + }, + std::move(values)); }; }