Skip to content

Instantly share code, notes, and snippets.

@qycyfjy
Created September 1, 2023 12:51
Show Gist options
  • Save qycyfjy/fe16dc30e4859da0b52d244dad71eeb5 to your computer and use it in GitHub Desktop.
Save qycyfjy/fe16dc30e4859da0b52d244dad71eeb5 to your computer and use it in GitHub Desktop.
简单的信号槽实现
#include <iostream>
#include "sigslot.h"
int main()
{
Echo echo;
Object::connect(&echo, "ping", &echo, "onPing");
Object::connect(&echo, "ping", &echo, "onPing");
echo.try_ping();
}
#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;
}
}
#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