// 实现原理
// 每个signal映射到bitset位,全集
// 每个slot做为signal的bitset子集
// signal全集触发,标志位有效
// flip将触发事件队列前置
// slot检测智能指针全集触发的标志位,主动运行子集绑定的函数
// 下一帧对bitset全集进行触发清空,防止slot一直检测到signal触发
#include <any> #include <iostream> #include "blinker.h" void testMatch() { blinker::SignalTrie<1024> trie; trie.Put("ab.cd.ef", 1); trie.Put("ab.cd.kk", 2); trie.Put("ab.xy.zz", 3); trie.Put("tt.xx", 4); trie.Put("ab.cd", 5); auto m1 = trie.Match("ab.cd.ef"); //REQUIRE(m1.count() == 1); //REQUIRE(m1[1]); auto m2 = trie.Match("ab.cd.kk"); //REQUIRE(m2.count() == 1); //REQUIRE(m2[2]); auto m3 = trie.Match("ab.xy.zz"); //REQUIRE(m3.count() == 1); //REQUIRE(m3[3]); auto m4 = trie.Match("ab.not.found"); //REQUIRE(m4.count() == 0); auto m5 = trie.Match("ab.*"); //REQUIRE(m5.count() == 4); //REQUIRE(m5[1]); //REQUIRE(m5[2]); //REQUIRE(m5[3]); //REQUIRE(m5[5]); auto m6 = trie.Match("*"); //REQUIRE(m6.count() == 5); //REQUIRE(m6[1]); //REQUIRE(m6[2]); //REQUIRE(m6[3]); //REQUIRE(m6[4]); //REQUIRE(m6[5]); auto m7 = trie.Match("ab.cd.*"); //REQUIRE(m7.count() == 2); //REQUIRE(m7[1]); //REQUIRE(m7[2]); auto m8 = trie.Match("tt.xx."); //REQUIRE(m8.count() == 0); auto m9 = trie.Match("tt.xx.*"); //REQUIRE(m9.count() == 0); auto m10 = trie.Match("ab.cd"); //REQUIRE(m10.count() == 1); //REQUIRE(m10[5]); } void testValue() { struct Data { int value = 1; Data(int value) : value(value) {} }; blinker::Board board; auto signal1 = board.NewSignal("ab.cd"); auto signal2 = board.NewSignal("ab.ef"); auto signal3 = board.NewSignal("xy.zk"); auto conn1 = board.Connect("ab.*"); auto conn2 = board.Connect("ab.cd"); auto conn3 = board.Connect("ab.ef"); auto conn4 = board.Connect("xy.zk"); auto conn5 = board.Connect("*"); bool conn1CallbackCalled = false; bool conn2CallbackCalled = false; bool conn3CallbackCalled = false; bool conn4CallbackCalled = false; bool conn5CallbackCalled = false; auto tick = [&]() { signal1->Emit(std::make_shared<Data>(1)); signal2->Emit(std::make_shared<Data>(2)); signal3->Emit(std::make_shared<Data>(3)); // signal1 and signal2 conn1->Poll([&](const blinker::SignalId id, std::any data) { conn1CallbackCalled = true; auto p = std::any_cast<std::shared_ptr<Data>>(data); if (id == signal1->Id()) std::cout << "value: " << p->value << std::endl; else if (id == signal2->Id()) std::cout << "value: " << p->value << std::endl; else std::cout << "value error!" << std::endl; }); // signal1 conn2->Poll([&](const blinker::SignalId id, std::any data) { conn2CallbackCalled = true; auto p = std::any_cast<std::shared_ptr<Data>>(data); if (id == signal1->Id()) std::cout << "value: " << p->value << std::endl; else std::cout << "value error!" << std::endl; }); // signal2 conn3->Poll([&](const blinker::SignalId id, std::any data) { conn3CallbackCalled = true; auto p = std::any_cast<std::shared_ptr<Data>>(data); if (id == signal2->Id()) std::cout << "value: " << p->value << std::endl; else std::cout << "value error!" << std::endl; }); // signal3 conn4->Poll([&](const blinker::SignalId id, std::any data) { conn4CallbackCalled = true; auto p = std::any_cast<std::shared_ptr<Data>>(data); if (id == signal3->Id()) std::cout << "value: " << p->value << std::endl; else std::cout << "value error!" << std::endl; }); // all signals conn5->Poll([&](const blinker::SignalId id, std::any data) { conn5CallbackCalled = true; auto p = std::any_cast<std::shared_ptr<Data>>(data); if (id == signal1->Id()) std::cout << "value: " << p->value << std::endl; else if (id == signal2->Id()) std::cout << "value: " << p->value << std::endl; else if (id == signal3->Id()) std::cout << "value: " << p->value << std::endl; else std::cout << "value error!" << std::endl; }); board.Flip(); }; tick(); // still not called. tick(); // called after flip } int testLoops() { // Creates a board. blinker::Board board; // Creates signals. auto taskStarted = board.NewSignal("task.started"); auto taskEnded = board.NewSignal("task.ended"); auto actionStarted = board.NewSignal("action.started"); // Creates connection to match some signals. auto connection = board.Connect("task.*"); // Callback to be called on signal fire. auto callback = [&](const blinker::SignalId id, std::any data) { if (id == taskStarted->Id()) std::cout << "signal taskStarted:"; else if (id == taskEnded->Id()) std::cout << "signal taskEnded:"; else if (id == actionStarted->Id()) std::cout << "signal actionStarted-:"; std::cout << std::any_cast<int>(data) << std::endl; }; // Assuming your main tick function here. for (int i = 0; i < 10; i++) { // Emit some signals (to backend). taskStarted->Emit(i); taskEnded->Emit(i); actionStarted->Emit(i); // Poll from frontend. connection->Poll(callback); // Flip double buffers. board.Flip(); } return 0; } void test() { testMatch(); testValue(); testLoops(); }输出
value: 1 value: 2 value: 1 value: 2 value: 3 value: 1 value: 2 value: 3 signal taskStarted:0 signal taskEnded:0 signal taskStarted:1 signal taskEnded:1 signal taskStarted:2 signal taskEnded:2 signal taskStarted:3 signal taskEnded:3 signal taskStarted:4 signal taskEnded:4 signal taskStarted:5 signal taskEnded:5 signal taskStarted:6 signal taskEnded:6 signal taskStarted:7 signal taskEnded:7 signal taskStarted:8 signal taskEnded:8参考
GitHub - hit9/blinker.h: A lightweight signal/event library for C++, similar to Python's blinker, but designed to work with ticking loops.