Started to implement combined path callables

This commit is contained in:
Denis Blank 2017-10-03 02:25:20 +02:00
parent 7dcd18c964
commit 52cf1ab929
5 changed files with 90 additions and 23 deletions

View File

@ -65,6 +65,11 @@ public:
void operator()(Args... args) {
data_(std::move(args)...);
}
/// Resolves the continuation with the given exception
void operator()(detail::types::dispatch_error_tag tag,
detail::types::error_type exception) {
data_(tag, std::move(exception));
}
/// Resolves the continuation with the given values
void set_value(Args... args) {

View File

@ -259,6 +259,39 @@ void packed_dispatch(Executor&& executor, Invoker&& invoker, Args&&... args) {
}
namespace callbacks {
template <typename Base>
struct error_handler_base {
void operator()(types::dispatch_error_tag, types::error_type error) {
// Just invoke the error handler, cancel the calling hierarchy after
auto invoker = [](typename Base::CallbackT&& callback,
types::error_type&& error) {
std::move(callback)(std::move(error));
};
// Invoke the error handler
packed_dispatch(
std::move(static_cast<Base*>(this)->executor_), std::move(invoker),
std::move(static_cast<Base*>(this)->callback_), std::move(error));
}
};
template <typename Base, typename = void>
struct result_callback_error_base {
/// The operator which is called when an error occurred
void operator()(types::dispatch_error_tag tag, types::error_type error) {
// Forward the error to the next callback
std::move(static_cast<Base*>(this)->next_callback_)(tag, std::move(error));
}
};
template <typename Base>
struct result_callback_error_base<
Base, std::enable_if_t<util::is_invokable<
typename Base::Callback,
std::tuple<types::dispatch_error_tag, types::error_type>>::value>>
: error_handler_base<Base> {
using error_handler_base<Base>::operator();
};
template <typename Hint, typename Callback, typename Executor,
typename NextCallback>
struct result_callback;
@ -266,11 +299,23 @@ struct result_callback;
template <typename... Args, typename Callback, typename Executor,
typename NextCallback>
struct result_callback<hints::signature_hint_tag<Args...>, Callback, Executor,
NextCallback> {
NextCallback>
: result_callback_error_base<
result_callback<hints::signature_hint_tag<Args...>, Callback,
Executor, NextCallback>> {
using CallbackT = Callback;
Callback callback_;
Executor executor_;
NextCallback next_callback_;
explicit result_callback(Callback callback, Executor executor,
NextCallback next_callback)
: callback_(std::move(callback)), executor_(std::move(executor)),
next_callback_(std::move(next_callback)) {
}
/// The operator which is called when the result was provided
void operator()(Args... args) {
// In order to retrieve the correct decorator we must know what the
@ -287,11 +332,7 @@ struct result_callback<hints::signature_hint_tag<Args...>, Callback, Executor,
std::move(args)...);
}
/// The operator which is called when an error occurred
void operator()(types::dispatch_error_tag tag, types::error_type error) {
// Forward the error to the next callback
std::move(next_callback_)(tag, std::move(error));
}
using result_callback_error_base<result_callback>::operator();
/// Resolves the continuation with the given values
void set_value(Args... args) {
@ -311,29 +352,29 @@ struct error_callback;
template <typename... Args, typename Callback, typename Executor,
typename NextCallback>
struct error_callback<hints::signature_hint_tag<Args...>, Callback, Executor,
NextCallback> {
NextCallback>
: error_handler_base<error_callback<hints::signature_hint_tag<Args...>,
Callback, Executor, NextCallback>> {
using CallbackT = Callback;
Callback callback_;
Executor executor_;
NextCallback next_callback_;
explicit error_callback(Callback callback, Executor executor,
NextCallback next_callback)
: callback_(std::move(callback)), executor_(std::move(executor)),
next_callback_(std::move(next_callback)) {
}
/// The operator which is called when the result was provided
void operator()(Args... args) {
// Forward the arguments to the next callback
std::move(next_callback_)(std::move(args)...);
}
/// The operator which is called when an error occurred
void operator()(types::dispatch_error_tag /*tag*/, types::error_type error) {
// Just invoke the error handler, cancel the calling hierarchy after
auto invoker = [](Callback&& callback, types::error_type&& error) {
std::move(callback)(std::move(error));
};
// Invoke the error handler
packed_dispatch(std::move(executor_), std::move(invoker),
std::move(callback_), std::move(error));
}
using error_handler_base<error_callback>::operator();
/// Resolves the continuation with the given values
void set_value(Args... args) {

View File

@ -34,7 +34,9 @@
#include <future>
#include <continuable/detail/api.hpp>
#include <continuable/detail/features.hpp>
#include <continuable/detail/hints.hpp>
#include <continuable/detail/types.hpp>
namespace cti {
namespace detail {
@ -90,6 +92,14 @@ public:
void operator()(Args... args) {
this->resolve(promise_, std::move(args)...);
}
#if !defined(CONTINUABLE_WITH_CUSTOM_ERROR_TYPE) && \
!defined(CONTINUABLE_WITH_NO_EXCEPTIONS)
/// Resolves the promise through the exception
void operator()(types::dispatch_error_tag, types::error_type error) {
promise_.set_exception(error);
}
#endif
/// Returns the future from the promise
auto get_future() {
return promise_.get_future();

View File

@ -73,10 +73,10 @@ struct is_invokable_impl<
/// arguments inside lambda closures.
///
/// ```cpp
/// traits::is_invokable_t<object, std::tuple<Args...>>
/// traits::is_invokable<object, std::tuple<Args...>>
/// ```
template <typename T, typename Args>
using is_invokable_t = typename detail::is_invokable_impl<T, Args>::type;
using is_invokable = typename detail::is_invokable_impl<T, Args>::type;
namespace detail {
/// Forwards every element in the tuple except the last one
@ -124,7 +124,7 @@ auto partial_invoke_impl(std::false_type, T&& callable,
auto next = forward_except_last(std::move(args));
// Test whether we are able to call the function with the given tuple
is_invokable_t<decltype(callable), decltype(next)> is_invokable;
is_invokable<decltype(callable), decltype(next)> is_invokable;
return partial_invoke_impl(is_invokable, std::forward<T>(callable),
std::move(next));
@ -157,7 +157,7 @@ auto partial_invoke_impl_shortcut(std::false_type failed, T&& callable,
template <typename T, typename... Args>
auto partial_invoke(T&& callable, Args&&... args) {
// Test whether we are able to call the function with the given arguments.
is_invokable_t<decltype(callable), std::tuple<Args...>> is_invokable;
is_invokable<decltype(callable), std::tuple<Args...>> is_invokable;
// The implementation is done in a shortcut way so there are less
// type instantiations needed to call the callable with its full signature.

View File

@ -57,7 +57,18 @@ static cti::continuable<std::string> http_request3(std::string url) {
};
}
struct my_callable {
void operator()(std::string) {
// ...
}
void operator()(cti::dispatch_error_tag, cti::error_type) {
// ...
}
};
int main(int, char**) {
http_request("github.com").then(my_callable{});
http_request("github.com")
.then([](std::string) {
// ...