diff --git a/src/Notification.h b/src/Notification.h new file mode 100644 index 0000000..06eb389 --- /dev/null +++ b/src/Notification.h @@ -0,0 +1,77 @@ +#pragma once + +#include +#include + +namespace Dexode +{ + +enum NotificationConst +{ + UNUSED_TAG = 0 +}; + +inline int getUniqueId() +{ + static int id = NotificationConst::UNUSED_TAG + 1; + return ++id; +} + +inline int getToken() +{ + return getUniqueId(); +} + +template +inline int getTokenForType() +{ + static int id_for_type = getUniqueId(); + return id_for_type; +} + +template +class Notification +{ +public: + using Callback = std::function; + + //dummyInt used only for prevent creating unused notifications you should use MAKE_NOTIFICATION + Notification(int dummyInt) + : tag(getUniqueId()) + { + assert(dummyInt == 691283); + } + + Notification& operator=(const Notification&) = delete; + + Notification& operator=(Notification&& notification) + { + tag = notification.tag; + return *this; + } + + Notification(const Notification& notification) + : tag(notification.tag) + { + } + + Notification(Notification&& notification) + : tag(notification.tag) + { + } + + int tag = NotificationConst::UNUSED_TAG; +}; + +template +struct notification_traits; + +template +struct notification_traits> +{ + using callback_type = typename std::function; +}; + +#define MAKE_NOTIFICATION(NAME, args...) inline const Dexode::Notification& getNotification##NAME(){static const Dexode::Notification variable(691283); return variable;} + +} diff --git a/src/Notifier.h b/src/Notifier.h new file mode 100644 index 0000000..ada1c81 --- /dev/null +++ b/src/Notifier.h @@ -0,0 +1,149 @@ +#pragma once + +#include "Notification.h" + +#include +#include +#include + +namespace Dexode +{ + +class Notifier +{ +public: + Notifier() + { + } + + virtual ~Notifier() + { + for (auto&& it = _callbacks.begin(); it != _callbacks.end(); ++it) + { + delete it->second; + } + } + + Notifier& operator=(const Notifier&) = delete; + + Notifier(const Notifier&) = delete; + + Notifier& operator=(Notifier&&) = delete; + + Notifier(Notifier&&) = delete; + + static Notifier& getGlobal() + { + static Notifier globalNotifier; + return globalNotifier; + } + + template + void listen(const int token + , const Notification& notification + , const std::function& callback) + { + using CallbackType = std::function; + + //Check for valid object + assert(callback && "Please set it"); + + if (_callbacks[notification.tag] == nullptr) + { + auto pVector = new VectorImpl(); + pVector->container.reserve(4); + + _callbacks[notification.tag] = pVector; + } + + auto pVector = static_cast*>(_callbacks[notification.tag]); + pVector->container.emplace_back(std::make_pair(callback, token)); + } + + void unlistenAll(const int token) + { + for (auto&& element : _callbacks) + { + element.second->remove(token); + } + } + + template + void unlisten(const int token, const NotificationType& notification) + { + using CallbackType = typename notification_traits::callback_type; + assert(notification.tag > NotificationConst::UNUSED_TAG); + + if (_callbacks[notification.tag] == nullptr) + { + return; + } + assert(dynamic_cast*>(_callbacks[notification.tag]) != nullptr); + _callbacks[notification.tag]->remove(token); + } + + template + void notify(const NotificationType& notification, Args&& ... params) + { + using CallbackType = typename notification_traits::callback_type; + assert(notification.tag > NotificationConst::UNUSED_TAG); + + if (_callbacks[notification.tag] == nullptr) + { + return; + } + + assert(dynamic_cast*>(_callbacks[notification.tag]) != nullptr); + + //Copy? TODO think about it Use 2 vectors? + auto pVector = static_cast*>(_callbacks[notification.tag]); + for (auto&& element : pVector->container) + { + element.first(std::forward(params)...); + } + } + +//////////////////////////////////////////////////////////////////////////////////////////////////// +private: + + struct VectorInterface + { + virtual ~VectorInterface() + { + } + + virtual void remove(const int token) = 0; + virtual void removeAll() = 0; + }; + + template + struct VectorImpl : public VectorInterface + { + std::vector> container; + + virtual ~VectorImpl() + { + } + + virtual void removeAll() override + { + container.clear(); + } + + virtual void remove(const int token) override + { + for (int i = container.size() - 1; i > -1; --i) + { + if (container[i].second == token) + { + std::swap(container[i], container.back()); + container.pop_back(); + } + } + } + }; + + std::map _callbacks; +}; + +} /* namespace Dexode */