// 实现原理
// 每个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.