最终的信号类

支持 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;
}
相关推荐
ha204289419442 分钟前
Linux操作系统学习之---基于环形队列的生产者消费者模型(毛坯版)
linux·c++·学习
Never_Satisfied1 小时前
在JavaScript / Node.js / 抖音小游戏中,使用tt.request通信
开发语言·javascript·node.js
爱吃小胖橘1 小时前
Unity资源加载模块全解析
开发语言·unity·c#·游戏引擎
budingxiaomoli2 小时前
算法--滑动窗口(二)
算法
ID_180079054733 小时前
淘宝实时拍立淘按图搜索数据|商品详情|数据分析提取教程
算法·数据分析·图搜索算法
l1t3 小时前
Lua与LuaJIT的安装与使用
算法·junit·单元测试·lua·luajit
千里镜宵烛3 小时前
Lua-迭代器
开发语言·junit·lua
渡我白衣3 小时前
C++ 同名全局变量:当符号在链接器中“相遇”
开发语言·c++·人工智能·深度学习·microsoft·语言模型·人机交互
淮北4943 小时前
html + css +js
开发语言·前端·javascript·css·html