mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 08:46:44 +08:00
Use a std::apply style unpack
* Some cleanup
This commit is contained in:
parent
41c7cb008a
commit
f091cbb079
@ -852,8 +852,8 @@ constexpr auto make_ready_continuable(FirstResult&& first_result,
|
||||
std::forward<SecondResult>(second_result),
|
||||
std::forward<Rest>(rest)...)](
|
||||
auto&& promise) mutable {
|
||||
detail::traits::unpack(result,
|
||||
std::forward<decltype(promise)>(promise));
|
||||
detail::traits::unpack(std::forward<decltype(promise)>(promise),
|
||||
result);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -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>(next_callback),
|
||||
std::forward<decltype(types)>(types)...);
|
||||
});
|
||||
invoke_no_except(std::forward<Next>(next_callback),
|
||||
std::forward<decltype(types)>(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>(invoker),
|
||||
args = std::make_tuple(std::forward<Args>(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<decltype(captured_args)>(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<decltype(captured_args)>(captured_args)...);
|
||||
},
|
||||
std::move(args));
|
||||
};
|
||||
|
||||
// Pass the work callable object to the executor
|
||||
|
||||
@ -149,9 +149,11 @@ public:
|
||||
}
|
||||
|
||||
auto unbox() && {
|
||||
return traits::unpack(unpack_lazy(std::move(args_)), [](auto&&... args) {
|
||||
return spread_this(std::forward<decltype(args)>(args)...);
|
||||
});
|
||||
return traits::unpack(
|
||||
[](auto&&... args) {
|
||||
return spread_this(std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
unpack_lazy(std::move(args_)));
|
||||
}
|
||||
};
|
||||
|
||||
@ -208,8 +210,8 @@ template <typename... Args, typename Callback, typename Data>
|
||||
constexpr auto finalize_impl(traits::identity<std::tuple<Args...>>,
|
||||
Callback&& callback, Data&& data) {
|
||||
// Call the final callback with the cleaned result
|
||||
return traits::unpack(unbox_continuables(std::forward<Data>(data)),
|
||||
std::forward<Callback>(callback));
|
||||
return traits::unpack(std::forward<Callback>(callback),
|
||||
unbox_continuables(std::forward<Data>(data)));
|
||||
}
|
||||
|
||||
struct hint_mapper {
|
||||
|
||||
@ -61,7 +61,7 @@ auto sequential_connect(Left&& left, Right&& right) {
|
||||
return std::move(right).then([previous = std::make_tuple(
|
||||
std::forward<decltype(args)>(args)...)](
|
||||
auto&&... args) mutable {
|
||||
return traits::merge(
|
||||
return std::tuple_cat(
|
||||
std::move(previous),
|
||||
std::make_tuple(std::forward<decltype(args)>(args)...));
|
||||
});
|
||||
|
||||
@ -56,7 +56,7 @@ template <typename... LeftArgs, typename... RightArgs>
|
||||
auto chain_connection(std::tuple<LeftArgs...> leftPack,
|
||||
std::tuple<RightArgs...> 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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -77,14 +77,15 @@ struct promisify_helper {
|
||||
auto&& promise) mutable {
|
||||
|
||||
traits::unpack(
|
||||
std::move(args), [promise = std::forward<decltype(promise)>(promise)](
|
||||
auto&&... args) mutable {
|
||||
[promise = std::forward<decltype(promise)>(promise)](
|
||||
auto&&... args) mutable {
|
||||
Evaluator<std::decay_t<decltype(promise)>> evaluator{
|
||||
std::move(promise)};
|
||||
|
||||
util::invoke(std::forward<decltype(args)>(args)...,
|
||||
std::move(evaluator));
|
||||
});
|
||||
},
|
||||
std::move(args));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -32,7 +32,6 @@
|
||||
#define CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED
|
||||
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@ -184,108 +183,33 @@ constexpr auto static_if(Type&& type, Check&& check,
|
||||
std::forward<FalseCallback>(falseCallback));
|
||||
}
|
||||
|
||||
/// Calls the given unpacker with the content of the given sequence
|
||||
template <typename U, std::size_t... I>
|
||||
constexpr decltype(auto) unpack(std::integer_sequence<std::size_t, I...>,
|
||||
U&& unpacker) {
|
||||
return std::forward<U>(unpacker)(std::integral_constant<std::size_t, I>{}...);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
/// Calls the given unpacker with the content of the given sequenceable
|
||||
template <typename F, typename U, std::size_t... I>
|
||||
constexpr auto unpack(F&& first_sequenceable, U&& unpacker,
|
||||
std::integer_sequence<std::size_t, I...>)
|
||||
template <typename U, typename F, std::size_t... I>
|
||||
constexpr auto unpack_impl(U&& unpacker, F&& first_sequenceable,
|
||||
std::integer_sequence<std::size_t, I...>)
|
||||
-> decltype(std::forward<U>(unpacker)(
|
||||
get<I>(std::forward<F>(first_sequenceable))...)) {
|
||||
std::get<I>(std::forward<F>(first_sequenceable))...)) {
|
||||
(void)first_sequenceable;
|
||||
return std::forward<U>(unpacker)(
|
||||
get<I>(std::forward<F>(first_sequenceable))...);
|
||||
}
|
||||
/// Calls the given unpacker with the content of the given sequenceable
|
||||
template <typename F, typename S, typename U, std::size_t... If,
|
||||
std::size_t... Is>
|
||||
constexpr auto unpack(F&& first_sequenceable, S&& second_sequenceable,
|
||||
U&& unpacker, std::integer_sequence<std::size_t, If...>,
|
||||
std::integer_sequence<std::size_t, Is...>)
|
||||
-> decltype(std::forward<U>(unpacker)(
|
||||
get<If>(std::forward<F>(first_sequenceable))...,
|
||||
get<Is>(std::forward<S>(second_sequenceable))...)) {
|
||||
(void)first_sequenceable;
|
||||
(void)second_sequenceable;
|
||||
return std::forward<U>(unpacker)(
|
||||
get<If>(std::forward<F>(first_sequenceable))...,
|
||||
get<Is>(std::forward<S>(second_sequenceable))...);
|
||||
}
|
||||
/// Calls the given unpacker with the content of the given sequenceable
|
||||
template <typename F, typename U>
|
||||
constexpr auto unpack(F&& first_sequenceable, U&& unpacker)
|
||||
-> decltype(unpack(std::forward<F>(first_sequenceable),
|
||||
std::forward<U>(unpacker),
|
||||
sequence_of(identify<decltype(first_sequenceable)>{}))) {
|
||||
return unpack(std::forward<F>(first_sequenceable), std::forward<U>(unpacker),
|
||||
sequence_of(identify<decltype(first_sequenceable)>{}));
|
||||
}
|
||||
/// Calls the given unpacker with the content of the given sequenceables
|
||||
template <typename F, typename S, typename U>
|
||||
constexpr auto unpack(F&& first_sequenceable, S&& second_sequenceable,
|
||||
U&& unpacker)
|
||||
-> decltype(unpack(std::forward<F>(first_sequenceable),
|
||||
std::forward<S>(second_sequenceable),
|
||||
std::forward<U>(unpacker),
|
||||
sequence_of(identity_of(first_sequenceable)),
|
||||
sequence_of(identity_of(second_sequenceable)))) {
|
||||
return unpack(std::forward<F>(first_sequenceable),
|
||||
std::forward<S>(second_sequenceable), std::forward<U>(unpacker),
|
||||
sequence_of(identity_of(first_sequenceable)),
|
||||
sequence_of(identity_of(second_sequenceable)));
|
||||
std::get<I>(std::forward<F>(first_sequenceable))...);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/// Adds the given type at the back of the left sequenceable
|
||||
template <typename Left, typename Element>
|
||||
constexpr auto push(Left&& left, Element&& element) {
|
||||
return unpack(std::forward<Left>(left), [&](auto&&... args) {
|
||||
return std::make_tuple(std::forward<decltype(args)>(args)...,
|
||||
std::forward<Element>(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 <typename Callable, typename TupleLike,
|
||||
typename Sequence = std::make_index_sequence<
|
||||
std::tuple_size<std::decay_t<TupleLike>>::value>>
|
||||
constexpr auto unpack(Callable&& obj, TupleLike&& tuple_like)
|
||||
-> decltype(detail::unpack_impl(std::forward<Callable>(obj),
|
||||
std::forward<TupleLike>(tuple_like),
|
||||
Sequence{})) {
|
||||
|
||||
/// Adds the element to the back of the identity
|
||||
template <typename... Args, typename Element>
|
||||
constexpr auto push(identity<Args...>, identity<Element>) noexcept {
|
||||
return identity<Args..., Element>{};
|
||||
}
|
||||
|
||||
/// Removes the first element from the identity
|
||||
template <typename First, typename... Rest>
|
||||
constexpr auto pop_first(identity<First, Rest...>) noexcept {
|
||||
return identity<Rest...>{};
|
||||
}
|
||||
|
||||
/// Returns the merged sequence
|
||||
template <typename Left>
|
||||
constexpr auto merge(Left&& left) {
|
||||
return std::forward<Left>(left);
|
||||
}
|
||||
/// Merges the left sequenceable with the right ones
|
||||
template <typename Left, typename Right, typename... Rest>
|
||||
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>(left), std::forward<Right>(right),
|
||||
[&](auto&&... args) {
|
||||
// Maybe use: template <template<typename...> class T,
|
||||
// typename... Args>
|
||||
return std::make_tuple(
|
||||
std::forward<decltype(args)>(args)...);
|
||||
}),
|
||||
std::forward<Rest>(rest)...);
|
||||
}
|
||||
/// Merges the left identity with the right ones
|
||||
template <typename... LeftArgs, typename... RightArgs, typename... Rest>
|
||||
constexpr auto merge(identity<LeftArgs...> /*left*/,
|
||||
identity<RightArgs...> /*right*/, Rest&&... rest) {
|
||||
return merge(identity<LeftArgs..., RightArgs...>{},
|
||||
std::forward<Rest>(rest)...);
|
||||
return detail::unpack_impl(std::forward<Callable>(obj),
|
||||
std::forward<TupleLike>(tuple_like), Sequence{});
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
@ -520,7 +520,7 @@ struct resume_state_callable {
|
||||
template <typename Frame, typename State>
|
||||
void resume_traversal_callable<Frame, State>::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
|
||||
|
||||
@ -192,10 +192,10 @@ struct flat_arraylizer {
|
||||
template <typename C, typename... T>
|
||||
constexpr auto apply_spread_impl(std::true_type, C&& callable, T&&... args)
|
||||
-> decltype(
|
||||
traits::unpack(std::tuple_cat(undecorate(std::forward<T>(args))...),
|
||||
std::forward<C>(callable))) {
|
||||
return traits::unpack(std::tuple_cat(undecorate(std::forward<T>(args))...),
|
||||
std::forward<C>(callable));
|
||||
traits::unpack(std::forward<C>(callable),
|
||||
std::tuple_cat(undecorate(std::forward<T>(args))...))) {
|
||||
return traits::unpack(std::forward<C>(callable),
|
||||
std::tuple_cat(undecorate(std::forward<T>(args))...));
|
||||
}
|
||||
|
||||
/// Use the linear instantiation for variadic packs which don't
|
||||
@ -630,14 +630,14 @@ struct tuple_like_remapper<
|
||||
/// different types.
|
||||
template <typename Strategy, typename T, typename M>
|
||||
auto remap(Strategy, T&& container, M&& mapper) -> decltype(traits::unpack(
|
||||
std::forward<T>(container),
|
||||
std::declval<tuple_like_remapper<Strategy, typename std::decay<M>::type,
|
||||
typename std::decay<T>::type>>())) {
|
||||
typename std::decay<T>::type>>(),
|
||||
std::forward<T>(container))) {
|
||||
return traits::unpack(
|
||||
std::forward<T>(container),
|
||||
tuple_like_remapper<Strategy, typename std::decay<M>::type,
|
||||
typename std::decay<T>::type>{
|
||||
std::forward<M>(mapper)});
|
||||
std::forward<M>(mapper)},
|
||||
std::forward<T>(container));
|
||||
}
|
||||
} // end namespace tuple_like_remapping
|
||||
|
||||
|
||||
@ -49,27 +49,27 @@ constexpr void unused(T&&...) noexcept {
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t... I>
|
||||
auto forward_except_last_impl(T&& tuple,
|
||||
std::integer_sequence<std::size_t, I...>) {
|
||||
(void)tuple;
|
||||
return std::forward_as_tuple(std::get<I>(std::forward<T>(tuple))...);
|
||||
}
|
||||
|
||||
/// Forwards every element in the tuple except the last one
|
||||
template <typename T>
|
||||
auto forward_except_last(T&& sequenceable) {
|
||||
constexpr auto const size = pack_size_of(traits::identify<T>()) - 1U;
|
||||
constexpr auto const sequence = std::make_index_sequence<size>();
|
||||
|
||||
return traits::unpack(std::forward<T>(sequenceable),
|
||||
[](auto&&... args) {
|
||||
return std::forward_as_tuple(
|
||||
std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
sequence);
|
||||
return forward_except_last_impl(std::forward<T>(sequenceable), sequence);
|
||||
}
|
||||
|
||||
/// We are able to call the callable with the arguments given in the tuple
|
||||
template <typename T, typename... Args>
|
||||
auto partial_invoke_impl(std::true_type, T&& callable,
|
||||
std::tuple<Args...> args) {
|
||||
return traits::unpack(std::move(args), [&](auto&&... arg) {
|
||||
return std::forward<T>(callable)(std::forward<decltype(arg)>(arg)...);
|
||||
});
|
||||
return traits::unpack(std::forward<T>(callable), std::move(args));
|
||||
}
|
||||
|
||||
/// We were unable to call the callable with the arguments in the tuple.
|
||||
|
||||
@ -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<int> v{args...};
|
||||
return std::accumulate(v.begin(), v.end(), 0);
|
||||
});
|
||||
auto count = traits::unpack(
|
||||
[](auto... args) {
|
||||
std::vector<int> v{args...};
|
||||
return std::accumulate(v.begin(), v.end(), 0);
|
||||
},
|
||||
tp2);
|
||||
EXPECT_EQ(count, 20);
|
||||
}
|
||||
|
||||
TEST(recursion_tests, are_noncopyable_mergeable) {
|
||||
std::tuple<util::non_copyable> nc1, nc2, nc3;
|
||||
traits::merge(std::move(nc1), std::move(nc2), std::move(nc3));
|
||||
}
|
||||
|
||||
@ -49,9 +49,11 @@ template <typename... Args>
|
||||
auto supplier_of(Args&&... args) {
|
||||
return [values = std::make_tuple(std::forward<Args>(args)...)](
|
||||
auto&& promise) mutable {
|
||||
cti::detail::traits::unpack(std::move(values), [&](auto&&... passed) {
|
||||
promise.set_value(std::forward<decltype(passed)>(passed)...);
|
||||
});
|
||||
cti::detail::traits::unpack(
|
||||
[&](auto&&... passed) {
|
||||
promise.set_value(std::forward<decltype(passed)>(passed)...);
|
||||
},
|
||||
std::move(values));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user