mirror of
https://github.com/gelldur/EventBus.git
synced 2025-01-15 01:58:19 +08:00
EventBus 2.0.0
This commit is contained in:
parent
630e220d43
commit
94973b5779
@ -2,15 +2,13 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.6 FATAL_ERROR)
|
|||||||
|
|
||||||
# BUILD_SHARED_LIBS can controll build type!
|
# BUILD_SHARED_LIBS can controll build type!
|
||||||
PROJECT(EventBus
|
PROJECT(EventBus
|
||||||
VERSION 1.1.0
|
VERSION 2.0.0
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
)
|
)
|
||||||
|
|
||||||
ADD_LIBRARY(EventBus
|
ADD_LIBRARY(EventBus
|
||||||
src/eventbus/EventCollector.cpp include/eventbus/EventCollector.h
|
src/eventbus/EventCollector.cpp include/eventbus/EventCollector.h
|
||||||
src/eventbus/Notification.cpp include/eventbus/Notification.h
|
include/eventbus/Event.h
|
||||||
include/eventbus/Notification2.h
|
|
||||||
include/eventbus/Notifier.h
|
|
||||||
include/eventbus/EventBus.h
|
include/eventbus/EventBus.h
|
||||||
)
|
)
|
||||||
ADD_LIBRARY(Dexode::EventBus ALIAS EventBus)
|
ADD_LIBRARY(Dexode::EventBus ALIAS EventBus)
|
||||||
|
BIN
EventBusDiagram.png
Normal file
BIN
EventBusDiagram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
150
README.md
150
README.md
@ -1,8 +1,156 @@
|
|||||||
# EventBus
|
# EventBus
|
||||||
Simple and very fast event bus
|
Simple and very fast event bus.
|
||||||
|
The EventBus library is a convenient realization of the observer pattern.
|
||||||
|
It works perfectly to supplement the implementation of MVC logic (model-view-controller) in event-driven UIs
|
||||||
|
|
||||||
|
|
||||||
|
![EventBus Diagram](EventBusDiagram.png)
|
||||||
|
|
||||||
|
|
||||||
|
EventBus was created because I want something easy to use and faster than [CCNotificationCenter](https://github.com/cocos2d/cocos2d-x/blob/v2/cocos2dx/support/CCNotificationCenter.h)
|
||||||
|
from [cocos2d-x](https://github.com/cocos2d/cocos2d-x) library. Of course C++11 support was mandatory.
|
||||||
|
|
||||||
|
|
||||||
|
EventBus is:
|
||||||
|
- Fast
|
||||||
|
- Easy to use
|
||||||
|
- Strong typed
|
||||||
|
- Free
|
||||||
|
- Decouples notification senders and receivers
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
Notify by Event object
|
||||||
|
```cpp
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
Dexode::Event<int> simpleEvent{"simple"};
|
||||||
|
//...
|
||||||
|
bus.notify(simpleEvent, 2);//Everyone who listens will receive this notification.
|
||||||
|
```
|
||||||
|
|
||||||
|
Notify without Event object
|
||||||
|
```cpp
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
//...
|
||||||
|
bus.notify<int>("simple", 2);//Everyone who listens will receive this notification.
|
||||||
|
```
|
||||||
|
|
||||||
|
Lambda listener
|
||||||
|
```cpp
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
//...
|
||||||
|
int token = bus.listen<int>("simple", [](int value) // register listener
|
||||||
|
{
|
||||||
|
});
|
||||||
|
//If we want unlisten exact listener we can use token for it
|
||||||
|
bus.unlistenAll(token);
|
||||||
|
```
|
||||||
|
|
||||||
|
Listener is identified by `token`. Token is returned from EventBus::listen methods.
|
||||||
|
We can register multiple listeners on one token.
|
||||||
|
```cpp
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
Dexode::Event<int> event{"simple"};
|
||||||
|
//...
|
||||||
|
int token = bus.listen(event, [](int value) // register listener
|
||||||
|
{
|
||||||
|
});
|
||||||
|
|
||||||
|
bus.listen(token, event, [](int value) // another listener
|
||||||
|
{
|
||||||
|
});
|
||||||
|
|
||||||
|
bus.unlistenAll(token);//Now those two lambdas will be removed from listeners
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don't want handle manually with `token` you can use `EventCollector` class.
|
||||||
|
It is useful when we want have multiple listen in one class. So above example could look like this:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
Dexode::Event<int> event{"simple"};
|
||||||
|
Dexode::EventCollector collector{&bus};
|
||||||
|
//...
|
||||||
|
collector.listen(event, [](int value) // register listener
|
||||||
|
{
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.listen(event, [](int value) // another listener
|
||||||
|
{
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.unlistenAll();//Now those two lambdas will be removed from listeners
|
||||||
|
```
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class Example
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Example(Dexode::EventBus& bus)
|
||||||
|
: _collector{&bus}
|
||||||
|
{
|
||||||
|
_collector.listen<int>("event1", std::bind(&Example::onEvent1, this, std::placeholders::_1));
|
||||||
|
_collector.listen<std::string>("event2", std::bind(&Example::onEvent2, this, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void onEvent1(int value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void onEvent2(std::string value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Dexode::EventCollector _collector;// use RAII
|
||||||
|
};
|
||||||
|
|
||||||
|
//EventCollector sample
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
Example ex{bus};
|
||||||
|
//...
|
||||||
|
bus.notify<int>("event1", 2);
|
||||||
|
```
|
||||||
|
|
||||||
|
# Add to your project
|
||||||
|
|
||||||
|
EventBus can be added as `ADD_SUBDIRECTORY` to your cmake file.
|
||||||
|
Then simply link it via `TARGET_LINK_LIBRARIES`
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
ADD_SUBDIRECTORY(lib/EventBus)
|
||||||
|
ADD_EXECUTABLE(MyExecutable
|
||||||
|
main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
SET_TARGET_PROPERTIES(MyExecutable PROPERTIES
|
||||||
|
CXX_STANDARD 14
|
||||||
|
CXX_STANDARD_REQUIRED YES
|
||||||
|
)
|
||||||
|
|
||||||
|
TARGET_LINK_LIBRARIES(MyExecutable PUBLIC Dexode::EventBus)
|
||||||
|
```
|
||||||
|
|
||||||
|
Also if you want you can install library and add it any other way you want.
|
||||||
|
|
||||||
|
|
||||||
|
# Performance
|
||||||
|
I have prepared some performance results. You can read about them [here](performance/README.md)
|
||||||
|
Small example:
|
||||||
|
|
||||||
|
```
|
||||||
|
check10NotificationsFor1kListeners 273 ns 273 ns 2609987 sum=-1.81219G
|
||||||
|
check10NotificationsFor1kListeners_EventBus2 267 ns 267 ns 2652159 sum=-1.77676G
|
||||||
|
check10NotificationsFor1kListeners_CCNotificationCenter 11172 ns 11171 ns 62865 sum=54.023M
|
||||||
|
```
|
||||||
|
|
||||||
# Thanks to
|
# Thanks to
|
||||||
|
|
||||||
- [stanislawkabacinski](https://github.com/stanislawkabacinski) for fixing windows ;) [53d5026](https://github.com/gelldur/EventBus/commit/53d5026cad24810e82cd8d4a43d58cbfe329c502)
|
- [stanislawkabacinski](https://github.com/stanislawkabacinski) for fixing windows ;) [53d5026](https://github.com/gelldur/EventBus/commit/53d5026cad24810e82cd8d4a43d58cbfe329c502)
|
||||||
- [kuhar](https://github.com/kuhar) for his advice and suggestions for EventBus
|
- [kuhar](https://github.com/kuhar) for his advice and suggestions for EventBus
|
||||||
- [ruslo](https://github.com/ruslo) for this great example: https://github.com/forexample/package-example
|
- [ruslo](https://github.com/ruslo) for this great example: https://github.com/forexample/package-example
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
EventBus source code can be used according to the Apache License, Version 2.0.
|
||||||
|
For more information see [LICENSE](LICENSE) file
|
||||||
|
@ -7,32 +7,32 @@ namespace Dexode
|
|||||||
{
|
{
|
||||||
|
|
||||||
template<typename ... Args>
|
template<typename ... Args>
|
||||||
class Notification2
|
class Event
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Callback = std::function<void(Args...)>;
|
using Callback = std::function<void(Args...)>;
|
||||||
|
|
||||||
constexpr explicit Notification2(const std::string& name)
|
constexpr explicit Event(const std::string& name)
|
||||||
: _key{std::hash<std::string>{}(name + typeid(Callback).name())}
|
: _key{std::hash<std::string>{}(name + typeid(Callback).name())}
|
||||||
, _name{name}
|
, _name{name}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Notification2(const Notification2& other)
|
constexpr Event(const Event& other)
|
||||||
: _key{other._key}
|
: _key{other._key}
|
||||||
, _name{other._name}
|
, _name{other._name}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Notification2(Notification2&& other)
|
Event(Event&& other)
|
||||||
: _key{other._key}
|
: _key{other._key}
|
||||||
, _name{other._name}
|
, _name{other._name}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Notification2& operator=(Notification2&&) = delete;
|
Event& operator=(Event&&) = delete;
|
||||||
|
|
||||||
Notification2& operator=(const Notification2&) = delete;
|
Event& operator=(const Event&) = delete;
|
||||||
|
|
||||||
const size_t getKey() const
|
const size_t getKey() const
|
||||||
{
|
{
|
||||||
@ -44,20 +44,20 @@ public:
|
|||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const Notification2& rhs) const
|
bool operator==(const Event& rhs) const
|
||||||
{
|
{
|
||||||
return _key == rhs._key &&
|
return _key == rhs._key &&
|
||||||
_name == rhs._name;
|
_name == rhs._name;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(const Notification2& rhs) const
|
bool operator!=(const Event& rhs) const
|
||||||
{
|
{
|
||||||
return !(rhs == *this);
|
return !(rhs == *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& stream, const Notification2& notification)
|
friend std::ostream& operator<<(std::ostream& stream, const Event& notification)
|
||||||
{
|
{
|
||||||
stream << "Notification{name: " << notification._name << " key: " << notification._key;
|
stream << "Event{name: " << notification._name << " key: " << notification._key;
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,11 +66,11 @@ private:
|
|||||||
const std::string _name;
|
const std::string _name;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename NotificationType>
|
template<typename EventType>
|
||||||
struct notification_traits;
|
struct event_traits;
|
||||||
|
|
||||||
template<typename ... Args>
|
template<typename ... Args>
|
||||||
struct notification_traits<Notification2<Args...>>
|
struct event_traits<Event<Args...>>
|
||||||
{
|
{
|
||||||
using callback_type = typename std::function<void(Args...)>;
|
using callback_type = typename std::function<void(Args...)>;
|
||||||
};
|
};
|
@ -5,8 +5,9 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include "Notification2.h"
|
#include "Event.h"
|
||||||
|
|
||||||
#if __cplusplus < 201402L
|
#if __cplusplus < 201402L
|
||||||
#error This library needs at least a C++14 compliant compiler
|
#error This library needs at least a C++14 compliant compiler
|
||||||
@ -15,17 +16,12 @@
|
|||||||
namespace Dexode
|
namespace Dexode
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct eventbus_traits
|
struct eventbus_traits
|
||||||
{
|
{
|
||||||
typedef T type;
|
typedef T type;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class EventBus
|
class EventBus
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -45,41 +41,41 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Register listener for notification. Returns token used for unlisten
|
* Register listener for notification. Returns token used for unlisten
|
||||||
*
|
*
|
||||||
* @param notification
|
* @param event
|
||||||
* @param callback - your callback to handle notification
|
* @param callback - your callback to handle notification
|
||||||
* @return token used for unlisten
|
* @return token used for unlisten
|
||||||
*/
|
*/
|
||||||
template<typename ... Args>
|
template<typename ... Args>
|
||||||
int listen(const Notification2<Args...>& notification
|
int listen(const Event<Args...>& event
|
||||||
, typename eventbus_traits<const std::function<void(Args...)>&>::type callback)
|
, typename eventbus_traits<const std::function<void(Args...)>&>::type callback)
|
||||||
{
|
{
|
||||||
const int token = ++_tokener;
|
const int token = ++_tokener;
|
||||||
listen(token, notification, callback);
|
listen(token, event, callback);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register listener for notification. Returns token used for unlisten
|
* Register listener for notification. Returns token used for unlisten
|
||||||
*
|
*
|
||||||
* @param notification - name of your notification
|
* @param eventName - name of your event
|
||||||
* @param callback - your callback to handle notification
|
* @param callback - your callback to handle notification
|
||||||
* @return token used for unlisten
|
* @return token used for unlisten
|
||||||
*/
|
*/
|
||||||
template<typename ... Args>
|
template<typename ... Args>
|
||||||
int listen(const std::string& notificationName
|
int listen(const std::string& eventName
|
||||||
, typename eventbus_traits<const std::function<void(Args...)>&>::type callback)
|
, typename eventbus_traits<const std::function<void(Args...)>&>::type callback)
|
||||||
{
|
{
|
||||||
return listen(Dexode::Notification2<Args...>{notificationName}, callback);
|
return listen(Dexode::Event<Args...>{eventName}, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param token - unique token for identification receiver. Simply pass token from @see EventBus::listen
|
* @param token - unique token for identification receiver. Simply pass token from @see EventBus::listen
|
||||||
* @param notification - pass notification like "getNotificationXYZ()"
|
* @param event - pass notification like "getNotificationXYZ()"
|
||||||
* @param callback - your callback to handle notification
|
* @param callback - your callback to handle notification
|
||||||
*/
|
*/
|
||||||
template<typename ... Args>
|
template<typename ... Args>
|
||||||
void listen(const int token
|
void listen(const int token
|
||||||
, const Notification2<Args...>& notification
|
, const Event<Args...>& event
|
||||||
, typename eventbus_traits<const std::function<void(Args...)>&>::type callback)
|
, typename eventbus_traits<const std::function<void(Args...)>&>::type callback)
|
||||||
{
|
{
|
||||||
using CallbackType = std::function<void(Args...)>;
|
using CallbackType = std::function<void(Args...)>;
|
||||||
@ -87,7 +83,7 @@ public:
|
|||||||
|
|
||||||
assert(callback && "Please set it");//Check for valid object
|
assert(callback && "Please set it");//Check for valid object
|
||||||
|
|
||||||
std::unique_ptr<VectorInterface>& vector = _callbacks[notification.getKey()];
|
std::unique_ptr<VectorInterface>& vector = _callbacks[event.getKey()];
|
||||||
if (vector == nullptr)
|
if (vector == nullptr)
|
||||||
{
|
{
|
||||||
vector.reset(new Vector{});
|
vector.reset(new Vector{});
|
||||||
@ -111,25 +107,25 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param token - token from EventBus::listen
|
* @param token - token from EventBus::listen
|
||||||
* @param notification - notification you wan't to unlisten. @see Notiier::listen
|
* @param event - notification you wan't to unlisten. @see Notiier::listen
|
||||||
*/
|
*/
|
||||||
template<typename NotificationType, typename ... Args>
|
template<typename EventType, typename ... Args>
|
||||||
void unlisten(const int token, const NotificationType& notification)
|
void unlisten(const int token, const EventType& event)
|
||||||
{
|
{
|
||||||
auto found = _callbacks.find(notification.getKey());
|
auto found = _callbacks.find(event.getKey());
|
||||||
if (found != _callbacks.end())
|
if (found != _callbacks.end())
|
||||||
{
|
{
|
||||||
found.second->remove(token);
|
found.second->remove(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename NotificationType, typename ... Args>
|
template<typename EventType, typename ... Args>
|
||||||
void notify(const NotificationType& notification, Args&& ... params)
|
void notify(const EventType& event, Args&& ... params)
|
||||||
{
|
{
|
||||||
using CallbackType = typename notification_traits<NotificationType>::callback_type;
|
using CallbackType = typename event_traits<EventType>::callback_type;
|
||||||
using Vector = VectorImpl<CallbackType>;
|
using Vector = VectorImpl<CallbackType>;
|
||||||
|
|
||||||
auto found = _callbacks.find(notification.getKey());
|
auto found = _callbacks.find(event.getKey());
|
||||||
if (found == _callbacks.end())
|
if (found == _callbacks.end())
|
||||||
{
|
{
|
||||||
return;// no such notifications
|
return;// no such notifications
|
||||||
@ -148,12 +144,12 @@ public:
|
|||||||
|
|
||||||
// We need to call this in form like: notify<int>("yes",value)
|
// We need to call this in form like: notify<int>("yes",value)
|
||||||
// We can't reduce it to notify("yes",value)
|
// We can't reduce it to notify("yes",value)
|
||||||
// It wouldn't be obvious which to call Notification<int> or Notification<int&>
|
// It wouldn't be obvious which to call Event<int> or Event<int&>
|
||||||
// So it can take to a lot of mistakes
|
// So it can take to a lot of mistakes
|
||||||
template<typename ... Args>
|
template<typename ... Args>
|
||||||
void notify(const std::string& notificationName, Args&& ... params)
|
void notify(const std::string& eventName, Args&& ... params)
|
||||||
{
|
{
|
||||||
notify(Dexode::Notification2<Args...>{notificationName}, std::forward<Args>(params)...);
|
notify(Dexode::Event<Args...>{eventName}, std::forward<Args>(params)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "Notifier.h"
|
#include "EventBus.h"
|
||||||
|
|
||||||
namespace Dexode
|
namespace Dexode
|
||||||
{
|
{
|
||||||
@ -14,8 +14,8 @@ namespace Dexode
|
|||||||
class EventCollector
|
class EventCollector
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EventCollector(const std::shared_ptr<Notifier>& notifier);
|
EventCollector(const std::shared_ptr<EventBus>& notifier);
|
||||||
EventCollector(Notifier& notifier = Notifier::getGlobal());
|
EventCollector(EventBus* notifier);
|
||||||
EventCollector(EventCollector const& other);
|
EventCollector(EventCollector const& other);
|
||||||
EventCollector(EventCollector&& other);
|
EventCollector(EventCollector&& other);
|
||||||
|
|
||||||
@ -25,16 +25,16 @@ public:
|
|||||||
EventCollector& operator=(EventCollector&& other);
|
EventCollector& operator=(EventCollector&& other);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register listener for notification. Returns token used to unregister
|
* Register listener for notification.
|
||||||
*
|
*
|
||||||
* @param notification - pass notification like "getNotificationXYZ()"
|
* @param notification - pass notification like "getNotificationXYZ()"
|
||||||
* @param callback - your callback to handle notification
|
* @param callback - your callback to handle notification
|
||||||
*/
|
*/
|
||||||
template<typename ... Args>
|
template<typename ... Args>
|
||||||
void listen(const Notification<Args...>& notification
|
void listen(const Event<Args...>& notification
|
||||||
, typename notifier_traits<const std::function<void(Args...)>&>::type callback)
|
, typename eventbus_traits<const std::function<void(Args...)>&>::type callback)
|
||||||
{
|
{
|
||||||
if (!callback)
|
if (!callback || !_notifier)
|
||||||
{
|
{
|
||||||
return;//Skip such things
|
return;//Skip such things
|
||||||
}
|
}
|
||||||
@ -48,6 +48,20 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register listener for notification. Returns token used for unlisten
|
||||||
|
*
|
||||||
|
* @param notification - name of your notification
|
||||||
|
* @param callback - your callback to handle notification
|
||||||
|
* @return token used for unlisten
|
||||||
|
*/
|
||||||
|
template<typename ... Args>
|
||||||
|
void listen(const std::string& notificationName
|
||||||
|
, typename eventbus_traits<const std::function<void(Args...)>&>::type callback)
|
||||||
|
{
|
||||||
|
listen(Dexode::Event<Args...>{notificationName}, callback);
|
||||||
|
}
|
||||||
|
|
||||||
void unlistenAll();
|
void unlistenAll();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,12 +70,15 @@ public:
|
|||||||
template<typename NotificationType, typename ... Args>
|
template<typename NotificationType, typename ... Args>
|
||||||
void unlisten(const NotificationType& notification)
|
void unlisten(const NotificationType& notification)
|
||||||
{
|
{
|
||||||
_notifier->unlisten(_token, notification);
|
if (_notifier)
|
||||||
|
{
|
||||||
|
_notifier->unlisten(_token, notification);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _token = 0;
|
int _token = 0;
|
||||||
std::shared_ptr<Notifier> _notifier;
|
std::shared_ptr<EventBus> _notifier;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ check1kNotificationsFor1kListeners_CCNotificationCenter 9711 ns
|
|||||||
-----------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------
|
||||||
checkNotifyFor10kListenersWhenNoOneListens 2 ns 2 ns 399367972 sum=0
|
checkNotifyFor10kListenersWhenNoOneListens 2 ns 2 ns 399367972 sum=0
|
||||||
checkNotifyFor10kListenersWhenNoOneListens_EventBus2 2 ns 2 ns 400616370 sum=0
|
checkNotifyFor10kListenersWhenNoOneListens_EventBus2 2 ns 2 ns 400616370 sum=0
|
||||||
checkNotifyFor10kListenersWhenNoOneListens_CCNotificationCenter 125173 ns 125162 ns 5657 sum=0```
|
checkNotifyFor10kListenersWhenNoOneListens_CCNotificationCenter 125173 ns 125162 ns 5657 sum=0
|
||||||
-----------------------------------------------------------------------------------------------------------------------
|
-----------------------------------------------------------------------------------------------------------------------
|
||||||
checkSimpleNotification 7 ns 7 ns 100833112 sum=384.648M
|
checkSimpleNotification 7 ns 7 ns 100833112 sum=384.648M
|
||||||
checkSimpleNotification_EventBus2 5 ns 5 ns 144959897 sum=552.978M
|
checkSimpleNotification_EventBus2 5 ns 5 ns 144959897 sum=552.978M
|
||||||
|
@ -16,7 +16,7 @@ void checkNListeners(benchmark::State& state, const int listenersCount)
|
|||||||
Dexode::EventBus bus;
|
Dexode::EventBus bus;
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
|
|
||||||
Dexode::Notification2<int> simpleNotification("simple");
|
Dexode::Event<int> simpleNotification("simple");
|
||||||
for (int i = 0; i < listenersCount; ++i)
|
for (int i = 0; i < listenersCount; ++i)
|
||||||
{
|
{
|
||||||
bus.listen(simpleNotification, [&](int value)
|
bus.listen(simpleNotification, [&](int value)
|
||||||
@ -82,7 +82,7 @@ void checkNNotificationsForNListeners(benchmark::State& state, const int notific
|
|||||||
std::uniform_int_distribution<int> uniformDistribution(0, notificationsCount - 1);
|
std::uniform_int_distribution<int> uniformDistribution(0, notificationsCount - 1);
|
||||||
|
|
||||||
//We generate here N different notifications
|
//We generate here N different notifications
|
||||||
std::vector<Dexode::Notification2<int>> notifications;
|
std::vector<Dexode::Event<int>> notifications;
|
||||||
notifications.reserve(notificationsCount);
|
notifications.reserve(notificationsCount);
|
||||||
for (int i = 0; i < notificationsCount; ++i)
|
for (int i = 0; i < notificationsCount; ++i)
|
||||||
{
|
{
|
||||||
@ -132,8 +132,8 @@ void check100NotificationsFor10kListeners_EventBus2(benchmark::State& state)
|
|||||||
void checkNotifyFor10kListenersWhenNoOneListens_EventBus2(benchmark::State& state)
|
void checkNotifyFor10kListenersWhenNoOneListens_EventBus2(benchmark::State& state)
|
||||||
{
|
{
|
||||||
Dexode::EventBus bus;
|
Dexode::EventBus bus;
|
||||||
Dexode::Notification2<int> simpleNotification("simple");
|
Dexode::Event<int> simpleNotification("simple");
|
||||||
Dexode::Notification2<int> unknownNotification("unknown");
|
Dexode::Event<int> unknownNotification("unknown");
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for (int i = 0; i < 10000; ++i)
|
for (int i = 0; i < 10000; ++i)
|
||||||
{
|
{
|
||||||
|
@ -4,10 +4,12 @@
|
|||||||
|
|
||||||
#include <eventbus/EventCollector.h>
|
#include <eventbus/EventCollector.h>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
void null_deleter(Dexode::Notifier*)
|
void null_deleter(Dexode::EventBus*)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,17 +18,16 @@ void null_deleter(Dexode::Notifier*)
|
|||||||
namespace Dexode
|
namespace Dexode
|
||||||
{
|
{
|
||||||
|
|
||||||
EventCollector::EventCollector(const std::shared_ptr<Notifier>& notifier)
|
EventCollector::EventCollector(const std::shared_ptr<EventBus>& notifier)
|
||||||
: _notifier(notifier)
|
: _notifier(notifier)
|
||||||
{
|
{
|
||||||
assert(_notifier);
|
assert(_notifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Maybe ugly but hey ;) Less code and simply i can :D
|
//Maybe ugly but hey ;) Less code and simply i can :D
|
||||||
EventCollector::EventCollector(Notifier& notifier)
|
EventCollector::EventCollector(EventBus* notifier)
|
||||||
: _notifier(¬ifier, &null_deleter)
|
: _notifier(notifier, &null_deleter)
|
||||||
{
|
{
|
||||||
assert(_notifier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EventCollector::EventCollector(EventCollector const& other)
|
EventCollector::EventCollector(EventCollector const& other)
|
||||||
@ -79,7 +80,7 @@ EventCollector& EventCollector::operator=(EventCollector&& other)
|
|||||||
|
|
||||||
void EventCollector::unlistenAll()
|
void EventCollector::unlistenAll()
|
||||||
{
|
{
|
||||||
if (_token != 0)
|
if (_token != 0 && _notifier)
|
||||||
{
|
{
|
||||||
_notifier->unlistenAll(_token);
|
_notifier->unlistenAll(_token);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
ADD_EXECUTABLE(EventBusTest
|
ADD_EXECUTABLE(EventBusTest
|
||||||
eventbus/EventCollectorTest.cpp
|
eventbus/EventCollectorTest.cpp
|
||||||
eventbus/NotifierTest.cpp
|
eventbus/NotifierTest.cpp
|
||||||
eventbus/NotificationTest.cpp)
|
eventbus/NotificationTest.cpp
|
||||||
|
eventbus/sample.cpp
|
||||||
|
)
|
||||||
|
|
||||||
SET_TARGET_PROPERTIES(EventBusTest PROPERTIES
|
SET_TARGET_PROPERTIES(EventBusTest PROPERTIES
|
||||||
CXX_STANDARD 14
|
CXX_STANDARD 14
|
||||||
|
@ -6,65 +6,57 @@
|
|||||||
|
|
||||||
#include <eventbus/EventCollector.h>
|
#include <eventbus/EventCollector.h>
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
MAKE_NOTIFICATION(SimpleNotification, int);
|
|
||||||
|
|
||||||
MAKE_NOTIFICATION(RefNotification, int &);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("eventbus/EventCollector sample", "Simple test for EventCollector")
|
TEST_CASE("eventbus/EventCollector sample", "Simple test for EventCollector")
|
||||||
{
|
{
|
||||||
Dexode::Notifier bus;
|
Dexode::EventBus bus;
|
||||||
int callCount = 0;
|
int callCount = 0;
|
||||||
{
|
{
|
||||||
Dexode::EventCollector listener{bus};
|
Dexode::EventCollector listener{&bus};
|
||||||
listener.listen(getNotificationSimpleNotification(), [&](int value)
|
listener.listen<int>("simple", [&](int value)
|
||||||
{
|
{
|
||||||
REQUIRE(value == 3);
|
REQUIRE(value == 3);
|
||||||
++callCount;
|
++callCount;
|
||||||
});
|
});
|
||||||
bus.notify(getNotificationSimpleNotification(), 3);
|
bus.notify<int>("simple", 3);
|
||||||
REQUIRE(callCount == 1);
|
REQUIRE(callCount == 1);
|
||||||
}
|
}
|
||||||
bus.notify(getNotificationSimpleNotification(), 2);
|
bus.notify<int>("simple", 2);
|
||||||
REQUIRE(callCount == 1);
|
REQUIRE(callCount == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("eventbus/EventCollector unlistenAll", "EventCollector::unlistenAll")
|
TEST_CASE("eventbus/EventCollector unlistenAll", "EventCollector::unlistenAll")
|
||||||
{
|
{
|
||||||
Dexode::Notifier bus;
|
Dexode::EventBus bus;
|
||||||
Dexode::EventCollector listener{bus};
|
Dexode::EventCollector listener{&bus};
|
||||||
|
|
||||||
int callCount = 0;
|
int callCount = 0;
|
||||||
listener.listen(getNotificationSimpleNotification(), [&](int value)
|
listener.listen<int>("simple", [&](int value)
|
||||||
{
|
{
|
||||||
REQUIRE(value == 3);
|
REQUIRE(value == 3);
|
||||||
++callCount;
|
++callCount;
|
||||||
});
|
});
|
||||||
bus.notify(getNotificationSimpleNotification(), 3);
|
bus.notify<int>("simple", 3);
|
||||||
listener.unlistenAll();
|
listener.unlistenAll();
|
||||||
|
|
||||||
bus.notify(getNotificationSimpleNotification(), 2);
|
bus.notify<int>("simple", 2);
|
||||||
REQUIRE(callCount == 1);
|
REQUIRE(callCount == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("eventbus/EventCollector reset", "EventCollector reset when we reasign")
|
TEST_CASE("eventbus/EventCollector reset", "EventCollector reset when we reasign")
|
||||||
{
|
{
|
||||||
Dexode::Notifier bus;
|
Dexode::EventBus bus;
|
||||||
int callCount = 0;
|
int callCount = 0;
|
||||||
Dexode::EventCollector listener{bus};
|
Dexode::EventCollector listener{&bus};
|
||||||
listener.listen(getNotificationSimpleNotification(), [&](int value)
|
Dexode::Event<int> simple{"simple"};
|
||||||
|
listener.listen(simple, [&](int value)
|
||||||
{
|
{
|
||||||
REQUIRE(value == 3);
|
REQUIRE(value == 3);
|
||||||
++callCount;
|
++callCount;
|
||||||
});
|
});
|
||||||
bus.notify(getNotificationSimpleNotification(), 3);
|
bus.notify(simple, 3);
|
||||||
REQUIRE(callCount == 1);
|
REQUIRE(callCount == 1);
|
||||||
listener = {};
|
listener = {nullptr};
|
||||||
|
|
||||||
bus.notify(getNotificationSimpleNotification(), 2);
|
bus.notify(simple, 2);
|
||||||
REQUIRE(callCount == 1);
|
REQUIRE(callCount == 1);
|
||||||
}
|
}
|
||||||
|
@ -3,49 +3,49 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <catch.hpp>
|
#include <catch.hpp>
|
||||||
#include <eventbus/Notification2.h>
|
#include <eventbus/Event.h>
|
||||||
|
|
||||||
TEST_CASE("eventbus/Notification same", "Notifications should be same")
|
TEST_CASE("eventbus/Event same", "Notifications should be same")
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Dexode::Notification2<int> one("one");
|
Dexode::Event<int> one("one");
|
||||||
Dexode::Notification2<int> two("one");
|
Dexode::Event<int> two("one");
|
||||||
REQUIRE(one == two);
|
REQUIRE(one == two);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Dexode::Notification2<int> one("one");
|
Dexode::Event<int> one("one");
|
||||||
Dexode::Notification2<signed> two("one");
|
Dexode::Event<signed> two("one");
|
||||||
REQUIRE(one == two);//int == signed
|
REQUIRE(one == two);//int == signed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("eventbus/Notification not same", "Notifications should different")
|
TEST_CASE("eventbus/Event not same", "Notifications should different")
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Dexode::Notification2<int> one("one");
|
Dexode::Event<int> one("one");
|
||||||
Dexode::Notification2<int> two("two");
|
Dexode::Event<int> two("two");
|
||||||
REQUIRE(one != two);
|
REQUIRE(one != two);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Dexode::Notification2<int> one("one");
|
Dexode::Event<int> one("one");
|
||||||
Dexode::Notification2<int&> two("two");
|
Dexode::Event<int&> two("two");
|
||||||
//REQUIRE(one != two); //Different types!
|
//REQUIRE(one != two); //Different types!
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Dexode::Notification2<unsigned> one("one");
|
Dexode::Event<unsigned> one("one");
|
||||||
Dexode::Notification2<signed> two("one");
|
Dexode::Event<signed> two("one");
|
||||||
//REQUIRE(one != two); //Different types!
|
//REQUIRE(one != two); //Different types!
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Dexode::Notification2<int, int> one("one");
|
Dexode::Event<int, int> one("one");
|
||||||
Dexode::Notification2<int, unsigned> two("one");
|
Dexode::Event<int, unsigned> two("one");
|
||||||
//REQUIRE(one != two); //Different types!
|
//REQUIRE(one != two); //Different types!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("eventbus/Notification should copy constructable", "Notifications should be copy constructable")
|
TEST_CASE("eventbus/Event should copy constructable", "Notifications should be copy constructable")
|
||||||
{
|
{
|
||||||
Dexode::Notification2<int> one("one");
|
Dexode::Event<int> one("one");
|
||||||
Dexode::Notification2<int> two = one;
|
Dexode::Event<int> two = one;
|
||||||
REQUIRE(one == two);
|
REQUIRE(one == two);
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
TEST_CASE("eventbus/Simple test", "Simple test")
|
TEST_CASE("eventbus/Simple test", "Simple test")
|
||||||
{
|
{
|
||||||
Dexode::EventBus bus;
|
Dexode::EventBus bus;
|
||||||
Dexode::Notification2<int> simpleNotification{"simple"};
|
Dexode::Event<int> simpleNotification{"simple"};
|
||||||
|
|
||||||
const auto token = bus.listen(simpleNotification, [](int value)
|
const auto token = bus.listen(simpleNotification, [](int value)
|
||||||
{
|
{
|
||||||
@ -31,8 +31,8 @@ TEST_CASE("eventbus/Simple test", "Simple test")
|
|||||||
TEST_CASE("eventbus/Multiple listen on same token", "Listening on the same token")
|
TEST_CASE("eventbus/Multiple listen on same token", "Listening on the same token")
|
||||||
{
|
{
|
||||||
Dexode::EventBus bus;
|
Dexode::EventBus bus;
|
||||||
Dexode::Notification2<int> simpleNotification{"simple"};
|
Dexode::Event<int> simpleNotification{"simple"};
|
||||||
Dexode::Notification2<int&> simpleRefNotification{"simple"};
|
Dexode::Event<int&> simpleRefNotification{"simple"};
|
||||||
const auto token = bus.listen(simpleRefNotification, [](int& value)
|
const auto token = bus.listen(simpleRefNotification, [](int& value)
|
||||||
{
|
{
|
||||||
REQUIRE(value == 3);
|
REQUIRE(value == 3);
|
||||||
@ -63,7 +63,7 @@ TEST_CASE("eventbus/EventBus listen", "Listen without notification object. Using
|
|||||||
REQUIRE(value == 3);
|
REQUIRE(value == 3);
|
||||||
});
|
});
|
||||||
|
|
||||||
Dexode::Notification2<int> simpleNotification{"simple"};
|
Dexode::Event<int> simpleNotification{"simple"};
|
||||||
REQUIRE(isCalled == 0);
|
REQUIRE(isCalled == 0);
|
||||||
bus.notify(simpleNotification, 3);
|
bus.notify(simpleNotification, 3);
|
||||||
REQUIRE(isCalled == 1);
|
REQUIRE(isCalled == 1);
|
||||||
@ -104,3 +104,44 @@ TEST_CASE("eventbus/EventBus listen & notify", "Listen & notify without notifica
|
|||||||
bus.notify<int>("simple", 1);
|
bus.notify<int>("simple", 1);
|
||||||
REQUIRE(isCalled == 2);
|
REQUIRE(isCalled == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("eventbus/EventBus type conversion", "Check for type conversion")
|
||||||
|
{
|
||||||
|
class Example
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Example(Dexode::EventBus& bus)
|
||||||
|
{
|
||||||
|
Dexode::Event<int> event{"event1"};
|
||||||
|
_token = bus.listen(event, std::bind(&Example::onEvent1, this, std::placeholders::_1));
|
||||||
|
bus.listen(_token, event, std::bind(&Example::onEvent2, this, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
int calledEvent1 = 0;
|
||||||
|
|
||||||
|
void onEvent1(int value)
|
||||||
|
{
|
||||||
|
++calledEvent1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int calledEvent2 = 0;
|
||||||
|
|
||||||
|
void onEvent2(bool value)
|
||||||
|
{
|
||||||
|
++calledEvent2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _token;
|
||||||
|
};
|
||||||
|
|
||||||
|
//EventCollector sample
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
Example ex{bus};
|
||||||
|
|
||||||
|
REQUIRE(ex.calledEvent1 == 0);
|
||||||
|
REQUIRE(ex.calledEvent2 == 0);
|
||||||
|
bus.notify<int>("event1", 2);
|
||||||
|
REQUIRE(ex.calledEvent1 == 1);
|
||||||
|
REQUIRE(ex.calledEvent2 == 0);
|
||||||
|
}
|
||||||
|
104
test/eventbus/sample.cpp
Normal file
104
test/eventbus/sample.cpp
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
//
|
||||||
|
// Created by Dawid Drozd aka Gelldur on 06.08.17.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <eventbus/EventBus.h>
|
||||||
|
#include <eventbus/EventCollector.h>
|
||||||
|
|
||||||
|
void sampleUsages()
|
||||||
|
{
|
||||||
|
|
||||||
|
{
|
||||||
|
//Notify by Event object
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
Dexode::Event<int> simpleEvent{"simple"};
|
||||||
|
//...
|
||||||
|
bus.notify(simpleEvent, 2);//Everyone who listens will receive this notification.
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Notify without Event object
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
//...
|
||||||
|
bus.notify<int>("simple", 2);//Everyone who listens will receive this notification.
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Lambda listener
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
//...
|
||||||
|
int token = bus.listen<int>("simple", [](int value) // register listener
|
||||||
|
{
|
||||||
|
});
|
||||||
|
//If we want unlisten exact listener we can use token for it
|
||||||
|
bus.unlistenAll(token);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Unlisten everyone who is waiting for event X //TODO
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
Dexode::Event<int> event{"simple"};
|
||||||
|
//...
|
||||||
|
int token = bus.listen(event, [](int value) // register listener
|
||||||
|
{
|
||||||
|
});
|
||||||
|
//If we want unlisten exact listener we can use token for it
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//Listen on some token
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
Dexode::Event<int> event{"simple"};
|
||||||
|
//...
|
||||||
|
int token = bus.listen(event, [](int value) // register listener
|
||||||
|
{
|
||||||
|
});
|
||||||
|
|
||||||
|
bus.listen(token, event, [](int value) // another listener
|
||||||
|
{
|
||||||
|
});
|
||||||
|
|
||||||
|
bus.unlistenAll(token);//Now those two lambdas will be removed from listeners
|
||||||
|
}
|
||||||
|
{
|
||||||
|
//EventCollector sample
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
Dexode::Event<int> event{"simple"};
|
||||||
|
Dexode::EventCollector collector{&bus};
|
||||||
|
//...
|
||||||
|
collector.listen(event, [](int value) // register listener
|
||||||
|
{
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.listen(event, [](int value) // another listener
|
||||||
|
{
|
||||||
|
});
|
||||||
|
|
||||||
|
collector.unlistenAll();//Now those two lambdas will be removed from listeners
|
||||||
|
}
|
||||||
|
{
|
||||||
|
class Example
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Example(Dexode::EventBus& bus)
|
||||||
|
: _collector{&bus}
|
||||||
|
{
|
||||||
|
_collector.listen<int>("event1", std::bind(&Example::onEvent1, this, std::placeholders::_1));
|
||||||
|
_collector.listen<std::string>("event2", std::bind(&Example::onEvent2, this, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void onEvent1(int value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void onEvent2(std::string value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Dexode::EventCollector _collector;// use RAII
|
||||||
|
};
|
||||||
|
|
||||||
|
//EventCollector sample
|
||||||
|
Dexode::EventBus bus;
|
||||||
|
Example ex{bus};
|
||||||
|
//...
|
||||||
|
bus.notify<int>("event1", 2);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user