最终的信号类
支持 int64 和string两种类型,同步和异步,连接和取消连接
发送信号尽量使用
sig.sync<int>(0, 1);这种方式
sig.sync(0, 1); 可能会有问题?
clear disconnect 同理
#pragma once
#include <functional>
#include <mutex>
#include <vector>
#include <system_error>
#include <unordered_map>
#include <string>
#include <memory>
#include <typeinfo>
#include <cstdint>
#include <tuple>
#include <iostream>
#include <thread>class Signal {
public:template <typename... Args>std::error_code connect(const std::string& key,std::function<void(std::decay_t<Args>...)> slot) {return connectImpl<std::string, Args...>(key, std::move(slot));}template <typename... Args, typename Obj, typename MemFn>std::error_code connect(const std::string& key, Obj* obj, MemFn mf) {return connectMember<std::string, Args...>(key, obj, mf);}template <typename... Args>std::error_code connect(int64_t key,std::function<void(std::decay_t<Args>...)> slot) {return connectImpl<int64_t, Args...>(key, std::move(slot));}template <typename... Args, typename Obj, typename MemFn>std::error_code connect(int64_t key, Obj* obj, MemFn mf) {return connectMember<int64_t, Args...>(key, obj, mf);}template <typename... Args, typename Obj, typename MemFn>std::size_t disconnect(const std::string& key, Obj* obj, MemFn mf) {return disconnectImpl<std::string, Args...>(key, obj, mf);}template <typename... Args, typename Obj, typename MemFn>std::size_t disconnect(int64_t key, Obj* obj, MemFn mf) {return disconnectImpl<int64_t, Args...>(key, obj, mf);}template <typename... Args>void clear(const std::string& key) { clearImpl<std::string, Args...>(key); }template <typename... Args>void clear(int64_t key) { clearImpl<int64_t, Args...>(key); }template <typename... Args>int sync(const std::string& key, Args&&... args) const {return syncImpl<std::string, Args...>(key, std::forward<Args>(args)...);}template <typename... Args>int sync(int64_t key, Args&&... args) const {return syncImpl<int64_t, Args...>(key, std::forward<Args>(args)...);}template <typename... Args>void async(const std::string& key, Args&&... args) const {auto* ctx = context<std::string, std::decay_t<Args>...>(key);std::thread([ctx, tup = std::make_tuple(std::forward<Args>(args)...)]() mutable {
// std::cout << "[async thread " << std::this_thread::get_id() << "]\n";std::apply([ctx](auto&&... as) { ctx->fire(std::forward<decltype(as)>(as)..., true); }, tup);}).detach();}template <typename... Args>void async(int64_t key, Args&&... args) const {auto* ctx = context<int64_t, std::decay_t<Args>...>(key);std::thread([ctx, tup = std::make_tuple(std::forward<Args>(args)...)]() mutable {
// std::cout << "[async thread " << std::this_thread::get_id() << "]\n";std::apply([ctx](auto&&... as) { ctx->fire(std::forward<decltype(as)>(as)..., true); }, tup);}).detach();}private:template <typename T>static const void* bitCast(T mf) { union { T in; const void* out; } u{mf}; return u.out; }template <typename Key, typename... Args>struct Context {using Slot = std::function<void(Args...)>;struct Node {Slot func;void* obj = nullptr;const void* mf = nullptr;size_t mfHash = 0;std::shared_ptr<void> holder;};mutable std::mutex m_;std::vector<std::unique_ptr<Node>> nodes_;void append(Slot f, void* objPtr, const void* mfPtr, size_t hash, std::shared_ptr<void> keep = {}) {std::lock_guard lg(m_);auto n = std::make_unique<Node>();n->func = std::move(f);n->obj = objPtr;n->mf = mfPtr;n->mfHash = hash;n->holder = std::move(keep);nodes_.push_back(std::move(n));}void keepAlive(const std::shared_ptr<Slot>& sp) {std::lock_guard lg(m_);if (!nodes_.empty()) nodes_.back()->holder = sp;}std::size_t remove(void* obj, const void* mf, size_t hash) {std::lock_guard lg(m_);auto old = nodes_.size();nodes_.erase(std::remove_if(nodes_.begin(), nodes_.end(),[=](const auto& n) {return n->mfHash == hash && n->obj == obj && n->mf == mf;}),nodes_.end());return old - nodes_.size();}void clear() {std::lock_guard lg(m_);nodes_.clear();}int fire(Args... args, bool) const {std::vector<Node*> snap;{std::lock_guard lg(m_);snap.reserve(nodes_.size());for (auto& n : nodes_) snap.push_back(n.get());}for (auto* p : snap) p->func(args...);return 0;}};template <typename Key, typename... Args>static Context<Key, Args...>* context(const Key& key) {static std::mutex g_m;static std::unordered_map<Key, std::unique_ptr<Context<Key, Args...>>> pool;std::lock_guard lg(g_m);auto& ptr = pool[key];if (!ptr) ptr = std::make_unique<Context<Key, Args...>>();return ptr.get();}template <typename Key, typename... Args>std::error_code connectImpl(const Key& key, std::function<void(std::decay_t<Args>...)> slot) {context<Key, Args...>(key)->append(std::move(slot), nullptr, nullptr, 0);return {};}template <typename Key, typename... Args, typename Obj, typename MemFn>std::error_code connectMember(const Key& key, Obj* obj, MemFn mf) {auto sp = std::make_shared<std::function<void(std::decay_t<Args>...)>>([obj, mf](std::decay_t<Args>... args) { (obj->*mf)(std::forward<std::decay_t<Args>>(args)...); });auto* ctx = context<Key, Args...>(key);ctx->append(*sp, obj, bitCast(mf), typeid(MemFn).hash_code(), sp);return {};}template <typename Key, typename... Args, typename Obj, typename MemFn>std::size_t disconnectImpl(const Key& key, Obj* obj, MemFn mf) {return context<Key, Args...>(key)->remove(obj, bitCast(mf), typeid(MemFn).hash_code());}template <typename Key, typename... Args>void clearImpl(const Key& key) { context<Key, Args...>(key)->clear(); }template <typename Key, typename... Args>int syncImpl(const Key& key, Args&&... args) const {return context<Key, Args...>(key)->fire(std::forward<Args>(args)..., false);}
};/*>>>>>>>> 测试 <<<<<<<<*/
#include <iostream>
class Foo {
public:void bar(int x) { std::cout << x << " " << std::this_thread::get_id()<<std::endl;}
};int main() {std::cout << "main " << std::this_thread::get_id()<<std::endl;Signal sig;Foo f;sig.connect<int>("s", &f, &Foo::bar);sig.connect<int>(0, &f, &Foo::bar);sig.sync<int>(0, 1);sig.sync<int>("s", 2);sig.async<int>(0, 3);sig.async<int>("s", 4);std::this_thread::sleep_for(std::chrono::milliseconds(1000));std::cout <<std::endl;sig.clear<int>("s");sig.sync<int>(0, 1);sig.sync<int>("s", 2);sig.async<int>(0, 3);sig.async<int>("s", 4);std::this_thread::sleep_for(std::chrono::milliseconds(1000));std::cout <<std::endl;
// sig.disconnect<int>("s", &f, &Foo::bar);sig.disconnect<int>(0, &f, &Foo::bar);sig.sync<int>(0, 1);sig.sync<int>("s", 2);sig.async<int>(0, 3);sig.async<int>("s", 4);std::this_thread::sleep_for(std::chrono::milliseconds(2000));std::cout <<std::endl;
}