Init with first implementation

This commit is contained in:
Dawid Drozd 2015-10-07 19:13:49 +02:00
parent b0d3ea9ad0
commit e40d1a3674
2 changed files with 226 additions and 0 deletions

77
src/Notification.h Normal file
View File

@ -0,0 +1,77 @@
#pragma once
#include <functional>
#include <cassert>
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<typename Type>
inline int getTokenForType()
{
static int id_for_type = getUniqueId();
return id_for_type;
}
template<typename ... Args>
class Notification
{
public:
using Callback = std::function<void(Args...)>;
//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<typename NotificationType>
struct notification_traits;
template<typename ... Args>
struct notification_traits<Notification<Args...>>
{
using callback_type = typename std::function<void(Args...)>;
};
#define MAKE_NOTIFICATION(NAME, args...) inline const Dexode::Notification<args>& getNotification##NAME(){static const Dexode::Notification<args> variable(691283); return variable;}
}

149
src/Notifier.h Normal file
View File

@ -0,0 +1,149 @@
#pragma once
#include "Notification.h"
#include <vector>
#include <functional>
#include <map>
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<typename ... Args>
void listen(const int token
, const Notification<Args...>& notification
, const std::function<void(Args...)>& callback)
{
using CallbackType = std::function<void(Args...)>;
//Check for valid object
assert(callback && "Please set it");
if (_callbacks[notification.tag] == nullptr)
{
auto pVector = new VectorImpl<CallbackType>();
pVector->container.reserve(4);
_callbacks[notification.tag] = pVector;
}
auto pVector = static_cast<VectorImpl <CallbackType>*>(_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<typename NotificationType, typename ... Args>
void unlisten(const int token, const NotificationType& notification)
{
using CallbackType = typename notification_traits<NotificationType>::callback_type;
assert(notification.tag > NotificationConst::UNUSED_TAG);
if (_callbacks[notification.tag] == nullptr)
{
return;
}
assert(dynamic_cast<VectorImpl <CallbackType>*>(_callbacks[notification.tag]) != nullptr);
_callbacks[notification.tag]->remove(token);
}
template<typename NotificationType, typename ... Args>
void notify(const NotificationType& notification, Args&& ... params)
{
using CallbackType = typename notification_traits<NotificationType>::callback_type;
assert(notification.tag > NotificationConst::UNUSED_TAG);
if (_callbacks[notification.tag] == nullptr)
{
return;
}
assert(dynamic_cast<VectorImpl <CallbackType>*>(_callbacks[notification.tag]) != nullptr);
//Copy? TODO think about it Use 2 vectors?
auto pVector = static_cast<VectorImpl <CallbackType>*>(_callbacks[notification.tag]);
for (auto&& element : pVector->container)
{
element.first(std::forward<Args>(params)...);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
private:
struct VectorInterface
{
virtual ~VectorInterface()
{
}
virtual void remove(const int token) = 0;
virtual void removeAll() = 0;
};
template<typename Type>
struct VectorImpl : public VectorInterface
{
std::vector<std::pair<Type, int>> 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<int, VectorInterface*> _callbacks;
};
} /* namespace Dexode */