#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();
		}
	};
}

Previous snippet | Next snippet