Secure EventBus from wrong usage

For example user previously could do such thing:

bus.listen<const MyEvent>(...)

bus.listen<MyEvent>(...)

Those we 2 different events :/
This commit is contained in:
Dawid Drozd 2018-07-27 14:38:40 +02:00
parent f9195316d3
commit 63395f5a7e

View File

@ -12,13 +12,21 @@ namespace Dexode
template <typename> template <typename>
void type_id() // Helper for getting "type id" void type_id() // Helper for getting "type id"
{ {}
}
using type_id_t = void (*)(); // Function pointer using type_id_t = void (*)(); // Function pointer
class EventBus class EventBus
{ {
template <class Event>
constexpr void validateEvent()
{
static_assert(std::is_const<Event>::value == false, "Struct must be without const");
static_assert(std::is_volatile<Event>::value == false, "Struct must be without volatile");
static_assert(std::is_reference<Event>::value == false, "Struct must be without reference");
static_assert(std::is_pointer<Event>::value == false, "Struct must be without pointer");
}
public: public:
EventBus() = default; EventBus() = default;
@ -43,6 +51,8 @@ public:
template <typename Event> template <typename Event>
int listen(const std::function<void(const Event&)>& callback) int listen(const std::function<void(const Event&)>& callback)
{ {
validateEvent<Event>();
const int token = ++_tokener; const int token = ++_tokener;
listen<Event>(token, callback); listen<Event>(token, callback);
return token; return token;
@ -56,6 +66,8 @@ public:
template <typename Event> template <typename Event>
void listen(const int token, const std::function<void(const Event&)>& callback) void listen(const int token, const std::function<void(const Event&)>& callback)
{ {
validateEvent<Event>();
using Vector = VectorImpl<Event>; using Vector = VectorImpl<Event>;
assert(callback && "callback should be valid"); //Check for valid object assert(callback && "callback should be valid"); //Check for valid object
@ -88,6 +100,8 @@ public:
template <typename Event> template <typename Event>
void unlisten(const int token) void unlisten(const int token)
{ {
validateEvent<Event>();
auto found = _callbacks.find(type_id<Event>); auto found = _callbacks.find(type_id<Event>);
if(found != _callbacks.end()) if(found != _callbacks.end())
{ {
@ -103,8 +117,11 @@ public:
template <typename Event> template <typename Event>
void notify(const Event& event) void notify(const Event& event)
{ {
using Vector = VectorImpl<Event>; using CleanEventType = typename std::remove_const<Event>::type;
auto found = _callbacks.find(type_id<Event>); validateEvent<CleanEventType>();
using Vector = VectorImpl<CleanEventType>;
auto found = _callbacks.find(type_id<CleanEventType>);
if(found == _callbacks.end()) if(found == _callbacks.end())
{ {
return; // no such notifications return; // no such notifications
@ -151,9 +168,9 @@ private:
//Invalidation rules: https://stackoverflow.com/questions/6438086/iterator-invalidation-rules //Invalidation rules: https://stackoverflow.com/questions/6438086/iterator-invalidation-rules
auto removeFrom = std::remove_if( auto removeFrom = std::remove_if(
container.begin(), container.end(), [token](const ContainerElement& element) { container.begin(), container.end(), [token](const ContainerElement& element) {
return element.first == token; return element.first == token;
}); });
if(removeFrom != container.end()) if(removeFrom != container.end())
{ {
container.erase(removeFrom, container.end()); container.erase(removeFrom, container.end());