Use a std::apply style unpack

* Some cleanup
This commit is contained in:
Denis Blank 2018-03-13 16:14:44 +01:00
parent 41c7cb008a
commit f091cbb079
13 changed files with 86 additions and 153 deletions

View File

@ -852,8 +852,8 @@ constexpr auto make_ready_continuable(FirstResult&& first_result,
std::forward<SecondResult>(second_result), std::forward<SecondResult>(second_result),
std::forward<Rest>(rest)...)]( std::forward<Rest>(rest)...)](
auto&& promise) mutable { auto&& promise) mutable {
detail::traits::unpack(result, detail::traits::unpack(std::forward<decltype(promise)>(promise),
std::forward<decltype(promise)>(promise)); result);
}); });
} }

View File

@ -231,12 +231,14 @@ inline auto sequenced_unpack_invoker() {
// the lambda. // the lambda.
using Next = decltype(next_callback); using Next = decltype(next_callback);
traits::unpack(std::move(result), [&](auto&&... types) { traits::unpack(
[&](auto&&... types) {
/// TODO Add inplace resolution here /// TODO Add inplace resolution here
invoke_no_except(std::forward<Next>(next_callback), invoke_no_except(std::forward<Next>(next_callback),
std::forward<decltype(types)>(types)...); std::forward<decltype(types)>(types)...);
}); },
std::move(result));
CONTINUABLE_BLOCK_TRY_END CONTINUABLE_BLOCK_TRY_END
}; };
} // namespace decoration } // namespace decoration
@ -277,12 +279,15 @@ void packed_dispatch(Executor&& executor, Invoker&& invoker, Args&&... args) {
invoker = std::forward<Invoker>(invoker), invoker = std::forward<Invoker>(invoker),
args = std::make_tuple(std::forward<Args>(args)...) args = std::make_tuple(std::forward<Args>(args)...)
]() mutable { ]() mutable {
traits::unpack(std::move(args), [&](auto&&... captured_args) { traits::unpack(
[&](auto&&... captured_args) {
// Just use the packed dispatch method which dispatches the work on // Just use the packed dispatch method which dispatches the work on
// the current thread. // the current thread.
packed_dispatch(types::this_thread_executor_tag{}, std::move(invoker), packed_dispatch(
types::this_thread_executor_tag{}, std::move(invoker),
std::forward<decltype(captured_args)>(captured_args)...); std::forward<decltype(captured_args)>(captured_args)...);
}); },
std::move(args));
}; };
// Pass the work callable object to the executor // Pass the work callable object to the executor

View File

@ -149,9 +149,11 @@ public:
} }
auto unbox() && { auto unbox() && {
return traits::unpack(unpack_lazy(std::move(args_)), [](auto&&... args) { return traits::unpack(
[](auto&&... args) {
return spread_this(std::forward<decltype(args)>(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...>>, constexpr auto finalize_impl(traits::identity<std::tuple<Args...>>,
Callback&& callback, Data&& data) { Callback&& callback, Data&& data) {
// Call the final callback with the cleaned result // Call the final callback with the cleaned result
return traits::unpack(unbox_continuables(std::forward<Data>(data)), return traits::unpack(std::forward<Callback>(callback),
std::forward<Callback>(callback)); unbox_continuables(std::forward<Data>(data)));
} }
struct hint_mapper { struct hint_mapper {

View File

@ -61,7 +61,7 @@ auto sequential_connect(Left&& left, Right&& right) {
return std::move(right).then([previous = std::make_tuple( return std::move(right).then([previous = std::make_tuple(
std::forward<decltype(args)>(args)...)]( std::forward<decltype(args)>(args)...)](
auto&&... args) mutable { auto&&... args) mutable {
return traits::merge( return std::tuple_cat(
std::move(previous), std::move(previous),
std::make_tuple(std::forward<decltype(args)>(args)...)); std::make_tuple(std::forward<decltype(args)>(args)...));
}); });

View File

@ -56,7 +56,7 @@ template <typename... LeftArgs, typename... RightArgs>
auto chain_connection(std::tuple<LeftArgs...> leftPack, auto chain_connection(std::tuple<LeftArgs...> leftPack,
std::tuple<RightArgs...> rightPack) { 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 /// Normalizes a continuation to a tuple holding an arbitrary count of

View File

@ -58,6 +58,8 @@
#define CONTINUABLE_HAS_CXX17_VOID_T #define CONTINUABLE_HAS_CXX17_VOID_T
#else #else
// Generic feature detection based on __has_feature // 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(__has_feature)
#if !defined(CONTINUABLE_HAS_CXX17_CONSTEXPR_IF) && \ #if !defined(CONTINUABLE_HAS_CXX17_CONSTEXPR_IF) && \
__has_feature(cxx_if_constexpr) __has_feature(cxx_if_constexpr)

View File

@ -77,14 +77,15 @@ struct promisify_helper {
auto&& promise) mutable { auto&& promise) mutable {
traits::unpack( traits::unpack(
std::move(args), [promise = std::forward<decltype(promise)>(promise)]( [promise = std::forward<decltype(promise)>(promise)](
auto&&... args) mutable { auto&&... args) mutable {
Evaluator<std::decay_t<decltype(promise)>> evaluator{ Evaluator<std::decay_t<decltype(promise)>> evaluator{
std::move(promise)}; std::move(promise)};
util::invoke(std::forward<decltype(args)>(args)..., util::invoke(std::forward<decltype(args)>(args)...,
std::move(evaluator)); std::move(evaluator));
}); },
std::move(args));
}); });
} }
}; };

View File

@ -32,7 +32,6 @@
#define CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED #define CONTINUABLE_DETAIL_TRAITS_HPP_INCLUDED
#include <cstdint> #include <cstdint>
#include <initializer_list>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@ -184,108 +183,33 @@ constexpr auto static_if(Type&& type, Check&& check,
std::forward<FalseCallback>(falseCallback)); std::forward<FalseCallback>(falseCallback));
} }
/// Calls the given unpacker with the content of the given sequence namespace detail {
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>{}...);
}
/// Calls the given unpacker with the content of the given sequenceable /// Calls the given unpacker with the content of the given sequenceable
template <typename F, typename U, std::size_t... I> template <typename U, typename F, std::size_t... I>
constexpr auto unpack(F&& first_sequenceable, U&& unpacker, constexpr auto unpack_impl(U&& unpacker, F&& first_sequenceable,
std::integer_sequence<std::size_t, I...>) std::integer_sequence<std::size_t, I...>)
-> decltype(std::forward<U>(unpacker)( -> decltype(std::forward<U>(unpacker)(
get<I>(std::forward<F>(first_sequenceable))...)) { std::get<I>(std::forward<F>(first_sequenceable))...)) {
(void)first_sequenceable; (void)first_sequenceable;
return std::forward<U>(unpacker)( return std::forward<U>(unpacker)(
get<I>(std::forward<F>(first_sequenceable))...); std::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)));
} }
} // namespace detail
/// Adds the given type at the back of the left sequenceable /// Calls the given callable object with the content of the given sequenceable
template <typename Left, typename Element> ///
constexpr auto push(Left&& left, Element&& element) { /// \note We can't use std::apply here since this implementation is SFINAE
return unpack(std::forward<Left>(left), [&](auto&&... args) { /// aware and the std version not! This would lead to compilation errors.
return std::make_tuple(std::forward<decltype(args)>(args)..., template <typename Callable, typename TupleLike,
std::forward<Element>(element)); 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 return detail::unpack_impl(std::forward<Callable>(obj),
template <typename... Args, typename Element> std::forward<TupleLike>(tuple_like), Sequence{});
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)...);
} }
namespace detail { namespace detail {

View File

@ -520,7 +520,7 @@ struct resume_state_callable {
template <typename Frame, typename State> template <typename Frame, typename State>
void resume_traversal_callable<Frame, State>::operator()() { void resume_traversal_callable<Frame, State>::operator()() {
auto hierarchy = std::tuple_cat(std::make_tuple(frame_), state_); 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 /// Gives access to types related to the traversal frame

View File

@ -192,10 +192,10 @@ struct flat_arraylizer {
template <typename C, typename... T> template <typename C, typename... T>
constexpr auto apply_spread_impl(std::true_type, C&& callable, T&&... args) constexpr auto apply_spread_impl(std::true_type, C&& callable, T&&... args)
-> decltype( -> decltype(
traits::unpack(std::tuple_cat(undecorate(std::forward<T>(args))...), traits::unpack(std::forward<C>(callable),
std::forward<C>(callable))) { std::tuple_cat(undecorate(std::forward<T>(args))...))) {
return traits::unpack(std::tuple_cat(undecorate(std::forward<T>(args))...), return traits::unpack(std::forward<C>(callable),
std::forward<C>(callable)); std::tuple_cat(undecorate(std::forward<T>(args))...));
} }
/// Use the linear instantiation for variadic packs which don't /// Use the linear instantiation for variadic packs which don't
@ -630,14 +630,14 @@ struct tuple_like_remapper<
/// different types. /// different types.
template <typename Strategy, typename T, typename M> template <typename Strategy, typename T, typename M>
auto remap(Strategy, T&& container, M&& mapper) -> decltype(traits::unpack( 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, 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( return traits::unpack(
std::forward<T>(container),
tuple_like_remapper<Strategy, typename std::decay<M>::type, tuple_like_remapper<Strategy, typename std::decay<M>::type,
typename std::decay<T>::type>{ typename std::decay<T>::type>{
std::forward<M>(mapper)}); std::forward<M>(mapper)},
std::forward<T>(container));
} }
} // end namespace tuple_like_remapping } // end namespace tuple_like_remapping

View File

@ -49,27 +49,27 @@ constexpr void unused(T&&...) noexcept {
} }
namespace detail { 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 /// Forwards every element in the tuple except the last one
template <typename T> template <typename T>
auto forward_except_last(T&& sequenceable) { auto forward_except_last(T&& sequenceable) {
constexpr auto const size = pack_size_of(traits::identify<T>()) - 1U; constexpr auto const size = pack_size_of(traits::identify<T>()) - 1U;
constexpr auto const sequence = std::make_index_sequence<size>(); constexpr auto const sequence = std::make_index_sequence<size>();
return traits::unpack(std::forward<T>(sequenceable), return forward_except_last_impl(std::forward<T>(sequenceable), sequence);
[](auto&&... args) {
return std::forward_as_tuple(
std::forward<decltype(args)>(args)...);
},
sequence);
} }
/// We are able to call the callable with the arguments given in the tuple /// We are able to call the callable with the arguments given in the tuple
template <typename T, typename... Args> template <typename T, typename... Args>
auto partial_invoke_impl(std::true_type, T&& callable, auto partial_invoke_impl(std::true_type, T&& callable,
std::tuple<Args...> args) { std::tuple<Args...> args) {
return traits::unpack(std::move(args), [&](auto&&... arg) { return traits::unpack(std::forward<T>(callable), std::move(args));
return std::forward<T>(callable)(std::forward<decltype(arg)>(arg)...);
});
} }
/// We were unable to call the callable with the arguments in the tuple. /// We were unable to call the callable with the arguments in the tuple.

View File

@ -33,21 +33,18 @@ using namespace cti::detail;
TEST(regression_tests, are_multiple_args_mergeable) { TEST(regression_tests, are_multiple_args_mergeable) {
{ {
auto tp = std::make_tuple(1, 2, 3); 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), 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), std::make_tuple(1, 2, 3),
std::make_tuple(1, 2, 3, 4)); std::make_tuple(1, 2, 3, 4));
auto count = traits::unpack(tp2, [](auto... args) { auto count = traits::unpack(
[](auto... args) {
std::vector<int> v{args...}; std::vector<int> v{args...};
return std::accumulate(v.begin(), v.end(), 0); return std::accumulate(v.begin(), v.end(), 0);
}); },
tp2);
EXPECT_EQ(count, 20); 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));
}

View File

@ -49,9 +49,11 @@ template <typename... Args>
auto supplier_of(Args&&... args) { auto supplier_of(Args&&... args) {
return [values = std::make_tuple(std::forward<Args>(args)...)]( return [values = std::make_tuple(std::forward<Args>(args)...)](
auto&& promise) mutable { auto&& promise) mutable {
cti::detail::traits::unpack(std::move(values), [&](auto&&... passed) { cti::detail::traits::unpack(
[&](auto&&... passed) {
promise.set_value(std::forward<decltype(passed)>(passed)...); promise.set_value(std::forward<decltype(passed)>(passed)...);
}); },
std::move(values));
}; };
} }