#pragma once
#include "megbrain/common.h"
#include "megbrain/utils/metahelper.h"
#include "megbrain/utils/thin/hash_table.h"
#include <list>
#include <memory>
#include <utility>
#include "megbrain/utils/thin/function.h"
namespace mgb {
class SyncEventConnecter : public NonCopyableObj {
class ReceiverBase {
public:
virtual ~ReceiverBase() = default;
};
template <typename T>
class Receiver : public ReceiverBase {
public:
thin_function<void(const T&)> callback;
template <typename Callback>
Receiver(Callback&& cb) : callback{std::forward<Callback>(cb)} {}
};
using ReceiverList = std::list<std::unique_ptr<ReceiverBase>>;
using ReceiverMap = ThinHashMap<Typeinfo*, ReceiverList>;
bool m_is_empty = true;
MGB_MUTEX m_mtx;
std::shared_ptr<ReceiverMap> m_receiver_map = std::make_shared<ReceiverMap>();
size_t m_version = 0;
public:
class ReceiverHandlerImpl;
struct ReceiverHandlerImplDeleter {
public:
MGE_WIN_DECLSPEC_FUC void operator()(ReceiverHandlerImpl*);
};
using ReceiverHandler =
std::unique_ptr<ReceiverHandlerImpl, ReceiverHandlerImplDeleter>;
template <typename T, typename Callback>
MGB_WARN_UNUSED_RESULT ReceiverHandler register_receiver(Callback&& callback) {
auto receiver = std::make_unique<Receiver<T>>(std::forward<Callback>(callback));
return do_register_receiver(T::typeinfo(), std::move(receiver));
}
template <typename T, typename Callback>
void register_receiver_permanent(Callback&& callback) {
auto hdl = register_receiver<T>(std::forward<Callback>(callback));
m_permanent_handler.push_back(std::move(hdl));
}
template <typename T, typename... Args>
void signal_inplace(Args&&... args) const {
if (m_is_empty)
return;
auto iter = m_receiver_map->find(T::typeinfo());
if (iter == m_receiver_map->end())
return;
T t_ins{std::forward<Args>(args)...};
using R = Receiver<T>;
for (auto&& i : iter->second) {
static_cast<R*>(i.get())->callback(t_ins);
}
}
size_t version() const { return m_version; }
private:
std::vector<ReceiverHandler> m_permanent_handler;
MGE_WIN_DECLSPEC_FUC ReceiverHandler
do_register_receiver(Typeinfo* type, std::unique_ptr<ReceiverBase> receiver);
};
}