From 19f8f11022f2747a86d7d89a7538091224fd8172 Mon Sep 17 00:00:00 2001 From: artpaul Date: Sat, 18 Jan 2025 05:55:01 +0500 Subject: [PATCH] more variations of functional handler --- include/acto/acto.h | 149 +++++++++++++++++++++++++++----------------- test/tests.cpp | 62 +++++++++++++++--- 2 files changed, 145 insertions(+), 66 deletions(-) diff --git a/include/acto/acto.h b/include/acto/acto.h index 049a6b9..af1a2c0 100644 --- a/include/acto/acto.h +++ b/include/acto/acto.h @@ -307,27 +307,38 @@ class actor { virtual void invoke(const std::unique_ptr msg) const = 0; }; - /** Wrapper for member function pointers. */ + template + struct is_handler_signature { + static constexpr bool value = + std::is_invocable_v || std::is_invocable_v || + std::is_invocable_v || std::is_invocable_v || + std::is_invocable_v || + std::is_invocable_v; + }; + + template + using message_reference_t = + std::conditional_t::is_value_movable && + std::is_rvalue_reference_v

, + core::msg_wrap_t&&, + const core::msg_wrap_t&>; + + /// Wrapper for member function pointers. template - class mem_handler_t : public handler_t { + class mem_handler_t final : public handler_t { using F = std::function; public: - mem_handler_t(F&& func, C* ptr) + mem_handler_t(F&& func, C* ptr) noexcept : func_(std::move(func)) , ptr_(ptr) { assert(func_); assert(ptr_); } - void invoke(std::unique_ptr msg) const override { - using message_reference_t = - typename std::conditional::is_value_movable, - core::msg_wrap_t&&, - const core::msg_wrap_t&>::type; - + void invoke(std::unique_ptr msg) const final { func_(ptr_, actor_ref(msg->sender, true), - static_cast(*msg.get()).data()); + static_cast>(*msg.get()).data()); } private: @@ -335,38 +346,34 @@ class actor { C* const ptr_; }; - /** Wrapper for functor objects. */ - template - class fun_handler_t : public handler_t { - using F = std::function; + /// Wrapper for functor objects. + template + class fun_handler_t final : public handler_t { + using F = std::function; public: - fun_handler_t(F&& func) + fun_handler_t(F&& func) noexcept : func_(std::move(func)) { assert(func_); } - void invoke(std::unique_ptr msg) const override { - func_(actor_ref(msg->sender, true), - static_cast*>(msg.get())->data()); - } - - private: - const F func_; - }; - - template - class fun_handler_no_args_t : public handler_t { - using F = std::function; - - public: - fun_handler_no_args_t(F&& func) - : func_(std::move(func)) { - assert(func_); - } - - void invoke(std::unique_ptr) const override { - func_(); + void invoke(std::unique_ptr msg) const final { + if constexpr (sizeof...(Args) == 0) { + func_(); + } else if constexpr (sizeof...(Args) == 1) { + using P0 = std::tuple_element_t<0, std::tuple>; + + if constexpr (std::is_same_v>) { + func_(actor_ref(msg->sender, true)); + } else { + func_(static_cast>(*msg.get()).data()); + } + } else if constexpr (sizeof...(Args) == 2) { + using P1 = std::tuple_element_t<1, std::tuple>; + + func_(actor_ref(msg->sender, true), + static_cast>(*msg.get()).data()); + } } private: @@ -377,11 +384,11 @@ class actor { virtual ~actor() noexcept = default; protected: - inline actor_ref context() const { + actor_ref context() const { return context_; } - inline actor_ref self() const { + actor_ref self() const { return self_; } @@ -391,9 +398,10 @@ class actor { /// Stops itself. void die() noexcept; +public: /// Sets handler as member function pointer. template - inline void handler(void (ClassName::*func)(actor_ref, P)) { + void handler(void (ClassName::*func)(actor_ref, P)) { set_handler( // Type of the handler. std::type_index(typeid(M)), @@ -403,34 +411,59 @@ class actor { } /// Sets handler as functor object. - template - inline void handler(std::function func) { - set_handler( - // Type of the handler. - std::type_index(typeid(M)), - // Callback. - std::make_unique>(std::move(func))); - } - - /// Sets handler as functor object. - template - inline void handler(std::function func) { - set_handler( - // Type of the handler. - std::type_index(typeid(M)), - // Callback. - std::make_unique>(std::move(func))); + template ::value>> + void handler(F&& func) { + if constexpr (std::is_invocable_v) { + set_handler( + // Type of the handler. + std::type_index(typeid(M)), + // Callback. + std::make_unique>(std::move(func))); + } else if constexpr (std::is_invocable_v) { + set_handler( + // Type of the handler. + std::type_index(typeid(M)), + // Callback. + std::make_unique>(std::move(func))); + } else if constexpr (std::is_invocable_v) { + set_handler( + // Type of the handler. + std::type_index(typeid(M)), + // Callback. + std::make_unique>(std::move(func))); + } else if constexpr (std::is_invocable_v) { + set_handler( + // Type of the handler. + std::type_index(typeid(M)), + // Callback. + std::make_unique>(std::move(func))); + } else if constexpr (std::is_invocable_v) { + set_handler( + // Type of the handler. + std::type_index(typeid(M)), + // Callback. + std::make_unique>( + std::move(func))); + } else if constexpr (std::is_invocable_v) { + set_handler( + // Type of the handler. + std::type_index(typeid(M)), + // Callback. + std::make_unique>(std::move(func))); + } } /// Removes handler for the given type. template - inline void handler() { + void handler() { set_handler(std::type_index(typeid(M)), nullptr); } /// Removes handler for the given type. template - inline void handler(std::nullptr_t) { + void handler(std::nullptr_t) { set_handler(std::type_index(typeid(M)), nullptr); } diff --git a/test/tests.cpp b/test/tests.cpp index dc2a99d..2afa888 100644 --- a/test/tests.cpp +++ b/test/tests.cpp @@ -64,13 +64,56 @@ TEST_CASE("Spawn actor") { acto::shutdown(); } -TEST_CASE("Handler") { +TEST_CASE("Function handlers") { struct A : acto::actor { - struct M { }; + struct A1 { }; + + struct M0 { }; + + struct M1 { + std::string s; + }; + + struct MR { + std::string s; + }; + + struct M2 { + std::string s; + }; + + using MU = std::unique_ptr; A(std::atomic& x) : x_(x) { - actor::handler([this]() { x_++; }); + actor::handler([this](acto::actor_ref sender) { + REQUIRE(!bool(sender)); + x_++; + }); + + actor::handler([this]() { x_++; }); + + actor::handler([this](const M1& m) { + REQUIRE(m.s == "M1"); + x_++; + }); + + actor::handler([this](MR&& m) { + REQUIRE(m.s == "MR"); + x_++; + }); + + actor::handler([this](acto::actor_ref sender, const M2& m) { + REQUIRE(!bool(sender)); + REQUIRE(m.s == "M2"); + x_++; + }); + + actor::handler([this](acto::actor_ref sender, MU m) { + REQUIRE(!bool(sender)); + REQUIRE(*m == "MU"); + x_++; + }); } private: @@ -80,14 +123,17 @@ TEST_CASE("Handler") { std::atomic x{0}; acto::actor_ref a = acto::spawn(x); - CHECK(a.send()); - CHECK(a.send()); - CHECK(a.send()); + CHECK(a.send()); + CHECK(a.send()); + CHECK(a.send(A::M1{.s = "M1"})); + CHECK(a.send(A::M2{.s = "M2"})); + CHECK(a.send(A::MR{.s = "MR"})); + CHECK(a.send(std::make_unique("MU"))); // Cleanup actor. acto::destroy_and_wait(a); // Check values. - REQUIRE(x.load() == 3); + REQUIRE(x.load() == 6); // Shutdown. acto::shutdown(); @@ -112,7 +158,7 @@ TEST_CASE("Process binded actors at exit") { }; A() { - actor::handler([](acto::actor_ref, const M& m) { (*m.counter)++; }); + actor::handler([](const M& m) { (*m.counter)++; }); } };