From b497ccbc6e0b3f541ccbd273d199d25ae6169c0c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 4 Jul 2024 13:05:16 +0200 Subject: [PATCH] Allow lambda handlers for signals with data --- common/core/Object.h | 32 ++++++++++++++++++++ tests/unit/signals.cxx | 69 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/common/core/Object.h b/common/core/Object.h index d49a591a7a..c5d2181950 100644 --- a/common/core/Object.h +++ b/common/core/Object.h @@ -71,9 +71,14 @@ namespace core { // lambda has a capture list, then an object must also be specified // to control the lifetime. Connection connectSignal(const char* name, void (*callback)()); + template + Connection connectSignal(const char* name, void (*callback)(I)); Connection connectSignal(const char* name, Object* obj, const std::function& callback); + template + Connection connectSignal(const char* name, Object* obj, + const std::function& callback); // disconnectSignal() unregisters a method that was previously // registered using connectSignal(). @@ -226,6 +231,33 @@ namespace core { typeid(I).hash_code()); } + template + Connection Object::connectSignal(const char* name, + void (*callback)(I)) + { + emitter_t emitter = [callback](const any& info) { + assert(info.has_value()); + using I_d = typename std::decay::type; + callback(any_cast(info)); + }; + return connectSignal(name, nullptr, callback, emitter, + typeid(I).hash_code()); + } + + template + Connection Object::connectSignal(const char* name, Object* obj, + const std::function& callback) + { + emitter_t emitter = [callback](const any& info) { + assert(info.has_value()); + using I_d = typename std::decay::type; + callback(any_cast(info)); + }; + assert(obj); + return connectSignal(name, obj, &callback, emitter, + typeid(I).hash_code()); + } + template void Object::disconnectSignal(const char* name, T* obj, void (T::*callback)()) diff --git a/tests/unit/signals.cxx b/tests/unit/signals.cxx index 39e2d25505..e5255d98b6 100644 --- a/tests/unit/signals.cxx +++ b/tests/unit/signals.cxx @@ -346,6 +346,34 @@ static void testConnectLambda() printf("OK\n"); } +static void testConnectLambdaArgs() +{ + Sender s; + Receiver r; + + printf("%s: ", __func__); + + /* Simple lambda */ + count = 0; + s.registerSignal("signal"); + s.connectSignal("signal", [](const char*) { count++; }); + s.emitSignal("signal", "data"); + ASSERT_EQ(count, 1); + + /* Lambda with captures */ + count = 0; + s.registerSignal("csignal"); + s.connectSignal("csignal", &r, [&s, &r](const char*) { + (void)s; + (void)r; + count++; + }); + s.emitSignal("csignal", "data"); + ASSERT_EQ(count, 1); + + printf("OK\n"); +} + static void testDisconnect() { Sender s; @@ -412,6 +440,15 @@ static void testDisconnect() s.emitSignal("lsignal"); ASSERT_EQ(count, 0); + /* Simple lambda with args */ + count = 0; + s.registerSignal("lasignal"); + c = s.connectSignal("lasignal", + [](const char*) { count++; }); + s.disconnectSignal(c); + s.emitSignal("lasignal", "data"); + ASSERT_EQ(count, 0); + /* Lambda with captures */ count = 0; s.registerSignal("lcsignal"); @@ -421,6 +458,18 @@ static void testDisconnect() s.emitSignal("lcsignal"); ASSERT_EQ(count, 0); + /* Lambda with captures and args */ + count = 0; + s.registerSignal("lcasignal"); + c = s.connectSignal("lcasignal", &r, + [&s, &r](const char*) { + (void)s; (void)r; + count++; + }); + s.disconnectSignal(c); + s.emitSignal("lcasignal", "data"); + ASSERT_EQ(count, 0); + /* Double remove */ ok = true; s.registerSignal("dblsignal"); @@ -584,6 +633,8 @@ static void testDisconnectAll() s.connectSignal("signal2", &r, &Receiver::genericHandler); s.connectSignal("signal3", &r, &Receiver::simpleStringHandler); s.connectSignal("signal3", &r, &Receiver::genericStringHandler); + s.connectSignal("signal3", &r, + [](const char*) { count++; }); s.connectSignal("signal1", &r2, &Receiver::genericHandler); s.disconnectSignals(&r); s.emitSignal("signal1"); @@ -643,16 +694,23 @@ static void testEmitConversion() s.registerSignal("refhandler"); s.connectSignal("refhandler", &r, &Receiver::simpleConstRefHandler); s.connectSignal("refhandler", &r, &Receiver::genericConstRefHandler); + s.connectSignal("refhandler", + [](const int&) { count++; }); + s.connectSignal("refhandler", &r, + [&r](const int&) { (void)r; count++; }); s.emitSignal("refhandler", 123); - ASSERT_EQ(count, 2); + ASSERT_EQ(count, 4); /* Sender adds reference */ count = 0; s.registerSignal("refemitter"); s.connectSignal("refemitter", &r, &Receiver::simpleConstRefHandler); s.connectSignal("refemitter", &r, &Receiver::genericConstRefHandler); + s.connectSignal("refemitter", [](int) { count++; }); + s.connectSignal("refemitter", &r, + [&r](int) { (void)r; count++; }); s.emitSignal("refemitter", 123); - ASSERT_EQ(count, 2); + ASSERT_EQ(count, 4); /* Receiver adds pointer const qualifier */ #if 0 /* FIXME: Currently broken*/ @@ -660,8 +718,12 @@ static void testEmitConversion() s.registerSignal("constemitter"); s.connectSignal("constemitter", &r, &Receiver::simpleConstPtrHandler); s.connectSignal("constemitter", &r, &Receiver::genericConstPtrHandler); + s.connectSignal("constemitter", + [](const int*) { count++; }); + s.connectSignal("constemitter", &r, + [&r](const int*) { (void)r; count++; }); s.emitSignal("constemitter", &count); - ASSERT_EQ(count, 2); + ASSERT_EQ(count, 4); #endif printf("OK\n"); @@ -676,6 +738,7 @@ int main(int /*argc*/, char** /*argv*/) testConnect(); testConnectArg(); testConnectLambda(); + testConnectLambdaArgs(); testDisconnect(); testDisconnectHelper(); testDisconnectHelperArg();