Created
September 1, 2023 12:51
-
-
Save qycyfjy/fe16dc30e4859da0b52d244dad71eeb5 to your computer and use it in GitHub Desktop.
简单的信号槽实现
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include "sigslot.h" | |
int main() | |
{ | |
Echo echo; | |
Object::connect(&echo, "ping", &echo, "onPing"); | |
Object::connect(&echo, "ping", &echo, "onPing"); | |
echo.try_ping(); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "sigslot.h" | |
#include <cstring> | |
#include <cstdio> | |
static int find_str(const char* defs, const char* name) | |
{ | |
size_t len1 = strlen(defs); | |
size_t len2 = strlen(name); | |
if (len1 < len2) { | |
return -1; | |
} | |
int idx = 0; | |
size_t i = 0; | |
while (i < len1) | |
{ | |
if (strncmp(defs + i, name, len2) == 0 && defs[i + len2] == '\n') | |
{ | |
return idx; | |
} | |
while (i < len1 && defs[i] != '\n') { | |
++i; | |
} | |
++i; | |
++idx; | |
} | |
return -1; | |
} | |
void MetaObject::activate(Object* sender, int idx) | |
{ | |
auto iterPair = sender->mConnectionMap.equal_range(idx); | |
for (auto iter = iterPair.first; iter != iterPair.second; iter++) | |
{ | |
auto& connection = iter->second; | |
connection.receiver->metacall(connection.method); | |
} | |
} | |
void Object::connect(Object* sender, const char* signal, Object* receiver, const char* slot) | |
{ | |
int sigIdx = find_str(sender->metaObject()->signals, signal); | |
int slotIdx = find_str(receiver->metaObject()->slots, slot); | |
if (sigIdx == -1 || slotIdx == -1) | |
{ | |
throw std::exception("signal or slot not found"); | |
} | |
else { | |
auto iterPair = sender->mConnectionMap.equal_range(sigIdx); | |
for (auto iter = iterPair.first; iter != iterPair.second; iter++) | |
{ | |
if (iter->second.method == slotIdx) { | |
std::fprintf(stderr, "sig-slot existed\n"); | |
return; | |
} | |
} | |
Connection c{ receiver, slotIdx }; | |
sender->mConnectionMap.insert({ sigIdx, std::move(c) }); | |
} | |
} | |
static constexpr const char* signals = "ping\n"; | |
static constexpr const char* slots = "onPing\n"; | |
MetaObject Echo::mMetaObject{ signals, slots }; | |
void Echo::onPing() | |
{ | |
std::printf("ping\n"); | |
} | |
Echo::Echo() {} | |
const MetaObject* Echo::metaObject() const | |
{ | |
return &mMetaObject; | |
} | |
void Echo::try_ping() | |
{ | |
emit ping(); | |
} | |
void Echo::ping() | |
{ | |
MetaObject::activate(this, 0); | |
} | |
void Echo::metacall(int idx) | |
{ | |
switch (idx) | |
{ | |
case 0: | |
onPing(); | |
break; | |
default: | |
break; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <string> | |
#include <unordered_map> | |
#define SIGNAL(signal) #signal | |
#define SLOT(slot) #slot | |
#define Signals public | |
#define Slots | |
#define emit | |
class Object; | |
struct MetaObject { | |
const char* signals; | |
const char* slots; | |
static void activate(Object* sender, int idx); | |
}; | |
struct Connection { | |
Object* receiver; | |
int method; | |
}; | |
using ConnectionMap = std::unordered_multimap<int, Connection>; | |
class Object { | |
public: | |
virtual ~Object() {} | |
virtual void metacall(int idx) = 0; | |
virtual const MetaObject* metaObject() const = 0; | |
static void connect(Object* sender, const char* signal, Object* receiver, const char* slot); | |
protected: | |
ConnectionMap mConnectionMap; | |
friend struct MetaObject; | |
}; | |
class Echo : public Object { | |
public: | |
Echo(); | |
const MetaObject* metaObject() const; | |
void try_ping(); | |
Signals : | |
void ping(); | |
public Slots : | |
void onPing(); | |
private: | |
static MetaObject mMetaObject; | |
void metacall(int idx) override; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment