最终的信号类

支持 int64 和string两种类型,同步和异步,连接和取消连接

发送信号尽量使用

复制代码
sig.sync<int>(0, 1);这种方式
复制代码
sig.sync(0, 1); 可能会有问题?
复制代码
clear disconnect 同理
cpp 复制代码
#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;
}
相关推荐
茉莉玫瑰花茶2 小时前
算法 --- 字符串
算法
博笙困了2 小时前
AcWing学习——差分
c++·算法
NAGNIP3 小时前
认识 Unsloth 框架:大模型高效微调的利器
算法
NAGNIP3 小时前
大模型微调框架之LLaMA Factory
算法
echoarts3 小时前
Rayon Rust中的数据并行库入门教程
开发语言·其他·算法·rust
Python技术极客3 小时前
一款超好用的 Python 交互式可视化工具,强烈推荐~
算法
徐小夕3 小时前
花了一天时间,开源了一套精美且支持复杂操作的表格编辑器tablejs
前端·算法·github
Aomnitrix3 小时前
知识管理新范式——cpolar+Wiki.js打造企业级分布式知识库
开发语言·javascript·分布式
小刘鸭地下城3 小时前
深入浅出链表:从基础概念到核心操作全面解析
算法