#31 - HandlerManager Template Class
Date: 2018-10-20 12:00 - C++
A template class that provides the interface for a manager of events. It allows to register functions and keep track of the handles.
#pragma once
#include <functional>
#include <typeinfo>
#include <map>
#include <set>
#include <memory>
#define HANDLER_FOR(CLASS) &typeid(CLASS)
namespace YourNamespace {
template<typename T, typename...Values>
class Handler : public std::enable_shared_from_this<Handler<T, Values...>> {
template<typename T, typename...Values> friend class HandlerManager;
const type_info* type;
std::function <void (T*, Values...)> function;
std::weak_ptr<HandlerManager<T, Values...>> manager;
bool _registered;
bool _weak;
public:
void unregister() {
if (_registered && !manager.expired()) {
std::shared_ptr<HandlerManager<T, Values...>> ptr(manager);
if(!_weak) {
auto it = ptr->handlers.find(type);
if (it != ptr->handlers.end()) {
auto &ref = (*it).second;
(*it).second.erase(this->shared_from_this());
}
}
else {
auto it = ptr->handlersWeak.find(type);
if (it != ptr->handlersWeak.end()) {
auto &ref = (*it).second;
(*it).second.erase(this->shared_from_this());
}
}
}
_registered = false;
}
bool registerSame() {
if (_registered || manager.expired())
return false;
std::shared_ptr<HandlerManager<T, Values...>> ptr(manager);
if (!_weak)
ptr->handlers[type].insert(this->shared_from_this());
else
ptr->handlersWeak[type].insert(this->shared_from_this());
_registered = true;
return true;
}
bool registered() {
if (!manager.expired())
return _registered;
return false;
}
bool weak() {
return _weak;
}
};
template <typename T, typename...Values>
class HandlerManager : public std::enable_shared_from_this<HandlerManager<T, Values...>> {
friend class Handler<T, Values>;
std::map<const type_info*, std::set<std::shared_ptr<Handler<T, Values...>>>> handlers;
std::map<const type_info*, std::set<std::weak_ptr<Handler<T, Values...>>, std::owner_less<std::weak_ptr<Handler<T, Values...>>>>> handlersWeak;
inline void dispatch(T* val, const type_info* type, Values... vals) {
auto itHandlers = handlers.find(type);
if (itHandlers != handlers.end()) {
for (auto handler : (*itHandlers).second)
handler->function(val, vals...);
}
}
inline void dispatchWeak(T* val, const type_info* type, Values... vals) {
auto itWeak = handlersWeak.find(type);
if (itWeak != handlersWeak.end()) {
auto &ref = (*itWeak).second;
for (auto itWeakSet = ref.begin(); itWeakSet != ref.end();) {
auto &handler = (*itWeakSet);
if(handler.expired()) {
itWeakSet = ref.erase(itWeakSet);
} else {
std::shared_ptr<Handler<T, Values...>> ptr(handler);
ptr->function(val, vals...);
++itWeakSet;
}
}
}
}
public:
virtual std::shared_ptr<Handler<T, Values...>> addHandler(const type_info* type, std::function<void (T*, Values...)> hFunc, bool weak = false) {
std::shared_ptr<Handler<T, Values...>> h = std::make_shared<Handler<T, Values...>>();
h->type = type;
h->function = hFunc;
h->manager = this->shared_from_this();
h->_weak = weak;
h->_registered = true;
if (!weak)
handlers[type].insert(h);
else
handlersWeak[type].insert(h);
return h;
}
virtual void dispatch(T* val, Values... vals) {
const type_info* type = &typeid(*val);
dispatch(val, type, vals...);
dispatchWeak(val, type, vals...);
}
virtual ~HandlerManager() {}
};
template<typename T, typename...Values>
class HandlerContainer {
std::set<std::shared_ptr<Handler<T, Values...>>> handlers;
public:
void add(std::shared_ptr<Handler<T, Values...>> handler) {
handlers.insert(handler);
}
virtual ~HandlerContainer() {
for (auto handler : handlers)
handler->unregister();
}
};
}