Fix the build

This commit is contained in:
Denis Blank 2018-11-27 16:38:19 +01:00
parent f1f9d61952
commit bb7112eec2
2 changed files with 143 additions and 58 deletions

View File

@ -326,8 +326,8 @@ constexpr auto invoker_of(traits::identity<std::tuple<Args...>>) {
inline auto exception_invoker_of(traits::identity<void>) noexcept { inline auto exception_invoker_of(traits::identity<void>) noexcept {
return [](auto&& callback, auto&& next_callback, auto&&... args) { return [](auto&& callback, auto&& next_callback, auto&&... args) {
CONTINUABLE_BLOCK_TRY_BEGIN CONTINUABLE_BLOCK_TRY_BEGIN
util::partial_invoke(std::forward<decltype(callback)>(callback), util::invoke(std::forward<decltype(callback)>(callback),
std::forward<decltype(args)>(args)...); std::forward<decltype(args)>(args)...);
// The legacy behaviour is not to proceed the chain // The legacy behaviour is not to proceed the chain
// on the first invoked failure handler // on the first invoked failure handler
@ -336,9 +336,81 @@ inline auto exception_invoker_of(traits::identity<void>) noexcept {
}; };
} }
template <typename Other> /*template <typename... Args>
auto exception_invoker_of(Other other) noexcept { auto exception_invoker_of(traits::identity<result<Args...>> id) noexcept {
return invoker_of(other); return invoker_of(id);
}*/
/// - empty_result -> <cancel>
inline auto exception_invoker_of(traits::identity<empty_result>) {
return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) {
(void)next_callback;
CONTINUABLE_BLOCK_TRY_BEGIN
empty_result result =
util::invoke(std::forward<decltype(callback)>(callback),
std::forward<decltype(args)>(args)...);
// Don't invoke anything here since returning an empty result
// cancels the asynchronous chain effectively.
(void)result;
CONTINUABLE_BLOCK_TRY_END
},
traits::identity<>{});
}
/// - exceptional_result -> <throw>
inline auto exception_invoker_of(traits::identity<exceptional_result>) {
return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) {
util::unused(callback, next_callback, args...);
CONTINUABLE_BLOCK_TRY_BEGIN
exceptional_result result =
util::invoke(std::forward<decltype(callback)>(callback),
std::forward<decltype(args)>(args)...);
// Forward the exception to the next available handler
invoke_no_except(std::forward<decltype(next_callback)>(next_callback),
exception_arg_t{},
std::move(result).get_exception());
CONTINUABLE_BLOCK_TRY_END
},
traits::identity<>{});
}
/// - result<?...> -> next_callback(?...)
template <typename... Args>
auto exception_invoker_of(traits::identity<result<Args...>>) {
return make_invoker(
[](auto&& callback, auto&& next_callback, auto&&... args) {
CONTINUABLE_BLOCK_TRY_BEGIN
result<Args...> result =
util::invoke(std::forward<decltype(callback)>(callback),
std::forward<decltype(args)>(args)...);
if (result.is_value()) {
// Workaround for MSVC not capturing the reference
// correctly inside the lambda.
using Next = decltype(next_callback);
result_trait<Args...>::visit(
std::move(result), //
[&](auto&&... values) {
invoke_no_except(std::forward<Next>(next_callback),
std::forward<decltype(values)>(values)...);
});
} else if (result.is_exception()) {
// Forward the exception to the next available handler
invoke_no_except(
std::forward<decltype(next_callback)>(next_callback),
exception_arg_t{}, std::move(result).get_exception());
}
// Otherwise the result is empty and we are cancelling our
// asynchronous chain.
CONTINUABLE_BLOCK_TRY_END
},
traits::identity<Args...>{});
} }
#undef CONTINUABLE_BLOCK_TRY_BEGIN #undef CONTINUABLE_BLOCK_TRY_BEGIN
@ -587,16 +659,25 @@ next_hint_of(std::integral_constant<handle_results, handle_results::no>,
return current; return current;
} }
namespace detail {
template <typename Callable>
struct exception_stripper_proxy {
Callable callable_;
template <typename... Args>
auto operator()(exception_arg_t, Args&&... args)
-> decltype(util::invoke(std::declval<Callable>(), //
std::declval<Args>()...)) {
return util::invoke(std::move(callable_), //
std::forward<decltype(args)>(args)...);
};
};
} // namespace detail
/// Removes the exception_arg_t from the arguments passed to the given callable /// Removes the exception_arg_t from the arguments passed to the given callable
template <typename Callable> template <typename Callable>
auto strip_exception_arg(Callable&& callable) { auto strip_exception_arg(Callable&& callable) {
return [callable = std::forward<Callable>(callable)] // using proxy = detail::exception_stripper_proxy<traits::unrefcv_t<Callable>>;
(exception_arg_t, auto&&... args) mutable return proxy{std::forward<Callable>(callable)};
-> decltype(util::invoke(std::declval<Callable>(), //
std::declval<decltype(args)>()...)) {
return util::invoke(std::move(callable), //
std::forward<decltype(args)>(args)...);
};
} }
/// Chains a callback together with a continuation and returns a continuation: /// Chains a callback together with a continuation and returns a continuation:

View File

@ -64,59 +64,62 @@ auto forward_except_last(T&& sequenceable) {
return forward_except_last_impl(std::forward<T>(sequenceable), 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 <std::size_t Keep>
template <typename T, typename... Args> struct invocation_env {
auto partial_invoke_impl(std::true_type, T&& callable, /// We are able to call the callable with the arguments given in the tuple
std::tuple<Args...> args) { template <typename T, typename... Args>
return traits::unpack(std::forward<T>(callable), std::move(args)); static auto partial_invoke_impl(std::true_type, T&& callable,
} std::tuple<Args...> args) {
return traits::unpack(std::forward<T>(callable), std::move(args));
}
/// 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.
/// Remove the last argument from the tuple and try it again. /// Remove the last argument from the tuple and try it again.
template <typename T, typename... Args> template <typename T, typename... Args>
auto partial_invoke_impl(std::false_type, T&& callable, static auto partial_invoke_impl(std::false_type, T&& callable,
std::tuple<Args...> args) { std::tuple<Args...> args) {
// If you are encountering this assertion you tried to attach a callback // If you are encountering this assertion you tried to attach a callback
// which can't accept the arguments of the continuation. // which can't accept the arguments of the continuation.
// //
// ```cpp // ```cpp
// continuable<int, int> c; // continuable<int, int> c;
// std::move(c).then([](std::vector<int> v) { /*...*/ }) // std::move(c).then([](std::vector<int> v) { /*...*/ })
// ``` // ```
static_assert( static_assert(
sizeof...(Args) > 0, sizeof...(Args) > Keep,
"There is no way to call the given object with these arguments!"); "There is no way to call the given object with these arguments!");
// Remove the last argument from the tuple // Remove the last argument from the tuple
auto next = forward_except_last(std::move(args)); auto next = forward_except_last(std::move(args));
// Test whether we are able to call the function with the given tuple // Test whether we are able to call the function with the given tuple
traits::is_invokable_from_tuple<decltype(callable), decltype(next)> traits::is_invokable_from_tuple<decltype(callable), decltype(next)>
is_invokable; is_invokable;
return partial_invoke_impl(is_invokable, std::forward<T>(callable), return partial_invoke_impl(is_invokable, std::forward<T>(callable),
std::move(next)); std::move(next));
} }
/// Shortcut - we can call the callable directly /// Shortcut - we can call the callable directly
template <typename T, typename... Args> template <typename T, typename... Args>
auto partial_invoke_impl_shortcut(std::true_type, T&& callable, static auto partial_invoke_impl_shortcut(std::true_type, T&& callable,
Args&&... args) { Args&&... args) {
return std::forward<T>(callable)(std::forward<Args>(args)...); return std::forward<T>(callable)(std::forward<Args>(args)...);
} }
/// Failed shortcut - we were unable to invoke the callable with the /// Failed shortcut - we were unable to invoke the callable with the
/// original arguments. /// original arguments.
template <typename T, typename... Args> template <typename T, typename... Args>
auto partial_invoke_impl_shortcut(std::false_type failed, T&& callable, static auto partial_invoke_impl_shortcut(std::false_type failed, T&& callable,
Args&&... args) { Args&&... args) {
// Our shortcut failed, convert the arguments into a forwarding tuple // Our shortcut failed, convert the arguments into a forwarding tuple
return partial_invoke_impl( return partial_invoke_impl(
failed, std::forward<T>(callable), failed, std::forward<T>(callable),
std::forward_as_tuple(std::forward<Args>(args)...)); std::forward_as_tuple(std::forward<Args>(args)...));
} }
};
} // namespace detail } // namespace detail
/// Partially invokes the given callable with the given arguments. /// Partially invokes the given callable with the given arguments.
@ -131,7 +134,8 @@ template <typename T, typename... Args>
// The implementation is done in a shortcut way so there are less // The implementation is done in a shortcut way so there are less
// type instantiations needed to call the callable with its full signature. // type instantiations needed to call the callable with its full signature.
return detail::partial_invoke_impl_shortcut( using env = detail::invocation_env<0U>;
return env::partial_invoke_impl_shortcut(
is_invokable, std::forward<T>(callable), std::forward<Args>(args)...); is_invokable, std::forward<T>(callable), std::forward<Args>(args)...);
} }