EventBus 2.0.0

This commit is contained in:
Dawid Drozd 2017-08-06 11:22:59 +02:00
parent 630e220d43
commit 94973b5779
14 changed files with 411 additions and 112 deletions

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

150
README.md
View File

@ -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

View 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...)>;
}; };

View File

@ -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:

View File

@ -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;
}; };
} }

View File

@ -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

View File

@ -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)
{ {

View File

@ -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(&notifier, &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);
} }

View File

@ -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

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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
View 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);
}
}