Unverified Commit ce63edff authored by Noir's avatar Noir Committed by GitHub

Merge pull request #1272

Modernize functor_attachable and allow non-const default handlers
parents a920cf3d 3731fc84
...@@ -20,6 +20,8 @@ is based on [Keep a Changelog](https://keepachangelog.com). ...@@ -20,6 +20,8 @@ is based on [Keep a Changelog](https://keepachangelog.com).
properly back off, causing high CPU load due to spinning and in some scenarios properly back off, causing high CPU load due to spinning and in some scenarios
never recovering. This issue has been resolved by properly handling never recovering. This issue has been resolved by properly handling
`SSL_ERROR_WANT_READ` on the transport (#1060). `SSL_ERROR_WANT_READ` on the transport (#1060).
- Scheduled actors now accept default handlers for down messages etc. with
non-const apply operator such as lambda expressions declared as `mutable`.
### Removed ### Removed
......
...@@ -324,6 +324,7 @@ caf_add_component( ...@@ -324,6 +324,7 @@ caf_add_component(
response_promise response_promise
result result
save_inspector save_inspector
scheduled_actor
selective_streaming selective_streaming
serial_reply serial_reply
serialization serialization
......
...@@ -11,41 +11,31 @@ ...@@ -11,41 +11,31 @@
namespace caf::detail { namespace caf::detail {
template <class F,
int Args = tl_size<typename get_callable_trait<F>::arg_types>::value>
struct functor_attachable : attachable {
static_assert(Args == 1 || Args == 2,
"Only 0, 1 or 2 arguments for F are supported");
F functor_;
functor_attachable(F arg) : functor_(std::move(arg)) {
// nop
}
void actor_exited(const error& fail_state, execution_unit*) override {
functor_(fail_state);
}
static constexpr size_t token_type = attachable::token::anonymous;
};
template <class F> template <class F>
struct functor_attachable<F, 2> : attachable { class functor_attachable : public attachable {
F functor_; public:
functor_attachable(F arg) : functor_(std::move(arg)) { static constexpr size_t num_args
// nop = tl_size<typename get_callable_trait<F>::arg_types>::value;
}
void actor_exited(const error& x, execution_unit* y) override {
functor_(x, y);
}
};
template <class F> static_assert(num_args < 3, "Only 0, 1 or 2 arguments for F are supported");
struct functor_attachable<F, 0> : attachable {
F functor_; explicit functor_attachable(F fn) : fn_(std::move(fn)) {
functor_attachable(F arg) : functor_(std::move(arg)) {
// nop // nop
} }
void actor_exited(const error&, execution_unit*) override {
functor_(); void actor_exited(const error& fail_state, execution_unit* host) override {
if constexpr (num_args == 0)
fn_();
else if constexpr (num_args == 1)
fn_(fail_state);
else
fn_(fail_state, host);
} }
static constexpr size_t token_type = attachable::token::anonymous;
private:
F fn_;
}; };
} // namespace caf::detail } // namespace caf::detail
...@@ -294,10 +294,12 @@ public: ...@@ -294,10 +294,12 @@ public:
/// Sets a custom handler for unexpected messages. /// Sets a custom handler for unexpected messages.
template <class F> template <class F>
typename std::enable_if<std::is_convertible< std::enable_if_t<std::is_invocable_r_v<skippable_result, F, message&>>
F, std::function<skippable_result(message&)>>::value>::type
set_default_handler(F fun) { set_default_handler(F fun) {
default_handler_ = [=](scheduled_actor*, message& xs) { return fun(xs); }; using std::move;
default_handler_ = [fn{move(fun)}](scheduled_actor*, message& xs) mutable {
return fn(xs);
};
} }
/// Sets a custom handler for error messages. /// Sets a custom handler for error messages.
...@@ -309,9 +311,11 @@ public: ...@@ -309,9 +311,11 @@ public:
} }
/// Sets a custom handler for error messages. /// Sets a custom handler for error messages.
template <class T> template <class F>
auto set_error_handler(T fun) -> decltype(fun(std::declval<error&>())) { std::enable_if_t<std::is_invocable_v<F, error&>> set_error_handler(F fun) {
set_error_handler([fun](scheduled_actor*, error& x) { fun(x); }); error_handler_ = [fn{std::move(fun)}](scheduled_actor*, error& x) mutable {
fn(x);
};
} }
/// Sets a custom handler for down messages. /// Sets a custom handler for down messages.
...@@ -323,9 +327,12 @@ public: ...@@ -323,9 +327,12 @@ public:
} }
/// Sets a custom handler for down messages. /// Sets a custom handler for down messages.
template <class T> template <class F>
auto set_down_handler(T fun) -> decltype(fun(std::declval<down_msg&>())) { std::enable_if_t<std::is_invocable_v<F, down_msg&>> set_down_handler(F fun) {
set_down_handler([fun](scheduled_actor*, down_msg& x) { fun(x); }); using std::move;
down_handler_ = [fn{move(fun)}](scheduled_actor*, down_msg& x) mutable {
fn(x);
};
} }
/// Sets a custom handler for node down messages. /// Sets a custom handler for node down messages.
...@@ -337,11 +344,13 @@ public: ...@@ -337,11 +344,13 @@ public:
} }
/// Sets a custom handler for down messages. /// Sets a custom handler for down messages.
template <class T> template <class F>
auto set_node_down_handler(T fun) std::enable_if_t<std::is_invocable_v<F, node_down_msg&>>
-> decltype(fun(std::declval<node_down_msg&>())) { set_node_down_handler(F fun) {
set_node_down_handler( node_down_handler_ = [fn{std::move(fun)}](scheduled_actor*,
[fun](scheduled_actor*, node_down_msg& x) { fun(x); }); node_down_msg& x) mutable {
fn(x);
};
} }
/// Sets a custom handler for error messages. /// Sets a custom handler for error messages.
...@@ -353,9 +362,12 @@ public: ...@@ -353,9 +362,12 @@ public:
} }
/// Sets a custom handler for exit messages. /// Sets a custom handler for exit messages.
template <class T> template <class F>
auto set_exit_handler(T fun) -> decltype(fun(std::declval<exit_msg&>())) { std::enable_if_t<std::is_invocable_v<F, exit_msg&>> set_exit_handler(F fun) {
set_exit_handler([fun](scheduled_actor*, exit_msg& x) { fun(x); }); using std::move;
exit_handler_ = [fn{move(fun)}](scheduled_actor*, exit_msg& x) mutable {
fn(x);
};
} }
#ifdef CAF_ENABLE_EXCEPTIONS #ifdef CAF_ENABLE_EXCEPTIONS
...@@ -371,11 +383,12 @@ public: ...@@ -371,11 +383,12 @@ public:
/// Sets a custom exception handler for this actor. If multiple handlers are /// Sets a custom exception handler for this actor. If multiple handlers are
/// defined, only the functor that was added *last* is being executed. /// defined, only the functor that was added *last* is being executed.
template <class F> template <class F>
typename std::enable_if<std::is_convertible< std::enable_if_t<std::is_invocable_r_v<error, F, std::exception_ptr&>>
F, std::function<error(std::exception_ptr&)>>::value>::type set_exception_handler(F fun) {
set_exception_handler(F f) { exception_handler_ = [fn{std::move(fun)}](scheduled_actor*,
set_exception_handler( std::exception_ptr& x) mutable {
[f](scheduled_actor*, std::exception_ptr& x) { return f(x); }); return fn(x);
};
} }
#endif // CAF_ENABLE_EXCEPTIONS #endif // CAF_ENABLE_EXCEPTIONS
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE scheduled_actor
#include "caf/scheduled_actor.hpp"
#include "caf/test/dsl.hpp"
using namespace caf;
#define ASSERT_COMPILES(expr, msg) \
static_assert(std::is_void_v<decltype(expr)>, msg);
namespace {
constexpr scheduled_actor* nil_actor = nullptr;
// -- compile-time checks for set_default_handler ------------------------------
struct mutable_default_fn {
skippable_result operator()(message&) {
return {};
}
};
ASSERT_COMPILES(nil_actor->set_default_handler(mutable_default_fn{}),
"set_default_handler must accept mutable function objects");
struct const_default_fn {
skippable_result operator()(message&) const {
return {};
}
};
ASSERT_COMPILES(nil_actor->set_default_handler(const_default_fn{}),
"set_default_handler must accept const function objects");
// -- compile-time checks for set_error_handler --------------------------------
struct mutable_error_fn {
void operator()(error&) {
// nop
}
};
ASSERT_COMPILES(nil_actor->set_error_handler(mutable_error_fn{}),
"set_error_handler must accept mutable function objects");
struct const_error_fn {
void operator()(error&) const {
// nop
}
};
ASSERT_COMPILES(nil_actor->set_error_handler(const_error_fn{}),
"set_error_handler must accept const function objects");
// -- compile-time checks for set_down_handler ---------------------------------
struct mutable_down_fn {
void operator()(down_msg&) {
// nop
}
};
ASSERT_COMPILES(nil_actor->set_down_handler(mutable_down_fn{}),
"set_down_handler must accept mutable function objects");
struct const_down_fn {
void operator()(down_msg&) const {
// nop
}
};
ASSERT_COMPILES(nil_actor->set_down_handler(const_down_fn{}),
"set_down_handler must accept const function objects");
// -- compile-time checks for set_node_down_handler ----------------------------
struct mutable_node_down_fn {
void operator()(node_down_msg&) {
// nop
}
};
ASSERT_COMPILES(nil_actor->set_node_down_handler(mutable_node_down_fn{}),
"set_node_down_handler must accept mutable function objects");
struct const_node_down_fn {
void operator()(node_down_msg&) const {
// nop
}
};
ASSERT_COMPILES(nil_actor->set_node_down_handler(const_node_down_fn{}),
"set_node_down_handler must accept const function objects");
// -- compile-time checks for set_exit_handler ---------------------------------
struct mutable_exit_fn {
void operator()(exit_msg&) {
// nop
}
};
ASSERT_COMPILES(nil_actor->set_exit_handler(mutable_exit_fn{}),
"set_exit_handler must accept mutable function objects");
struct const_exit_fn {
void operator()(exit_msg&) const {
// nop
}
};
ASSERT_COMPILES(nil_actor->set_exit_handler(const_exit_fn{}),
"set_exit_handler must accept const function objects");
// -- compile-time checks for set_exception_handler ----------------------------
#ifdef CAF_ENABLE_EXCEPTIONS
struct mutable_exception_fn {
error operator()(std::exception_ptr&) {
return {};
}
};
ASSERT_COMPILES(nil_actor->set_exception_handler(mutable_exception_fn{}),
"set_exception_handler must accept mutable function objects");
struct const_exception_fn {
error operator()(std::exception_ptr&) const {
return {};
}
};
ASSERT_COMPILES(nil_actor->set_exception_handler(const_exception_fn{}),
"set_exception_handler must accept const function objects");
#endif // CAF_ENABLE_EXCEPTIONS
} // namespace
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment