1
0
mirror of https://github.com/wqking/eventpp.git synced 2024-12-27 00:17:02 +08:00

tab->spaces in documents for easier read

This commit is contained in:
wqking 2022-02-04 09:00:50 +08:00
parent 05f3dc8249
commit 6e5f6ee45d
25 changed files with 815 additions and 815 deletions

View File

@ -54,9 +54,9 @@ A typical implementation of `Digester`:
template <typename T> template <typename T>
struct MyDigest struct MyDigest
{ {
TheDigestTypeSuchAsSizeT operator() (const T & value) const { TheDigestTypeSuchAsSizeT operator() (const T & value) const {
// compute the digest of value and return the digest. // compute the digest of value and return the digest.
} }
}; };
``` ```
Note: the return type of the function call operator (here is TheDigestTypeSuchAsSizeT) must be the same for all T, it can't be different type for different T. Note: the return type of the function call operator (here is TheDigestTypeSuchAsSizeT) must be the same for all T, it can't be different type for different T.
@ -65,12 +65,12 @@ A typical implementation of `Storage`:
```c++ ```c++
struct MyStorage struct MyStorage
{ {
template <typename T> template <typename T>
MyStorage(const T & value) { MyStorage(const T & value) {
// store the value // store the value
} }
// any other member functions can be added, such as getting the underlying value. // any other member functions can be added, such as getting the underlying value.
}; };
``` ```
Or none template version: Or none template version:
@ -78,10 +78,10 @@ Or none template version:
// In this version, only value of `int` and `std::string` can be stored. // In this version, only value of `int` and `std::string` can be stored.
struct MyStorage struct MyStorage
{ {
MyStorage(const int value) {} MyStorage(const int value) {}
MyStorage(const std::string & value) {} MyStorage(const std::string & value) {}
// any other member functions can be added, such as getting the underlying value. // any other member functions can be added, such as getting the underlying value.
}; };
``` ```

View File

@ -70,74 +70,74 @@ Below is the example code to demonstrate how to use `argumentAdapter`. There are
// Define the event types // Define the event types
enum class EventType enum class EventType
{ {
// for MouseEvent // for MouseEvent
mouse, mouse,
// for KeyEvent // for KeyEvent
key, key,
// for MessageEvent // for MessageEvent
message, message,
// For either MouseEvent or KeyEvent, we use this type to demonstrate // For either MouseEvent or KeyEvent, we use this type to demonstrate
// how to use conditionalFunctor // how to use conditionalFunctor
input, input,
}; };
class Event class Event
{ {
public: public:
Event() { Event() {
} }
// Make the Event polymorphism so we can use dynamic_cast to detect // Make the Event polymorphism so we can use dynamic_cast to detect
// if it's a MouseEvent or KeyEvent // if it's a MouseEvent or KeyEvent
virtual ~Event() { virtual ~Event() {
} }
}; };
class MouseEvent : public Event class MouseEvent : public Event
{ {
public: public:
MouseEvent(const int x, const int y) MouseEvent(const int x, const int y)
: x(x), y(y) : x(x), y(y)
{ {
} }
int getX() const { return x; } int getX() const { return x; }
int getY() const { return y; } int getY() const { return y; }
private: private:
int x; int x;
int y; int y;
}; };
class KeyEvent : public Event class KeyEvent : public Event
{ {
public: public:
explicit KeyEvent(const int key) explicit KeyEvent(const int key)
: key(key) : key(key)
{ {
} }
int getKey() const { return key; } int getKey() const { return key; }
private: private:
int key; int key;
}; };
class MessageEvent : public Event class MessageEvent : public Event
{ {
public: public:
explicit MessageEvent(const std::string & message) explicit MessageEvent(const std::string & message)
: message(message) { : message(message) {
} }
std::string getMessage() const { return message; } std::string getMessage() const { return message; }
private: private:
std::string message; std::string message;
}; };
// A free function that will be added as listener later. // A free function that will be added as listener later.
@ -145,61 +145,61 @@ private:
// lambda, functor object, std::function, free function, etc. // lambda, functor object, std::function, free function, etc.
void tutorialArgumentAdapterFreeFunction(const MouseEvent & e) void tutorialArgumentAdapterFreeFunction(const MouseEvent & e)
{ {
std::cout << "Received MouseEvent in free function, x=" << e.getX() << " y=" << e.getY() << std::endl; std::cout << "Received MouseEvent in free function, x=" << e.getX() << " y=" << e.getY() << std::endl;
} }
void example1() void example1()
{ {
eventpp::EventDispatcher<EventType, void (const Event &)> eventDispatcher; eventpp::EventDispatcher<EventType, void (const Event &)> eventDispatcher;
// callback 1 -- lambda, or any functor object // callback 1 -- lambda, or any functor object
// This can't compile because a 'const Event &' can be passed to 'const MouseEvent &' // This can't compile because a 'const Event &' can be passed to 'const MouseEvent &'
//eventDispatcher.appendListener(mouseEventId, [](const MouseEvent & e) {}); //eventDispatcher.appendListener(mouseEventId, [](const MouseEvent & e) {});
// This compiles. eventpp::argumentAdapter creates a functor object that static_cast // This compiles. eventpp::argumentAdapter creates a functor object that static_cast
// 'const Event &' to 'const MouseEvent &' automatically. // 'const Event &' to 'const MouseEvent &' automatically.
// Note we need to pass the function type to eventpp::argumentAdapter because the lambda // Note we need to pass the function type to eventpp::argumentAdapter because the lambda
// doesn't have any function type information and eventpp::argumentAdapter can't deduce // doesn't have any function type information and eventpp::argumentAdapter can't deduce
// the type. This rule also applies to other functor object. // the type. This rule also applies to other functor object.
eventDispatcher.appendListener( eventDispatcher.appendListener(
EventType::mouse, EventType::mouse,
eventpp::argumentAdapter<void(const MouseEvent &)>([](const MouseEvent & e) { eventpp::argumentAdapter<void(const MouseEvent &)>([](const MouseEvent & e) {
std::cout << "Received MouseEvent in lambda, x=" << e.getX() << " y=" << e.getY() << std::endl; std::cout << "Received MouseEvent in lambda, x=" << e.getX() << " y=" << e.getY() << std::endl;
}) })
); );
eventDispatcher.appendListener( eventDispatcher.appendListener(
EventType::message, EventType::message,
eventpp::argumentAdapter<void(const MessageEvent &)>([](const MessageEvent & e) { eventpp::argumentAdapter<void(const MessageEvent &)>([](const MessageEvent & e) {
std::cout << "Received MessageEvent in lambda, message=" << e.getMessage() << std::endl; std::cout << "Received MessageEvent in lambda, message=" << e.getMessage() << std::endl;
}) })
); );
// callback 2 -- std::function // callback 2 -- std::function
// We don't need to pass the function type to eventpp::argumentAdapter because it can // We don't need to pass the function type to eventpp::argumentAdapter because it can
// deduce the type from the std::function // deduce the type from the std::function
eventDispatcher.appendListener( eventDispatcher.appendListener(
EventType::key, EventType::key,
eventpp::argumentAdapter(std::function<void(const KeyEvent &)>([](const KeyEvent & e) { eventpp::argumentAdapter(std::function<void(const KeyEvent &)>([](const KeyEvent & e) {
std::cout << "Received KeyEvent in std::function, key=" << e.getKey() << std::endl; std::cout << "Received KeyEvent in std::function, key=" << e.getKey() << std::endl;
})) }))
); );
// callback 3 -- free function // callback 3 -- free function
// We don't need to pass the function type to eventpp::argumentAdapter because it can // We don't need to pass the function type to eventpp::argumentAdapter because it can
// deduce the type from the free function // deduce the type from the free function
eventDispatcher.appendListener( eventDispatcher.appendListener(
EventType::mouse, EventType::mouse,
eventpp::argumentAdapter(tutorialArgumentAdapterFreeFunction) eventpp::argumentAdapter(tutorialArgumentAdapterFreeFunction)
); );
eventDispatcher.dispatch(EventType::mouse, MouseEvent(3, 5)); eventDispatcher.dispatch(EventType::mouse, MouseEvent(3, 5));
eventDispatcher.dispatch(EventType::key, KeyEvent(255)); eventDispatcher.dispatch(EventType::key, KeyEvent(255));
eventDispatcher.dispatch(EventType::message, MessageEvent("Hello, argumentAdapter")); eventDispatcher.dispatch(EventType::message, MessageEvent("Hello, argumentAdapter"));
// In syntax we can dispatch KeyEvent under EventType::mouse, in our case, // In syntax we can dispatch KeyEvent under EventType::mouse, in our case,
// the EventType::mouse listener casts KeyEvent to MouseEvent, which is invalid object, // the EventType::mouse listener casts KeyEvent to MouseEvent, which is invalid object,
// and the listener will either use garbled data, or crash. // and the listener will either use garbled data, or crash.
//eventDispatcher.dispatch(EventType::mouse, KeyEvent(255)); //eventDispatcher.dispatch(EventType::mouse, KeyEvent(255));
} }
void example2() void example2()
@ -212,25 +212,25 @@ eventpp::EventDispatcher<EventType, void(const Event &)> eventDispatcher;
// listener 1 // listener 1
eventDispatcher.appendListener( eventDispatcher.appendListener(
EventType::input, EventType::input,
eventpp::conditionalFunctor( eventpp::conditionalFunctor(
eventpp::argumentAdapter<void(const MouseEvent &)>([](const MouseEvent & e) { eventpp::argumentAdapter<void(const MouseEvent &)>([](const MouseEvent & e) {
std::cout << "Received MouseEvent in conditional tutorial, x=" << e.getX() << " y=" << e.getY() << std::endl; std::cout << "Received MouseEvent in conditional tutorial, x=" << e.getX() << " y=" << e.getY() << std::endl;
}), }),
// This lambda is the condition. We use dynamic_cast to check if the event is desired. // This lambda is the condition. We use dynamic_cast to check if the event is desired.
// This is for demonstration purpose, in production you may use a better way than dynamic_cast. // This is for demonstration purpose, in production you may use a better way than dynamic_cast.
[](const Event & e) { return dynamic_cast<const MouseEvent *>(&e) != nullptr; } [](const Event & e) { return dynamic_cast<const MouseEvent *>(&e) != nullptr; }
) )
); );
// listener 2 // listener 2
eventDispatcher.appendListener( eventDispatcher.appendListener(
EventType::input, EventType::input,
eventpp::conditionalFunctor( eventpp::conditionalFunctor(
eventpp::argumentAdapter<void(const KeyEvent &)>([](const KeyEvent & e) { eventpp::argumentAdapter<void(const KeyEvent &)>([](const KeyEvent & e) {
std::cout << "Received KeyEvent in conditional tutorial, key=" << e.getKey() << std::endl; std::cout << "Received KeyEvent in conditional tutorial, key=" << e.getKey() << std::endl;
}), }),
[](const Event & e) { return dynamic_cast<const KeyEvent *>(&e) != nullptr; } [](const Event & e) { return dynamic_cast<const KeyEvent *>(&e) != nullptr; }
) )
); );
// listener 1 will receive this event, listener 2 will not. // listener 1 will receive this event, listener 2 will not.
@ -255,10 +255,10 @@ eventpp::EventQueue<EventType, void(std::shared_ptr<Event>)> eventQueue;
// This compiles. eventpp::argumentAdapter creates a functor object that static_cast // This compiles. eventpp::argumentAdapter creates a functor object that static_cast
// 'std::shared_ptr<Event>' to 'std::shared_ptr<MouseEvent>' automatically. // 'std::shared_ptr<Event>' to 'std::shared_ptr<MouseEvent>' automatically.
eventQueue.appendListener( eventQueue.appendListener(
EventType::mouse, EventType::mouse,
eventpp::argumentAdapter<void(std::shared_ptr<MouseEvent>)>([](std::shared_ptr<MouseEvent> e) { eventpp::argumentAdapter<void(std::shared_ptr<MouseEvent>)>([](std::shared_ptr<MouseEvent> e) {
std::cout << "Received MouseEvent as std::shared_ptr, x=" << e->getX() << " y=" << e->getY() << std::endl; std::cout << "Received MouseEvent as std::shared_ptr, x=" << e->getX() << " y=" << e->getY() << std::endl;
}) })
); );
eventQueue.enqueue(EventType::mouse, std::make_shared<MouseEvent>(3, 5)); eventQueue.enqueue(EventType::mouse, std::make_shared<MouseEvent>(3, 5));

View File

@ -8,40 +8,40 @@ Time unit: milliseconds (unless explicitly specified)
<table> <table>
<tr> <tr>
<th>Iterations</th> <th>Iterations</th>
<th>Queue size</th> <th>Queue size</th>
<th>Event count</th> <th>Event count</th>
<th>Event Types</th> <th>Event Types</th>
<th>Listener count</th> <th>Listener count</th>
<th>Time of single threading</th> <th>Time of single threading</th>
<th>Time of multi threading</th> <th>Time of multi threading</th>
</tr> </tr>
<tr> <tr>
<td>100k</td> <td>100k</td>
<td>100</td> <td>100</td>
<td>10M</td> <td>10M</td>
<td>100</td> <td>100</td>
<td>100</td> <td>100</td>
<td>401</td> <td>401</td>
<td>1146</td> <td>1146</td>
</tr> </tr>
<tr> <tr>
<td>100k</td> <td>100k</td>
<td>1000</td> <td>1000</td>
<td>100M</td> <td>100M</td>
<td>100</td> <td>100</td>
<td>100</td> <td>100</td>
<td>4012</td> <td>4012</td>
<td>11467</td> <td>11467</td>
</tr> </tr>
<tr> <tr>
<td>100k</td> <td>100k</td>
<td>1000</td> <td>1000</td>
<td>100M</td> <td>100M</td>
<td>1000</td> <td>1000</td>
<td>1000</td> <td>1000</td>
<td>4102</td> <td>4102</td>
<td>11600</td> <td>11600</td>
</tr> </tr>
<table> <table>
@ -53,107 +53,107 @@ The EventQueue is processed in one thread. The Single/Multi threading in the tab
<table> <table>
<tr> <tr>
<th>Mutex</th> <th>Mutex</th>
<th>Enqueue threads</th> <th>Enqueue threads</th>
<th>Process threads</th> <th>Process threads</th>
<th>Event count</th> <th>Event count</th>
<th>Event Types</th> <th>Event Types</th>
<th>Listener count</th> <th>Listener count</th>
<th>Time</th> <th>Time</th>
</tr> </tr>
<tr> <tr>
<td>std::mutex</td> <td>std::mutex</td>
<td>1</td> <td>1</td>
<td>1</td> <td>1</td>
<td>10M</td> <td>10M</td>
<td>100</td> <td>100</td>
<td>100</td> <td>100</td>
<td>2283</td> <td>2283</td>
</tr> </tr>
<tr> <tr>
<td>SpinLock</td> <td>SpinLock</td>
<td>1</td> <td>1</td>
<td>1</td> <td>1</td>
<td>10M</td> <td>10M</td>
<td>100</td> <td>100</td>
<td>100</td> <td>100</td>
<td>1692</td> <td>1692</td>
</tr> </tr>
<tr> <tr>
<td>std::mutex</td> <td>std::mutex</td>
<td>1</td> <td>1</td>
<td>3</td> <td>3</td>
<td>10M</td> <td>10M</td>
<td>100</td> <td>100</td>
<td>100</td> <td>100</td>
<td>3446</td> <td>3446</td>
</tr> </tr>
<tr> <tr>
<td>SpinLock</td> <td>SpinLock</td>
<td>1</td> <td>1</td>
<td>3</td> <td>3</td>
<td>10M</td> <td>10M</td>
<td>100</td> <td>100</td>
<td>100</td> <td>100</td>
<td>3025</td> <td>3025</td>
</tr> </tr>
<tr> <tr>
<td>std::mutex</td> <td>std::mutex</td>
<td>2</td> <td>2</td>
<td>2</td> <td>2</td>
<td>10M</td> <td>10M</td>
<td>100</td> <td>100</td>
<td>100</td> <td>100</td>
<td>4000</td> <td>4000</td>
</tr> </tr>
<tr> <tr>
<td>SpinLock</td> <td>SpinLock</td>
<td>2</td> <td>2</td>
<td>2</td> <td>2</td>
<td>10M</td> <td>10M</td>
<td>100</td> <td>100</td>
<td>100</td> <td>100</td>
<td>3076</td> <td>3076</td>
</tr> </tr>
<tr> <tr>
<td>std::mutex</td> <td>std::mutex</td>
<td>4</td> <td>4</td>
<td>4</td> <td>4</td>
<td>10M</td> <td>10M</td>
<td>100</td> <td>100</td>
<td>100</td> <td>100</td>
<td>1971</td> <td>1971</td>
</tr> </tr>
<tr> <tr>
<td>SpinLock</td> <td>SpinLock</td>
<td>4</td> <td>4</td>
<td>4</td> <td>4</td>
<td>10M</td> <td>10M</td>
<td>100</td> <td>100</td>
<td>100</td> <td>100</td>
<td>1755</td> <td>1755</td>
</tr> </tr>
<tr> <tr>
<td>std::mutex</td> <td>std::mutex</td>
<td>16</td> <td>16</td>
<td>16</td> <td>16</td>
<td>10M</td> <td>10M</td>
<td>100</td> <td>100</td>
<td>100</td> <td>100</td>
<td>928</td> <td>928</td>
</tr> </tr>
<tr> <tr>
<td>SpinLock</td> <td>SpinLock</td>
<td>16</td> <td>16</td>
<td>16</td> <td>16</td>
<td>10M</td> <td>10M</td>
<td>100</td> <td>100</td>
<td>100</td> <td>100</td>
<td>2082</td> <td>2082</td>
</tr> </tr>
</table> </table>
@ -172,123 +172,123 @@ Iterations: 100,000,000
<table> <table>
<tr> <tr>
<th>Function</th> <th>Function</th>
<th>Compiler</th> <th>Compiler</th>
<th>Native invoking</th> <th>Native invoking</th>
<th>CallbackList single threading</th> <th>CallbackList single threading</th>
<th>CallbackList multi threading</th> <th>CallbackList multi threading</th>
</tr> </tr>
<tr> <tr>
<td rowspan="2">Inline global function</td> <td rowspan="2">Inline global function</td>
<td>MSVC 2017</td> <td>MSVC 2017</td>
<td>217</td> <td>217</td>
<td>1501</td> <td>1501</td>
<td>6921</td> <td>6921</td>
</tr> </tr>
<tr> <tr>
<td>GCC 7.2</td> <td>GCC 7.2</td>
<td>187</td> <td>187</td>
<td>1489</td> <td>1489</td>
<td>4463</td> <td>4463</td>
</tr> </tr>
<tr> <tr>
<td rowspan="2">Non-inline global function</td> <td rowspan="2">Non-inline global function</td>
<td>MSVC 2017</td> <td>MSVC 2017</td>
<td>241</td> <td>241</td>
<td>1526</td> <td>1526</td>
<td>6544</td> <td>6544</td>
</tr> </tr>
<tr> <tr>
<td>GCC 7.2</td> <td>GCC 7.2</td>
<td>233</td> <td>233</td>
<td>1488</td> <td>1488</td>
<td>4787</td> <td>4787</td>
</tr> </tr>
<tr> <tr>
<td rowspan="2">Function object</td> <td rowspan="2">Function object</td>
<td>MSVC 2017</td> <td>MSVC 2017</td>
<td>194</td> <td>194</td>
<td>1498</td> <td>1498</td>
<td>6433</td> <td>6433</td>
</tr> </tr>
<tr> <tr>
<td>GCC 7.2</td> <td>GCC 7.2</td>
<td>212</td> <td>212</td>
<td>1485</td> <td>1485</td>
<td>4951</td> <td>4951</td>
</tr> </tr>
<tr> <tr>
<td rowspan="2">Member virtual function</td> <td rowspan="2">Member virtual function</td>
<td>MSVC 2017</td> <td>MSVC 2017</td>
<td>207</td> <td>207</td>
<td>1533</td> <td>1533</td>
<td>6558</td> <td>6558</td>
</tr> </tr>
<tr> <tr>
<td>GCC 7.2</td> <td>GCC 7.2</td>
<td>212</td> <td>212</td>
<td>1485</td> <td>1485</td>
<td>4489</td> <td>4489</td>
</tr> </tr>
<tr> <tr>
<td rowspan="2">Member non-virtual function</td> <td rowspan="2">Member non-virtual function</td>
<td>MSVC 2017</td> <td>MSVC 2017</td>
<td>214</td> <td>214</td>
<td>1533</td> <td>1533</td>
<td>6390</td> <td>6390</td>
</tr> </tr>
<tr> <tr>
<td>GCC 7.2</td> <td>GCC 7.2</td>
<td>211</td> <td>211</td>
<td>1486</td> <td>1486</td>
<td>4872</td> <td>4872</td>
</tr> </tr>
<tr> <tr>
<td rowspan="2">Member non-inline virtual function</td> <td rowspan="2">Member non-inline virtual function</td>
<td>MSVC 2017</td> <td>MSVC 2017</td>
<td>206</td> <td>206</td>
<td>1522</td> <td>1522</td>
<td>6578</td> <td>6578</td>
</tr> </tr>
<tr> <tr>
<td>GCC 7.2</td> <td>GCC 7.2</td>
<td>182</td> <td>182</td>
<td>1666</td> <td>1666</td>
<td>4593</td> <td>4593</td>
</tr> </tr>
<tr> <tr>
<td rowspan="2">Member non-inline non-virtual function</td> <td rowspan="2">Member non-inline non-virtual function</td>
<td>MSVC 2017</td> <td>MSVC 2017</td>
<td>206</td> <td>206</td>
<td>1491</td> <td>1491</td>
<td>6992</td> <td>6992</td>
</tr> </tr>
<tr> <tr>
<td>GCC 7.2</td> <td>GCC 7.2</td>
<td>205</td> <td>205</td>
<td>1486</td> <td>1486</td>
<td>4490</td> <td>4490</td>
</tr> </tr>
<tr> <tr>
<td rowspan="2">All functions</td> <td rowspan="2">All functions</td>
<td>MSVC 2017</td> <td>MSVC 2017</td>
<td>1374</td> <td>1374</td>
<td>10951</td> <td>10951</td>
<td>29973</td> <td>29973</td>
</tr> </tr>
<tr> <tr>
<td>GCC 7.2</td> <td>GCC 7.2</td>
<td>1223</td> <td>1223</td>
<td>9770</td> <td>9770</td>
<td>22958</td> <td>22958</td>
</tr> </tr>
</table> </table>
@ -306,40 +306,40 @@ volatile int globalValue = 0;
void globalFunction(int a, const int b) void globalFunction(int a, const int b)
{ {
globalValue += a + b; globalValue += a + b;
} }
NON_INLINE void nonInlineGlobalFunction(int a, const int b) NON_INLINE void nonInlineGlobalFunction(int a, const int b)
{ {
globalValue += a + b; globalValue += a + b;
} }
struct FunctionObject struct FunctionObject
{ {
void operator() (int a, const int b) void operator() (int a, const int b)
{ {
globalValue += a + b; globalValue += a + b;
} }
virtual void virFunc(int a, const int b) virtual void virFunc(int a, const int b)
{ {
globalValue += a + b; globalValue += a + b;
} }
void nonVirFunc(int a, const int b) void nonVirFunc(int a, const int b)
{ {
globalValue += a + b; globalValue += a + b;
} }
NON_INLINE virtual void nonInlineVirFunc(int a, const int b) NON_INLINE virtual void nonInlineVirFunc(int a, const int b)
{ {
globalValue += a + b; globalValue += a + b;
} }
NON_INLINE void nonInlineNonVirFunc(int a, const int b) NON_INLINE void nonInlineNonVirFunc(int a, const int b)
{ {
globalValue += a + b; globalValue += a + b;
} }
}; };
#undef NON_INLINE #undef NON_INLINE

View File

@ -35,8 +35,8 @@ eventpp/callbacklist.h
```c++ ```c++
template < template <
typename Prototype, typename Prototype,
typename Policies = DefaultPolicies typename Policies = DefaultPolicies
> >
class CallbackList; class CallbackList;
``` ```

View File

@ -10,14 +10,14 @@ For example,
eventpp::CallbackList<void(int)> callbackList; eventpp::CallbackList<void(int)> callbackList;
callbackList.append( callbackList.append(
eventpp::conditionalFunctor( eventpp::conditionalFunctor(
[](const int value) { [](const int value) {
std::cout << "We should get value 1." << here; std::cout << "We should get value 1." << here;
}, },
[](const int value) { [](const int value) {
return value == 1; return value == 1;
} }
) )
); );
callbackList(2); // not trigger the callback callbackList(2); // not trigger the callback
callbackList(1); // trigger the callback callbackList(1); // trigger the callback
@ -44,34 +44,34 @@ eventpp::CallbackList<void(int)> callbackList;
std::vector<int> dataList(3); std::vector<int> dataList(3);
callbackList.append( callbackList.append(
eventpp::conditionalFunctor( eventpp::conditionalFunctor(
[&dataList](const int index) { [&dataList](const int index) {
++dataList[index]; ++dataList[index];
}, },
[](const int index) { [](const int index) {
return index == 0; return index == 0;
} }
) )
); );
callbackList.append( callbackList.append(
eventpp::conditionalFunctor( eventpp::conditionalFunctor(
[&dataList](const int index) { [&dataList](const int index) {
++dataList[index]; ++dataList[index];
}, },
[](const int index) { [](const int index) {
return index == 1; return index == 1;
} }
) )
); );
callbackList.append( callbackList.append(
eventpp::conditionalFunctor( eventpp::conditionalFunctor(
[&dataList](const int index) { [&dataList](const int index) {
++dataList[index]; ++dataList[index];
}, },
[](const int index) { [](const int index) {
return index == 2; return index == 2;
} }
) )
); );
REQUIRE(dataList == std::vector<int>{ 0, 0, 0 }); REQUIRE(dataList == std::vector<int>{ 0, 0, 0 });

View File

@ -49,47 +49,47 @@ Constructs an instance of ConditionalRemover.
```c++ ```c++
template <typename Condition> template <typename Condition>
typename DispatcherType::Handle appendListener( typename DispatcherType::Handle appendListener(
const typename DispatcherType::Event & event, const typename DispatcherType::Event & event,
const typename DispatcherType::Callback & listener, const typename DispatcherType::Callback & listener,
const Condition & condition const Condition & condition
); );
template <typename Condition> template <typename Condition>
typename DispatcherType::Handle prependListener( typename DispatcherType::Handle prependListener(
const typename DispatcherType::Event & event, const typename DispatcherType::Event & event,
const typename DispatcherType::Callback & listener, const typename DispatcherType::Callback & listener,
const Condition & condition const Condition & condition
); );
template <typename Condition> template <typename Condition>
typename DispatcherType::Handle insertListener( typename DispatcherType::Handle insertListener(
const typename DispatcherType::Event & event, const typename DispatcherType::Event & event,
const typename DispatcherType::Callback & listener, const typename DispatcherType::Callback & listener,
const typename DispatcherType::Handle & before, const typename DispatcherType::Handle & before,
const Condition & condition const Condition & condition
); );
``` ```
**Member functions for CallbackList** **Member functions for CallbackList**
```c++ ```c++
template <typename Condition> template <typename Condition>
typename CallbackListType::Handle append( typename CallbackListType::Handle append(
const typename CallbackListType::Callback & listener, const typename CallbackListType::Callback & listener,
const Condition & condition const Condition & condition
); );
template <typename Condition> template <typename Condition>
typename CallbackListType::Handle prepend( typename CallbackListType::Handle prepend(
const typename CallbackListType::Callback & listener, const typename CallbackListType::Callback & listener,
const Condition & condition const Condition & condition
); );
template <typename Condition> template <typename Condition>
typename CallbackListType::Handle insert( typename CallbackListType::Handle insert(
const typename CallbackListType::Callback & listener, const typename CallbackListType::Callback & listener,
const typename CallbackListType::Handle & before, const typename CallbackListType::Handle & before,
const Condition & condition const Condition & condition
); );
``` ```
The member functions have the same names with the corresponding underlying class (CallbackList, EventDispatcher, or EventQueue), and also have the same parameters except there is one more parameter, `condition`. `condition` is a predicate function that returns a bool value. It's invoked after each trigger, if it returns true, the listener will be removed. The member functions have the same names with the corresponding underlying class (CallbackList, EventDispatcher, or EventQueue), and also have the same parameters except there is one more parameter, `condition`. `condition` is a predicate function that returns a bool value. It's invoked after each trigger, if it returns true, the listener will be removed.
@ -126,26 +126,26 @@ eventpp::EventDispatcher<int, void ()> dispatcher;
constexpr int event = 3; constexpr int event = 3;
dispatcher.appendListener(event, []() { dispatcher.appendListener(event, []() {
// listener A // listener A
}); });
// Note the ConditionalRemover instance returned by conditionalRemover is invoked // Note the ConditionalRemover instance returned by conditionalRemover is invoked
// prependListener and destroyed immediately. // prependListener and destroyed immediately.
std::string removeWho; std::string removeWho;
eventpp::conditionalRemover(dispatcher).prependListener(event, [&dataList]() { eventpp::conditionalRemover(dispatcher).prependListener(event, [&dataList]() {
// listener B // listener B
}, [&removeWho]() -> bool { }, [&removeWho]() -> bool {
return removeWho == "removeB"; return removeWho == "removeB";
}); });
auto handle = eventpp::conditionalRemover(dispatcher).appendListener(event, [&dataList]() { auto handle = eventpp::conditionalRemover(dispatcher).appendListener(event, [&dataList]() {
// listener C // listener C
}, [&removeWho]() -> bool { }, [&removeWho]() -> bool {
return removeWho == "removeC"; return removeWho == "removeC";
}); });
eventpp::conditionalRemover(dispatcher).insertListener(event, [&dataList]() { eventpp::conditionalRemover(dispatcher).insertListener(event, [&dataList]() {
// listener D // listener D
}, handle, [&removeWho]() -> bool { }, handle, [&removeWho]() -> bool {
return removeWho == "removeD"; return removeWho == "removeD";
}); });
dispatcher.dispatch(event); dispatcher.dispatch(event);

View File

@ -48,42 +48,42 @@ Constructs an instance of CounterRemover.
**Member functions for EventDispatcher and EventQueue** **Member functions for EventDispatcher and EventQueue**
```c++ ```c++
typename DispatcherType::Handle appendListener( typename DispatcherType::Handle appendListener(
const typename DispatcherType::Event & event, const typename DispatcherType::Event & event,
const typename DispatcherType::Callback & listener, const typename DispatcherType::Callback & listener,
const int triggerCount = 1 const int triggerCount = 1
); );
typename DispatcherType::Handle prependListener( typename DispatcherType::Handle prependListener(
const typename DispatcherType::Event & event, const typename DispatcherType::Event & event,
const typename DispatcherType::Callback & listener, const typename DispatcherType::Callback & listener,
const int triggerCount = 1 const int triggerCount = 1
); );
typename DispatcherType::Handle insertListener( typename DispatcherType::Handle insertListener(
const typename DispatcherType::Event & event, const typename DispatcherType::Event & event,
const typename DispatcherType::Callback & listener, const typename DispatcherType::Callback & listener,
const typename DispatcherType::Handle & before, const typename DispatcherType::Handle & before,
const int triggerCount = 1 const int triggerCount = 1
); );
``` ```
**Member functions for CallbackList** **Member functions for CallbackList**
```c++ ```c++
typename CallbackListType::Handle append( typename CallbackListType::Handle append(
const typename CallbackListType::Callback & listener, const typename CallbackListType::Callback & listener,
const int triggerCount = 1 const int triggerCount = 1
); );
typename CallbackListType::Handle prepend( typename CallbackListType::Handle prepend(
const typename CallbackListType::Callback & listener, const typename CallbackListType::Callback & listener,
const int triggerCount = 1 const int triggerCount = 1
); );
typename CallbackListType::Handle insert( typename CallbackListType::Handle insert(
const typename CallbackListType::Callback & listener, const typename CallbackListType::Callback & listener,
const typename CallbackListType::Handle & before, const typename CallbackListType::Handle & before,
const int triggerCount = 1 const int triggerCount = 1
); );
``` ```
The member functions have the same names with the corresponding underlying class (CallbackList, EventDispatcher, or EventQueue), and also have the same parameters except there is one more parameter, `triggerCount`. `triggerCount` is decreased by one on each trigger, and when `triggerCount` is zero or negative, the listener will be removed. The member functions have the same names with the corresponding underlying class (CallbackList, EventDispatcher, or EventQueue), and also have the same parameters except there is one more parameter, `triggerCount`. `triggerCount` is decreased by one on each trigger, and when `triggerCount` is zero or negative, the listener will be removed.
@ -110,19 +110,19 @@ eventpp::EventDispatcher<int, void ()> dispatcher;
constexpr int event = 3; constexpr int event = 3;
dispatcher.appendListener(event, []() { dispatcher.appendListener(event, []() {
// listener A // listener A
}); });
// Note the CounterRemover instance returned by counterRemover is invoked // Note the CounterRemover instance returned by counterRemover is invoked
// prependListener and destroyed immediately. // prependListener and destroyed immediately.
eventpp::counterRemover(dispatcher).prependListener(event, []() { eventpp::counterRemover(dispatcher).prependListener(event, []() {
// listener B // listener B
}); });
auto handle = eventpp::counterRemover(dispatcher).appendListener(event, []() { auto handle = eventpp::counterRemover(dispatcher).appendListener(event, []() {
// listener C // listener C
}, 2); }, 2);
eventpp::counterRemover(dispatcher).insertListener(event, []() { eventpp::counterRemover(dispatcher).insertListener(event, []() {
// listener D // listener D
}, handle, 3); }, handle, 3);
dispatcher.dispatch(event); dispatcher.dispatch(event);

View File

@ -34,9 +34,9 @@ eventpp/eventdispatcher.h
```c++ ```c++
template < template <
typename Event, typename Event,
typename Prototype, typename Prototype,
typename Policies = DefaultPolicies typename Policies = DefaultPolicies
> >
class EventDispatcher; class EventDispatcher;
``` ```

View File

@ -15,23 +15,23 @@ class Event
class EventMouseDown : public Event class EventMouseDown : public Event
{ {
public: public:
int getX() const; int getX() const;
int getY() const; int getY() const;
int getButton() const; int getButton() const;
private: private:
int x; int x;
int y; int y;
int button; int button;
}; };
class EventKeyDown : public Event class EventKeyDown : public Event
{ {
public: public:
int getKey() const; int getKey() const;
private: private:
int key; int key;
}; };
``` ```
@ -62,8 +62,8 @@ The macro always generates a default constructor and a constructor that takes al
Code examples: Code examples:
```c++ ```c++
EVENTPP_MAKE_EVENT( EVENTPP_MAKE_EVENT(
EventDraw, Event, EventType::draw, EventDraw, Event, EventType::draw,
(std::string, getText, setText), (int, getX), (double, getSize) (std::string, getText, setText), (int, getX), (double, getSize)
); );
``` ```
Generates class like (in pseudo code), Generates class like (in pseudo code),
@ -71,45 +71,45 @@ Generates class like (in pseudo code),
class EventDraw : public Event class EventDraw : public Event
{ {
public: public:
EventDraw(const std::string & text, const int x, const double size) EventDraw(const std::string & text, const int x, const double size)
: Event(EventType::draw), text(text), x(x), size(size) : Event(EventType::draw), text(text), x(x), size(size)
{ {
} }
const std::string & getText() const { const std::string & getText() const {
return text; return text;
} }
void setText(const std::string & value) { void setText(const std::string & value) {
text = value; text = value;
} }
const int getX() const { const int getX() const {
return x; return x;
} }
const double getSize() const { const double getSize() const {
return size; return size;
} }
private: private:
std::string text; std::string text;
int x; int x;
double size; double size;
}; };
``` ```
```c++ ```c++
EVENTPP_MAKE_EVENT(EventDraw, (Event<int, char>), EventType::draw, EVENTPP_MAKE_EVENT(EventDraw, (Event<int, char>), EventType::draw,
(std::string, getText, setText), (int, getX), (double, getSize) (std::string, getText, setText), (int, getX), (double, getSize)
); );
``` ```
Similar to above example, except the base class is `Event<int, char>`. Similar to above example, except the base class is `Event<int, char>`.
```c++ ```c++
EVENTPP_MAKE_EVENT(EventDraw, (Event<int, char>), (EventType::draw, 5), EVENTPP_MAKE_EVENT(EventDraw, (Event<int, char>), (EventType::draw, 5),
(std::string, getText, setText), (int, getX), (double, getSize) (std::string, getText, setText), (int, getX), (double, getSize)
); );
``` ```
Similar to above example, except the base class is constructed with `(EventType::draw, 5)` instead of `(EventType::draw)`. Similar to above example, except the base class is constructed with `(EventType::draw, 5)` instead of `(EventType::draw)`.

View File

@ -33,9 +33,9 @@ eventpp/eventqueue.h
```c++ ```c++
template < template <
typename Event, typename Event,
typename Prototype, typename Prototype,
typename Policies = DefaultPolicies typename Policies = DefaultPolicies
> >
class EventQueue; class EventQueue;
``` ```
@ -49,16 +49,16 @@ EventQueue has the exactly same template parameters with EventDispatcher. Please
```c++ ```c++
struct EventQueue::QueuedEvent struct EventQueue::QueuedEvent
{ {
EventType event; EventType event;
std::tuple<ArgTypes...> arguments; std::tuple<ArgTypes...> arguments;
// get the event // get the event
EventType getEvent() const; EventType getEvent() const;
// get the argument of index N // get the argument of index N
// same as std::get<N>(queuedEvent.arguments) // same as std::get<N>(queuedEvent.arguments)
template <std::size_t N> template <std::size_t N>
NthArgType getArgument() const; NthArgType getArgument() const;
}; };
``` ```
`event` is the EventQueue::Event, `arguments` are the arguments passed in `enqueue`. `event` is the EventQueue::Event, `arguments` are the arguments passed in `enqueue`.
@ -170,8 +170,8 @@ Note: though `wait` has work around with spurious wakeup internally, the queue i
`wait` is useful when a thread processes the event queue. A sampel usage is, `wait` is useful when a thread processes the event queue. A sampel usage is,
```c++ ```c++
for(;;) { for(;;) {
eventQueue.wait(); eventQueue.wait();
eventQueue.process(); eventQueue.process();
} }
``` ```
The code works even if it doesn't `wait`, but doing that will waste CPU power resource. The code works even if it doesn't `wait`, but doing that will waste CPU power resource.
@ -188,12 +188,12 @@ Return true if the queue is not empty, false if the return is caused by time out
```c++ ```c++
std::atomic<bool> shouldStop(false); std::atomic<bool> shouldStop(false);
for(;;) { for(;;) {
while(! eventQueue.waitFor(std::chrono::milliseconds(10)) && ! shouldStop.load()) ; while(! eventQueue.waitFor(std::chrono::milliseconds(10)) && ! shouldStop.load()) ;
if(shouldStop.load()) { if(shouldStop.load()) {
break; break;
} }
eventQueue.process(); eventQueue.process();
} }
``` ```
@ -206,8 +206,8 @@ Retrieve an event from the queue. The event is returned in `queuedEvent`.
```c++ ```c++
struct EventQueue::QueuedEvent struct EventQueue::QueuedEvent
{ {
TheEventType event; TheEventType event;
std::tuple<ArgumentTypes...> arguments; std::tuple<ArgumentTypes...> arguments;
}; };
``` ```
`queuedEvent` is a EventQueue::QueuedEvent struct. `event` is the EventQueue::Event, `arguments` are the arguments passed in `enqueue`. `queuedEvent` is a EventQueue::QueuedEvent struct. `event` is the EventQueue::Event, `arguments` are the arguments passed in `enqueue`.
@ -245,10 +245,10 @@ Sample code
using EQ = eventpp::EventQueue<int, void ()>; using EQ = eventpp::EventQueue<int, void ()>;
EQ queue; EQ queue;
{ {
EQ::DisableQueueNotify disableNotify(&queue); EQ::DisableQueueNotify disableNotify(&queue);
// any blocking threads will not be waken up by the below two lines. // any blocking threads will not be waken up by the below two lines.
queue.enqueue(1); queue.enqueue(1);
queue.enqueue(2); queue.enqueue(2);
} }
// any blocking threads are waken up here immediately. // any blocking threads are waken up here immediately.

View File

@ -9,9 +9,9 @@ eventpp/utilities/eventutil.h
```c++ ```c++
template <typename DispatcherType> template <typename DispatcherType>
bool removeListener( bool removeListener(
DispatcherType & dispatcher, DispatcherType & dispatcher,
const typename DispatcherType::Event & event, const typename DispatcherType::Event & event,
const typename DispatcherType::Callback & listener const typename DispatcherType::Callback & listener
); );
``` ```
The function finds `listener` of `event` in `dispatcher`, if it finds one, removes the listener and returns true, otherwise returns false. The function finds `listener` of `event` in `dispatcher`, if it finds one, removes the listener and returns true, otherwise returns false.
@ -21,8 +21,8 @@ This function requires the listener be able to be compared with equal operator (
```c++ ```c++
template <typename CallbackListType> template <typename CallbackListType>
bool removeListener( bool removeListener(
CallbackListType & callbackList, CallbackListType & callbackList,
const typename CallbackListType::Callback & callback const typename CallbackListType::Callback & callback
); );
``` ```
The function finds `callback` in `callbackList`, if it finds one, removes the callback and returns true, otherwise returns false. The function finds `callback` in `callbackList`, if it finds one, removes the callback and returns true, otherwise returns false.
@ -32,9 +32,9 @@ This function requires the callback be able to be compared with equal operator (
```c++ ```c++
template <typename DispatcherType> template <typename DispatcherType>
bool hasListener( bool hasListener(
DispatcherType & dispatcher, DispatcherType & dispatcher,
const typename DispatcherType::Event & event, const typename DispatcherType::Event & event,
const typename DispatcherType::Callback & listener const typename DispatcherType::Callback & listener
); );
``` ```
The function finds `listener` of `event` in `dispatcher`, returns true if it finds any one, otherwise returns false. The function finds `listener` of `event` in `dispatcher`, returns true if it finds any one, otherwise returns false.
@ -43,8 +43,8 @@ This function requires the listener be able to be compared with equal operator (
```c++ ```c++
template <typename DispatcherType> template <typename DispatcherType>
bool hasAnyListener( bool hasAnyListener(
DispatcherType & dispatcher, DispatcherType & dispatcher,
const typename DispatcherType::Event & event const typename DispatcherType::Event & event
); );
``` ```
The function finds any listener of `event` in `dispatcher`, returns true if it finds any one, otherwise returns false. The function finds any listener of `event` in `dispatcher`, returns true if it finds any one, otherwise returns false.
@ -52,8 +52,8 @@ The function finds any listener of `event` in `dispatcher`, returns true if it f
```c++ ```c++
template <typename CallbackListType> template <typename CallbackListType>
bool hasListener( bool hasListener(
CallbackListType & callbackList, CallbackListType & callbackList,
const typename CallbackListType::Callback & callback const typename CallbackListType::Callback & callback
); );
``` ```
The function finds `callback` in `callbackList`, returns true if it finds one, otherwise returns false. The function finds `callback` in `callbackList`, returns true if it finds one, otherwise returns false.
@ -62,7 +62,7 @@ This function requires the callback be able to be compared with equal operator (
```c++ ```c++
template <typename CallbackListType> template <typename CallbackListType>
bool hasAnyListener( bool hasAnyListener(
CallbackListType & callbackList CallbackListType & callbackList
); );
``` ```
The function finds any callback in `callbackList`, returns true if it finds any one, otherwise returns false. The function finds any callback in `callbackList`, returns true if it finds any one, otherwise returns false.

View File

@ -58,7 +58,7 @@ For example,
class MyEventDispatcher : public EventDispatcher<blah blah> class MyEventDispatcher : public EventDispatcher<blah blah>
{ {
public: public:
virtual ~MyEventDispatcher(); virtual ~MyEventDispatcher();
}; };
class MyClass : public MyEventDispatcher class MyClass : public MyEventDispatcher
@ -86,22 +86,22 @@ eventpp::CallbackList<void ()> mainLoopTasks;
void mainLoop() void mainLoop()
{ {
for(;;) { for(;;) {
// Do any stuff in the loop // Do any stuff in the loop
mainLoopTasks(); mainLoopTasks();
} }
} }
class MyEventQueue : public eventpp::EventQueue<blah blah> class MyEventQueue : public eventpp::EventQueue<blah blah>
{ {
public: public:
MyEventQueue() MyEventQueue()
{ {
mainLoopTasks.append([this]() { mainLoopTasks.append([this]() {
process(); process();
}); });
} }
}; };
``` ```
@ -118,25 +118,25 @@ eventpp::CallbackList<void ()> mainLoopTasks;
void threadMain() void threadMain()
{ {
while(! stopped) { while(! stopped) {
ioService.poll(); ioService.poll();
mainLoopTasks(); mainLoopTasks();
sleepSomeTime(); sleepSomeTime();
} }
ioService.run(); ioService.run();
mainLoopTasks(); mainLoopTasks();
} }
class MyEventQueue : public eventpp::EventQueue<blah blah> class MyEventQueue : public eventpp::EventQueue<blah blah>
{ {
public: public:
MyEventQueue() MyEventQueue()
{ {
mainLoopTasks.append([this]() { mainLoopTasks.append([this]() {
process(); process();
}); });
} }
}; };
``` ```

View File

@ -32,8 +32,8 @@ eventpp/hetercallbacklist.h
```c++ ```c++
template < template <
typename PrototypeList, typename PrototypeList,
typename Policies = DefaultPolicies typename Policies = DefaultPolicies
> >
class HeterCallbackList; class HeterCallbackList;
``` ```

View File

@ -31,9 +31,9 @@ eventpp/hetereventdispatcher.h
```c++ ```c++
template < template <
typename Event, typename Event,
typename PrototypeList, typename PrototypeList,
typename Policies = DefaultPolicies typename Policies = DefaultPolicies
> >
class HeterEventDispatcher; class HeterEventDispatcher;
``` ```

View File

@ -31,9 +31,9 @@ eventpp/eventqueue.h
```c++ ```c++
template < template <
typename Event, typename Event,
typename PrototypeList, typename PrototypeList,
typename Policies = DefaultPolicies typename Policies = DefaultPolicies
> >
class HeterEventQueue; class HeterEventQueue;
``` ```
@ -137,8 +137,8 @@ Note: though `wait` has work around with spurious wakeup internally, the queue i
`wait` is useful when a thread processes the event queue. A sampel usage is, `wait` is useful when a thread processes the event queue. A sampel usage is,
```c++ ```c++
for(;;) { for(;;) {
eventQueue.wait(); eventQueue.wait();
eventQueue.process(); eventQueue.process();
} }
``` ```
The code works event if it doesn't `wait`, but doing that will waste CPU power resource. The code works event if it doesn't `wait`, but doing that will waste CPU power resource.
@ -155,12 +155,12 @@ Return true if the queue is not empty, false if the return is caused by time out
```c++ ```c++
std::atomic<bool> shouldStop(false); std::atomic<bool> shouldStop(false);
for(;;) { for(;;) {
while(! eventQueue.waitFor(std::chrono::milliseconds(10)) && ! shouldStop.load()) ; while(! eventQueue.waitFor(std::chrono::milliseconds(10)) && ! shouldStop.load()) ;
if(shouldStop.load()) { if(shouldStop.load()) {
break; break;
} }
eventQueue.process(); eventQueue.process();
} }
``` ```
@ -177,10 +177,10 @@ Sample code
using EQ = eventpp::HeterEventQueue<int, void ()>; using EQ = eventpp::HeterEventQueue<int, void ()>;
EQ queue; EQ queue;
{ {
EQ::DisableQueueNotify disableNotify(&queue); EQ::DisableQueueNotify disableNotify(&queue);
// any blocking threads will not be waken up by the below two lines. // any blocking threads will not be waken up by the below two lines.
queue.enqueue(1); queue.enqueue(1);
queue.enqueue(2); queue.enqueue(2);
} }
// any blocking threads are waken up here immediately. // any blocking threads are waken up here immediately.

View File

@ -30,22 +30,22 @@ eventpp/hetereventqueue.h
```c++ ```c++
template < template <
typename PrototypeList, typename PrototypeList,
typename Policies = DefaultPolicies typename Policies = DefaultPolicies
> >
class HeterCallbackList; class HeterCallbackList;
template < template <
typename Event, typename Event,
typename PrototypeList, typename PrototypeList,
typename Policies = DefaultPolicies typename Policies = DefaultPolicies
> >
class HeterEventDispatcher; class HeterEventDispatcher;
template < template <
typename Event, typename Event,
typename PrototypeList, typename PrototypeList,
typename Policies = DefaultPolicies typename Policies = DefaultPolicies
> >
class HeterEventQueue; class HeterEventQueue;
``` ```
@ -54,22 +54,22 @@ For comparison, below are the template parameters for the homogeneous counterpar
```c++ ```c++
template < template <
typename Prototype, typename Prototype,
typename Policies = DefaultPolicies typename Policies = DefaultPolicies
> >
class CallbackList; class CallbackList;
template < template <
typename Event, typename Event,
typename Prototype, typename Prototype,
typename Policies = DefaultPolicies typename Policies = DefaultPolicies
> >
class EventDispatcher; class EventDispatcher;
template < template <
typename Event, typename Event,
typename Prototype, typename Prototype,
typename Policies = DefaultPolicies typename Policies = DefaultPolicies
> >
class EventQueue; class EventQueue;
``` ```

View File

@ -28,22 +28,22 @@ EventDispatcher is ideal when there are many kinds of events, or the number of e
```c++ ```c++
enum class MyEventType enum class MyEventType
{ {
redraw, redraw,
mouseDown, mouseDown,
mouseUp, mouseUp,
//... maybe 200 other events here //... maybe 200 other events here
}; };
struct MyEvent { struct MyEvent {
MyEventType type; MyEventType type;
// data that all events may need // data that all events may need
}; };
struct MyEventPolicies struct MyEventPolicies
{ {
static MyEventType getEvent(const MyEvent & e) { static MyEventType getEvent(const MyEvent & e) {
return e.type; return e.type;
} }
}; };
eventpp::EventDispatcher<MyEventType, void(const MyEvent &), MyEventPolicies> dispatcher; eventpp::EventDispatcher<MyEventType, void(const MyEvent &), MyEventPolicies> dispatcher;

View File

@ -47,7 +47,7 @@ class MyMixin : public Base
To enable mixins, add them to the `Mixins` type in the policies class. For example, to enable `MixinFilter`, define the dispatcher as, To enable mixins, add them to the `Mixins` type in the policies class. For example, to enable `MixinFilter`, define the dispatcher as,
```c++ ```c++
struct MyPolicies { struct MyPolicies {
using Mixins = eventpp::MixinList<eventpp::MixinFilter>; using Mixins = eventpp::MixinList<eventpp::MixinFilter>;
}; };
eventpp::EventDispatcher<int, void (), MyPolicies> dispatcher; eventpp::EventDispatcher<int, void (), MyPolicies> dispatcher;
``` ```
@ -121,19 +121,19 @@ Return true if the filter is removed successfully.
**Code** **Code**
```c++ ```c++
struct MyPolicies { struct MyPolicies {
using Mixins = eventpp::MixinList<eventpp::MixinFilter>; using Mixins = eventpp::MixinList<eventpp::MixinFilter>;
}; };
eventpp::EventDispatcher<int, void (int e, int i, std::string), MyPolicies> dispatcher; eventpp::EventDispatcher<int, void (int e, int i, std::string), MyPolicies> dispatcher;
dispatcher.appendListener(3, [](const int e, const int i, const std::string & s) { dispatcher.appendListener(3, [](const int e, const int i, const std::string & s) {
std::cout std::cout
<< "Got event 3, i was 1 but actural is " << i << "Got event 3, i was 1 but actural is " << i
<< " s was Hello but actural is " << s << " s was Hello but actural is " << s
<< std::endl << std::endl
; ;
}); });
dispatcher.appendListener(5, [](const int e, const int i, const std::string & s) { dispatcher.appendListener(5, [](const int e, const int i, const std::string & s) {
std::cout << "Shout not got event 5" << std::endl; std::cout << "Shout not got event 5" << std::endl;
}); });
// Add three event filters. // Add three event filters.
@ -141,27 +141,27 @@ dispatcher.appendListener(5, [](const int e, const int i, const std::string & s)
// The first filter modifies the input arguments to other values, then the subsequence filters // The first filter modifies the input arguments to other values, then the subsequence filters
// and listeners will see the modified values. // and listeners will see the modified values.
dispatcher.appendFilter([](const int e, int & i, std::string & s) -> bool { dispatcher.appendFilter([](const int e, int & i, std::string & s) -> bool {
std::cout << "Filter 1, e is " << e << " passed in i is " << i << " s is " << s << std::endl; std::cout << "Filter 1, e is " << e << " passed in i is " << i << " s is " << s << std::endl;
i = 38; i = 38;
s = "Hi"; s = "Hi";
std::cout << "Filter 1, changed i is " << i << " s is " << s << std::endl; std::cout << "Filter 1, changed i is " << i << " s is " << s << std::endl;
return true; return true;
}); });
// The second filter filters out all event of 5. So no listeners on event 5 can be triggered. // The second filter filters out all event of 5. So no listeners on event 5 can be triggered.
// The third filter is not invoked on event 5 also. // The third filter is not invoked on event 5 also.
dispatcher.appendFilter([](const int e, int & i, std::string & s) -> bool { dispatcher.appendFilter([](const int e, int & i, std::string & s) -> bool {
std::cout << "Filter 2, e is " << e << " passed in i is " << i << " s is " << s << std::endl; std::cout << "Filter 2, e is " << e << " passed in i is " << i << " s is " << s << std::endl;
if(e == 5) { if(e == 5) {
return false; return false;
} }
return true; return true;
}); });
// The third filter just prints the input arguments. // The third filter just prints the input arguments.
dispatcher.appendFilter([](const int e, int & i, std::string & s) -> bool { dispatcher.appendFilter([](const int e, int & i, std::string & s) -> bool {
std::cout << "Filter 3, e is " << e << " passed in i is " << i << " s is " << s << std::endl; std::cout << "Filter 3, e is " << e << " passed in i is " << i << " s is " << s << std::endl;
return true; return true;
}); });
// Dispatch the events, the first argument is always the event type. // Dispatch the events, the first argument is always the event type.

View File

@ -43,10 +43,10 @@ Its default implementation `OrderedQueueListCompare` looks like,
```c++ ```c++
struct OrderedQueueListCompare struct OrderedQueueListCompare
{ {
template <typename T> template <typename T>
bool operator() (const T & a, const T & b) const { bool operator() (const T & a, const T & b) const {
return a.event < b.event; return a.event < b.event;
} }
}; };
``` ```
The typename T is actually the `EventQueue::QueuedEvent`. But since `OrderedQueueList` is used in the policies that are used to construct the EventQueue, it's not possible to specify the actual type in `OrderedQueueListCompare`, so here we use a template operator. The typename T is actually the `EventQueue::QueuedEvent`. But since `OrderedQueueList` is used in the policies that are used to construct the EventQueue, it's not possible to specify the actual type in `OrderedQueueListCompare`, so here we use a template operator.
@ -56,8 +56,8 @@ The typename T is actually the `EventQueue::QueuedEvent`. But since `OrderedQueu
```c++ ```c++
struct QueuedEvent struct QueuedEvent
{ {
EventType event; EventType event;
std::tuple<Args> arguments; std::tuple<Args> arguments;
}; };
``` ```
`event` is the event sent to the queue. `event` is the event sent to the queue.
@ -70,56 +70,56 @@ struct QueuedEvent
// First let's define the event struct. e is the event type, priority determines the priority. // First let's define the event struct. e is the event type, priority determines the priority.
struct MyEvent struct MyEvent
{ {
int e; int e;
int priority; int priority;
}; };
// The comparison function object used by eventpp::OrderedQueueList. // The comparison function object used by eventpp::OrderedQueueList.
// The function compares the event by priority. // The function compares the event by priority.
struct MyCompare struct MyCompare
{ {
template <typename T> template <typename T>
bool operator() (const T & a, const T & b) const { bool operator() (const T & a, const T & b) const {
return std::get<0>(a.arguments).priority > std::get<0>(b.arguments).priority; return std::get<0>(a.arguments).priority > std::get<0>(b.arguments).priority;
} }
}; };
// Define the EventQueue policy // Define the EventQueue policy
struct MyPolicy struct MyPolicy
{ {
template <typename Item> template <typename Item>
using QueueList = eventpp::OrderedQueueList<Item, MyCompare >; using QueueList = eventpp::OrderedQueueList<Item, MyCompare >;
static int getEvent(const MyEvent & event) { static int getEvent(const MyEvent & event) {
return event.e; return event.e;
} }
}; };
void main() void main()
{ {
using EQ = eventpp::EventQueue<int, void(const MyEvent &), MyPolicy>; using EQ = eventpp::EventQueue<int, void(const MyEvent &), MyPolicy>;
EQ queue; EQ queue;
queue.appendListener(3, [](const MyEvent & event) { queue.appendListener(3, [](const MyEvent & event) {
std::cout << "Get event " << event.e << "(should be 3)." << " priority: " << event.priority << std::endl; std::cout << "Get event " << event.e << "(should be 3)." << " priority: " << event.priority << std::endl;
}); });
queue.appendListener(5, [](const MyEvent & event) { queue.appendListener(5, [](const MyEvent & event) {
std::cout << "Get event " << event.e << "(should be 5)." << " priority: " << event.priority << std::endl; std::cout << "Get event " << event.e << "(should be 5)." << " priority: " << event.priority << std::endl;
}); });
queue.appendListener(7, [](const MyEvent & event) { queue.appendListener(7, [](const MyEvent & event) {
std::cout << "Get event " << event.e << "(should be 7)." << " priority: " << event.priority << std::endl; std::cout << "Get event " << event.e << "(should be 7)." << " priority: " << event.priority << std::endl;
}); });
// Add an event, the first number 5 is the event type, the second number 100 is the priority. // Add an event, the first number 5 is the event type, the second number 100 is the priority.
// After the queue processes, the events will be processed from higher priority to lower priority. // After the queue processes, the events will be processed from higher priority to lower priority.
queue.enqueue(MyEvent{ 5, 100 }); queue.enqueue(MyEvent{ 5, 100 });
queue.enqueue(MyEvent{ 5, 200 }); queue.enqueue(MyEvent{ 5, 200 });
queue.enqueue(MyEvent{ 7, 300 }); queue.enqueue(MyEvent{ 7, 300 });
queue.enqueue(MyEvent{ 7, 400 }); queue.enqueue(MyEvent{ 7, 400 });
queue.enqueue(MyEvent{ 3, 500 }); queue.enqueue(MyEvent{ 3, 500 });
queue.enqueue(MyEvent{ 3, 600 }); queue.enqueue(MyEvent{ 3, 600 });
queue.process(); queue.process();
} }
``` ```

View File

@ -42,39 +42,39 @@ Sample code
```c++ ```c++
// Define an Event to hold all parameters. // Define an Event to hold all parameters.
struct MyEvent { struct MyEvent {
int type; int type;
std::string message; std::string message;
int param; int param;
}; };
// Define policies to let the dispatcher knows how to // Define policies to let the dispatcher knows how to
// extract the event type. // extract the event type.
struct MyEventPolicies struct MyEventPolicies
{ {
static int getEvent(const MyEvent & e, bool /*b*/) { static int getEvent(const MyEvent & e, bool /*b*/) {
return e.type; return e.type;
} }
}; };
// Pass MyEventPolicies as the third template argument of EventDispatcher. // Pass MyEventPolicies as the third template argument of EventDispatcher.
// Note: the first template argument is the event type type int, not MyEvent. // Note: the first template argument is the event type type int, not MyEvent.
eventpp::EventDispatcher< eventpp::EventDispatcher<
int, int,
void (const MyEvent &, bool), void (const MyEvent &, bool),
MyEventPolicies MyEventPolicies
> dispatcher; > dispatcher;
// Add a listener. // Add a listener.
// Note: the first argument is the event type of type int, not MyEvent. // Note: the first argument is the event type of type int, not MyEvent.
dispatcher.appendListener(3, [](const MyEvent & e, bool b) { dispatcher.appendListener(3, [](const MyEvent & e, bool b) {
std::cout std::cout
<< std::boolalpha << std::boolalpha
<< "Got event 3" << std::endl << "Got event 3" << std::endl
<< "Event::type is " << e.type << std::endl << "Event::type is " << e.type << std::endl
<< "Event::message is " << e.message << std::endl << "Event::message is " << e.message << std::endl
<< "Event::param is " << e.param << std::endl << "Event::param is " << e.param << std::endl
<< "b is " << b << std::endl << "b is " << b << std::endl
; ;
}); });
// Dispatch the event. // Dispatch the event.
@ -93,35 +93,35 @@ Sample code
```c++ ```c++
struct MyEvent { struct MyEvent {
MyEvent() : type(0), canceled(false) { MyEvent() : type(0), canceled(false) {
} }
explicit MyEvent(const int type) explicit MyEvent(const int type)
: type(type), canceled(false) { : type(type), canceled(false) {
} }
int type; int type;
mutable bool canceled; mutable bool canceled;
}; };
struct MyEventPolicies struct MyEventPolicies
{ {
static int getEvent(const MyEvent & e) { static int getEvent(const MyEvent & e) {
return e.type; return e.type;
} }
static bool canContinueInvoking(const MyEvent & e) { static bool canContinueInvoking(const MyEvent & e) {
return ! e.canceled; return ! e.canceled;
} }
}; };
eventpp::EventDispatcher<int, void (const MyEvent &), MyEventPolicies> dispatcher; eventpp::EventDispatcher<int, void (const MyEvent &), MyEventPolicies> dispatcher;
dispatcher.appendListener(3, [](const MyEvent & e) { dispatcher.appendListener(3, [](const MyEvent & e) {
std::cout << "Got event 3" << std::endl; std::cout << "Got event 3" << std::endl;
e.canceled = true; e.canceled = true;
}); });
dispatcher.appendListener(3, [](const MyEvent & e) { dispatcher.appendListener(3, [](const MyEvent & e) {
std::cout << "Should not get this event 3" << std::endl; std::cout << "Should not get this event 3" << std::endl;
}); });
dispatcher.dispatch(MyEvent(3)); dispatcher.dispatch(MyEvent(3));
@ -158,12 +158,12 @@ A typical `Threading` type looks like
```c++ ```c++
struct MultipleThreading struct MultipleThreading
{ {
using Mutex = std::mutex; using Mutex = std::mutex;
template <typename T> template <typename T>
using Atomic = std::atomic<T>; using Atomic = std::atomic<T>;
using ConditionVariable = std::condition_variable; using ConditionVariable = std::condition_variable;
}; };
``` ```
For `SingleThreading`, all the types `Mutex`, `Atomic`, and `ConditionVariable` are dummy types that don't do anything. For `SingleThreading`, all the types `Mutex`, `Atomic`, and `ConditionVariable` are dummy types that don't do anything.
@ -177,15 +177,15 @@ Below is the sample code for how to use `SpinLock`
```c++ ```c++
struct MultipleThreadingSpinLock struct MultipleThreadingSpinLock
{ {
using Mutex = eventpp::SpinLock; using Mutex = eventpp::SpinLock;
template <typename T> template <typename T>
using Atomic = std::atomic<T>; using Atomic = std::atomic<T>;
using ConditionVariable = std::condition_variable; using ConditionVariable = std::condition_variable;
}; };
struct MyEventPolicies { struct MyEventPolicies {
using Threading = MultipleThreadingSpinLock; using Threading = MultipleThreadingSpinLock;
}; };
eventpp::EventDispatcher<int, void (), MyEventPolicies> dispatcher; eventpp::EventDispatcher<int, void (), MyEventPolicies> dispatcher;
eventpp::CallbackList<void (), MyEventPolicies> callbackList; eventpp::CallbackList<void (), MyEventPolicies> callbackList;
@ -194,18 +194,18 @@ eventpp::CallbackList<void (), MyEventPolicies> callbackList;
`eventpp` provides a shortcut template class to customize the threading. `eventpp` provides a shortcut template class to customize the threading.
```c++ ```c++
template < template <
typename Mutex_, typename Mutex_,
template <typename > class Atomic_ = std::atomic, template <typename > class Atomic_ = std::atomic,
typename ConditionVariable_ = std::condition_variable typename ConditionVariable_ = std::condition_variable
> >
struct GeneralThreading struct GeneralThreading
{ {
using Mutex = Mutex_; using Mutex = Mutex_;
template <typename T> template <typename T>
using Atomic = Atomic_<T>; using Atomic = Atomic_<T>;
using ConditionVariable = ConditionVariable_; using ConditionVariable = ConditionVariable_;
}; };
``` ```
@ -213,7 +213,7 @@ So the previous sample code for spinlock can be rewritten as
```c++ ```c++
struct MyEventPolicies { struct MyEventPolicies {
using Threading = eventpp::GeneralThreading<eventpp::SpinLock>; using Threading = eventpp::GeneralThreading<eventpp::SpinLock>;
}; };
eventpp::EventDispatcher<int, void (), MyEventPolicies> dispatcher; eventpp::EventDispatcher<int, void (), MyEventPolicies> dispatcher;
eventpp::CallbackList<void (), MyEventPolicies> callbackList; eventpp::CallbackList<void (), MyEventPolicies> callbackList;
@ -270,12 +270,12 @@ Examples to demonstrate argument passing mode
```c++ ```c++
struct MyPolicies struct MyPolicies
{ {
using ArgumentPassingMode = ArgumentPassingAutoDetect; using ArgumentPassingMode = ArgumentPassingAutoDetect;
}; };
eventpp::EventDispatcher< eventpp::EventDispatcher<
int, int,
void(int, const std::string &), void(int, const std::string &),
MyPolicies MyPolicies
> dispatcher; > dispatcher;
// or just // or just
//eventpp::EventDispatcher<int, void(int, const std::string &)> dispatcher; //eventpp::EventDispatcher<int, void(int, const std::string &)> dispatcher;
@ -286,12 +286,12 @@ dispatcher.dispatch(3, 8, "hello"); // Compile OK
```c++ ```c++
struct MyPolicies struct MyPolicies
{ {
using ArgumentPassingMode = ArgumentPassingIncludeEvent; using ArgumentPassingMode = ArgumentPassingIncludeEvent;
}; };
eventpp::EventDispatcher< eventpp::EventDispatcher<
int, int,
void(int, const std::string &), void(int, const std::string &),
MyPolicies MyPolicies
> dispatcher; > dispatcher;
dispatcher.dispatch(3, "hello"); // Compile OK dispatcher.dispatch(3, "hello"); // Compile OK
//dispatcher.dispatch(3, 8, "hello"); // Compile failure //dispatcher.dispatch(3, 8, "hello"); // Compile failure
@ -300,12 +300,12 @@ dispatcher.dispatch(3, "hello"); // Compile OK
```c++ ```c++
struct MyPolicies struct MyPolicies
{ {
using ArgumentPassingMode = ArgumentPassingExcludeEvent; using ArgumentPassingMode = ArgumentPassingExcludeEvent;
}; };
eventpp::EventDispatcher< eventpp::EventDispatcher<
int, int,
void(int, const std::string &), void(int, const std::string &),
MyPolicies MyPolicies
> dispatcher; > dispatcher;
//dispatcher.dispatch(3, "hello"); // Compile failure //dispatcher.dispatch(3, "hello"); // Compile failure
dispatcher.dispatch(3, 8, "hello"); // Compile OK dispatcher.dispatch(3, 8, "hello"); // Compile OK
@ -367,10 +367,10 @@ To use policies, declare a struct, define the policies in it, and pass the struc
```c++ ```c++
struct MyPolicies //the struct name doesn't matter struct MyPolicies //the struct name doesn't matter
{ {
template <typename ...Args> template <typename ...Args>
static int getEvent(const MyEvent & e, const Args &...) { static int getEvent(const MyEvent & e, const Args &...) {
return e.type; return e.type;
} }
}; };
EventDispatcher<int, void(const MyEvent &), MyPolicies> dispatcher; EventDispatcher<int, void(const MyEvent &), MyPolicies> dispatcher;
``` ```

View File

@ -58,24 +58,24 @@ void reset();
void setDispatcher(DispatcherType & dispatcher); void setDispatcher(DispatcherType & dispatcher);
typename DispatcherType::Handle appendListener( typename DispatcherType::Handle appendListener(
const typename DispatcherType::Event & event, const typename DispatcherType::Event & event,
const typename DispatcherType::Callback & listener const typename DispatcherType::Callback & listener
); );
typename DispatcherType::Handle prependListener( typename DispatcherType::Handle prependListener(
const typename DispatcherType::Event & event, const typename DispatcherType::Event & event,
const typename DispatcherType::Callback & listener const typename DispatcherType::Callback & listener
); );
typename DispatcherType::Handle insertListener( typename DispatcherType::Handle insertListener(
const typename DispatcherType::Event & event, const typename DispatcherType::Event & event,
const typename DispatcherType::Callback & listener, const typename DispatcherType::Callback & listener,
const typename DispatcherType::Handle & before const typename DispatcherType::Handle & before
); );
bool removeListener( bool removeListener(
const typename DispatcherType::Event & event, const typename DispatcherType::Event & event,
const typename DispatcherType::Handle handle const typename DispatcherType::Handle handle
); );
``` ```
**Member functions for CallbackList** **Member functions for CallbackList**
@ -85,17 +85,17 @@ void reset();
void setCallbackList(CallbackListType & callbackList); void setCallbackList(CallbackListType & callbackList);
typename CallbackListType::Handle append( typename CallbackListType::Handle append(
const typename CallbackListType::Callback & callback const typename CallbackListType::Callback & callback
); );
typename CallbackListType::Handle prepend( typename CallbackListType::Handle prepend(
const typename CallbackListType::Callback & callback const typename CallbackListType::Callback & callback
); );
typename CallbackListType::Handle insert( typename CallbackListType::Handle insert(
const typename CallbackListType::Callback & callback, const typename CallbackListType::Callback & callback,
const typename CallbackListType::Handle & before const typename CallbackListType::Handle & before
); );
bool remove(const typename CallbackListType::Handle handle); bool remove(const typename CallbackListType::Handle handle);
``` ```
@ -119,39 +119,39 @@ using Remover = eventpp::ScopedRemover<eventpp::EventDispatcher<int, void ()> >;
constexpr int event = 3; constexpr int event = 3;
dispatcher.appendListener(event, [&dataList]() { dispatcher.appendListener(event, [&dataList]() {
// listener A // listener A
}); });
{ {
Remover r1(dispatcher); Remover r1(dispatcher);
r1.prependListener(event, [&dataList]() { r1.prependListener(event, [&dataList]() {
// listener B // listener B
}); });
{ {
Remover r2(dispatcher); Remover r2(dispatcher);
auto handle = r2.appendListener(event, [&dataList]() { auto handle = r2.appendListener(event, [&dataList]() {
// listener C // listener C
}); });
{ {
Remover r3(dispatcher); Remover r3(dispatcher);
r3.insertListener(event, [&dataList]() { r3.insertListener(event, [&dataList]() {
// listener D // listener D
}, handle); }, handle);
dispatcher.dispatch(event); dispatcher.dispatch(event);
// All listeners were triggered. // All listeners were triggered.
} }
// listener D was removed // listener D was removed
dispatcher.dispatch(event); dispatcher.dispatch(event);
// Listeners A, B, C were triggered. // Listeners A, B, C were triggered.
} }
// listener C was removed // listener C was removed
dispatcher.dispatch(event); dispatcher.dispatch(event);
// Listeners A, B were triggered. // Listeners A, B were triggered.
} }
// listener B was removed // listener B was removed
@ -173,12 +173,12 @@ SomeDispatcher someDispatcher;
class MyClass class MyClass
{ {
MyClass() MyClass()
{ {
someDispatcher.appendListener(SomeEvent, callback of myListener); someDispatcher.appendListener(SomeEvent, callback of myListener);
} }
void myListener() {} void myListener() {}
}; };
``` ```
@ -191,14 +191,14 @@ SomeDispatcher someDispatcher;
class MyClass class MyClass
{ {
MyClass() : scopedRemover(someDispatcher) MyClass() : scopedRemover(someDispatcher)
{ {
scopedRemover.appendListener(SomeEvent, callback of myListener); scopedRemover.appendListener(SomeEvent, callback of myListener);
} }
void myListener() {} void myListener() {}
eventpp::ScopedRemover<SomeDispatcher> scopedRemover; eventpp::ScopedRemover<SomeDispatcher> scopedRemover;
}; };
``` ```

View File

@ -19,10 +19,10 @@ eventpp::CallbackList<void ()> callbackList;
// Lambda is not required, any function or std::function // Lambda is not required, any function or std::function
// or whatever function object with the required prototype is fine. // or whatever function object with the required prototype is fine.
callbackList.append([]() { callbackList.append([]() {
std::cout << "Got callback 1." << std::endl; std::cout << "Got callback 1." << std::endl;
}); });
callbackList.append([]() { callbackList.append([]() {
std::cout << "Got callback 2." << std::endl; std::cout << "Got callback 2." << std::endl;
}); });
// Invoke the callback list // Invoke the callback list
@ -44,7 +44,7 @@ The *prototype* is C++ function type, such as `void (int)`, `void (const std::st
Now let's add a callback. Now let's add a callback.
```c++ ```c++
callbackList.append([]() { callbackList.append([]() {
std::cout << "Got callback 1." << std::endl; std::cout << "Got callback 1." << std::endl;
}); });
``` ```
Function `append` takes one arguments, the *callback*. Function `append` takes one arguments, the *callback*.
@ -65,12 +65,12 @@ During the invoking, all callbacks will be invoked one by one in the order of th
eventpp::CallbackList<void (const std::string &, const bool)> callbackList; eventpp::CallbackList<void (const std::string &, const bool)> callbackList;
callbackList.append([](const std::string & s, const bool b) { callbackList.append([](const std::string & s, const bool b) {
std::cout << std::boolalpha << "Got callback 1, s is " << s << " b is " << b << std::endl; std::cout << std::boolalpha << "Got callback 1, s is " << s << " b is " << b << std::endl;
}); });
// The callback prototype doesn't need to be exactly same as the callback list. // The callback prototype doesn't need to be exactly same as the callback list.
// It would be fine as long as the arguments are compatible with the callbacklist. // It would be fine as long as the arguments are compatible with the callbacklist.
callbackList.append([](std::string s, int b) { callbackList.append([](std::string s, int b) {
std::cout << std::boolalpha << "Got callback 2, s is " << s << " b is " << b << std::endl; std::cout << std::boolalpha << "Got callback 2, s is " << s << " b is " << b << std::endl;
}); });
// Invoke the callback list // Invoke the callback list
@ -96,13 +96,13 @@ CL::Handle handle2;
// Add some callbacks. // Add some callbacks.
callbackList.append([]() { callbackList.append([]() {
std::cout << "Got callback 1." << std::endl; std::cout << "Got callback 1." << std::endl;
}); });
handle2 = callbackList.append([]() { handle2 = callbackList.append([]() {
std::cout << "Got callback 2." << std::endl; std::cout << "Got callback 2." << std::endl;
}); });
callbackList.append([]() { callbackList.append([]() {
std::cout << "Got callback 3." << std::endl; std::cout << "Got callback 3." << std::endl;
}); });
callbackList.remove(handle2); callbackList.remove(handle2);
@ -127,30 +127,30 @@ CL callbackList;
// Add some callbacks. // Add some callbacks.
callbackList.append([]() { callbackList.append([]() {
std::cout << "Got callback 1." << std::endl; std::cout << "Got callback 1." << std::endl;
}); });
callbackList.append([]() { callbackList.append([]() {
std::cout << "Got callback 2." << std::endl; std::cout << "Got callback 2." << std::endl;
}); });
callbackList.append([]() { callbackList.append([]() {
std::cout << "Got callback 3." << std::endl; std::cout << "Got callback 3." << std::endl;
}); });
// Now call forEach to remove the second callback // Now call forEach to remove the second callback
// The forEach callback prototype is void(const CallbackList::Handle & handle, const CallbackList::Callback & callback) // The forEach callback prototype is void(const CallbackList::Handle & handle, const CallbackList::Callback & callback)
int index = 0; int index = 0;
callbackList.forEach([&callbackList, &index](const CL::Handle & handle, const CL::Callback & callback) { callbackList.forEach([&callbackList, &index](const CL::Handle & handle, const CL::Callback & callback) {
std::cout << "forEach(Handle, Callback), invoked " << index << std::endl; std::cout << "forEach(Handle, Callback), invoked " << index << std::endl;
if(index == 1) { if(index == 1) {
callbackList.remove(handle); callbackList.remove(handle);
std::cout << "forEach(Handle, Callback), removed second callback" << std::endl; std::cout << "forEach(Handle, Callback), removed second callback" << std::endl;
} }
++index; ++index;
}); });
// The forEach callback prototype can also be void(const CallbackList::Callback & callback) // The forEach callback prototype can also be void(const CallbackList::Callback & callback)
callbackList.forEach([&callbackList, &index](const CL::Callback & callback) { callbackList.forEach([&callbackList, &index](const CL::Callback & callback) {
std::cout << "forEach(Callback), invoked" << std::endl; std::cout << "forEach(Callback), invoked" << std::endl;
}); });
// Invoke the callback list // Invoke the callback list

View File

@ -22,13 +22,13 @@ eventpp::EventDispatcher<int, void ()> dispatcher;
// Lambda is not required, any function or std::function // Lambda is not required, any function or std::function
// or whatever function object with the required prototype is fine. // or whatever function object with the required prototype is fine.
dispatcher.appendListener(3, []() { dispatcher.appendListener(3, []() {
std::cout << "Got event 3." << std::endl; std::cout << "Got event 3." << std::endl;
}); });
dispatcher.appendListener(5, []() { dispatcher.appendListener(5, []() {
std::cout << "Got event 5." << std::endl; std::cout << "Got event 5." << std::endl;
}); });
dispatcher.appendListener(5, []() { dispatcher.appendListener(5, []() {
std::cout << "Got another event 5." << std::endl; std::cout << "Got another event 5." << std::endl;
}); });
// Dispatch the events, the first argument is always the event type. // Dispatch the events, the first argument is always the event type.
@ -53,7 +53,7 @@ The *prototype* is C++ function type, such as `void (int)`, `void (const std::st
Now let's add a listener. Now let's add a listener.
```c++ ```c++
dispatcher.appendListener(3, []() { dispatcher.appendListener(3, []() {
std::cout << "Got event 3." << std::endl; std::cout << "Got event 3." << std::endl;
}); });
``` ```
Function `appendListener` takes at least two arguments. The first argument is the *event* of type *event type*, here is `int`. The second is the *callback*. Function `appendListener` takes at least two arguments. The first argument is the *event* of type *event type*, here is `int`. The second is the *callback*.
@ -76,15 +76,15 @@ During the dispatching, all listeners of that event will be invoked one by one i
eventpp::EventDispatcher<int, void (const std::string &, const bool)> dispatcher; eventpp::EventDispatcher<int, void (const std::string &, const bool)> dispatcher;
dispatcher.appendListener(3, [](const std::string & s, const bool b) { dispatcher.appendListener(3, [](const std::string & s, const bool b) {
std::cout << std::boolalpha << "Got event 3, s is " << s << " b is " << b << std::endl; std::cout << std::boolalpha << "Got event 3, s is " << s << " b is " << b << std::endl;
}); });
// The listener prototype doesn't need to be exactly same as the dispatcher. // The listener prototype doesn't need to be exactly same as the dispatcher.
// It would be find as long as the arguments is compatible with the dispatcher. // It would be find as long as the arguments is compatible with the dispatcher.
dispatcher.appendListener(5, [](std::string s, int b) { dispatcher.appendListener(5, [](std::string s, int b) {
std::cout << std::boolalpha << "Got event 5, s is " << s << " b is " << b << std::endl; std::cout << std::boolalpha << "Got event 5, s is " << s << " b is " << b << std::endl;
}); });
dispatcher.appendListener(5, [](const std::string & s, const bool b) { dispatcher.appendListener(5, [](const std::string & s, const bool b) {
std::cout << std::boolalpha << "Got another event 5, s is " << s << " b is " << b << std::endl; std::cout << std::boolalpha << "Got another event 5, s is " << s << " b is " << b << std::endl;
}); });
// Dispatch the events, the first argument is always the event type. // Dispatch the events, the first argument is always the event type.
@ -107,39 +107,39 @@ The listener's prototype is not required to be same as the dispatcher, it's fine
```c++ ```c++
// Define an Event to hold all parameters. // Define an Event to hold all parameters.
struct MyEvent { struct MyEvent {
int type; int type;
std::string message; std::string message;
int param; int param;
}; };
// Define policies to let the dispatcher knows how to // Define policies to let the dispatcher knows how to
// extract the event type. // extract the event type.
struct MyEventPolicies struct MyEventPolicies
{ {
static int getEvent(const MyEvent & e, bool /*b*/) { static int getEvent(const MyEvent & e, bool /*b*/) {
return e.type; return e.type;
} }
}; };
// Pass MyEventPolicies as the third template argument of EventDispatcher. // Pass MyEventPolicies as the third template argument of EventDispatcher.
// Note: the first template argument is the event type type int, not MyEvent. // Note: the first template argument is the event type type int, not MyEvent.
eventpp::EventDispatcher< eventpp::EventDispatcher<
int, int,
void (const MyEvent &, bool), void (const MyEvent &, bool),
MyEventPolicies MyEventPolicies
> dispatcher; > dispatcher;
// Add a listener. // Add a listener.
// Note: the first argument is the event type of type int, not MyEvent. // Note: the first argument is the event type of type int, not MyEvent.
dispatcher.appendListener(3, [](const MyEvent & e, bool b) { dispatcher.appendListener(3, [](const MyEvent & e, bool b) {
std::cout std::cout
<< std::boolalpha << std::boolalpha
<< "Got event 3" << std::endl << "Got event 3" << std::endl
<< "Event::type is " << e.type << std::endl << "Event::type is " << e.type << std::endl
<< "Event::message is " << e.message << std::endl << "Event::message is " << e.message << std::endl
<< "Event::param is " << e.param << std::endl << "Event::param is " << e.param << std::endl
<< "b is " << b << std::endl << "b is " << b << std::endl
; ;
}); });
// Dispatch the event. // Dispatch the event.

View File

@ -13,15 +13,15 @@ Note if you are going to try the tutorial code, you'd better test the code under
eventpp::EventQueue<int, void (const std::string &, std::unique_ptr<int> &)> queue; eventpp::EventQueue<int, void (const std::string &, std::unique_ptr<int> &)> queue;
queue.appendListener(3, [](const std::string & s, std::unique_ptr<int> & n) { queue.appendListener(3, [](const std::string & s, std::unique_ptr<int> & n) {
std::cout << "Got event 3, s is " << s << " n is " << *n << std::endl; std::cout << "Got event 3, s is " << s << " n is " << *n << std::endl;
}); });
// The listener prototype doesn't need to be exactly same as the dispatcher. // The listener prototype doesn't need to be exactly same as the dispatcher.
// It would be find as long as the arguments is compatible with the dispatcher. // It would be find as long as the arguments is compatible with the dispatcher.
queue.appendListener(5, [](std::string s, const std::unique_ptr<int> & n) { queue.appendListener(5, [](std::string s, const std::unique_ptr<int> & n) {
std::cout << "Got event 5, s is " << s << " n is " << *n << std::endl; std::cout << "Got event 5, s is " << s << " n is " << *n << std::endl;
}); });
queue.appendListener(5, [](const std::string & s, std::unique_ptr<int> & n) { queue.appendListener(5, [](const std::string & s, std::unique_ptr<int> & n) {
std::cout << "Got another event 5, s is " << s << " n is " << *n << std::endl; std::cout << "Got another event 5, s is " << s << " n is " << *n << std::endl;
}); });
// Enqueue the events, the first argument is always the event type. // Enqueue the events, the first argument is always the event type.
@ -59,19 +59,19 @@ constexpr int otherEvent = 2;
// Start a thread to process the event queue. // Start a thread to process the event queue.
// All listeners are invoked in that thread. // All listeners are invoked in that thread.
std::thread thread([stopEvent, otherEvent, &queue]() { std::thread thread([stopEvent, otherEvent, &queue]() {
volatile bool shouldStop = false; volatile bool shouldStop = false;
queue.appendListener(stopEvent, [&shouldStop](int) { queue.appendListener(stopEvent, [&shouldStop](int) {
shouldStop = true; shouldStop = true;
}); });
queue.appendListener(otherEvent, [](const int index) { queue.appendListener(otherEvent, [](const int index) {
std::cout << "Got event, index is " << index << std::endl; std::cout << "Got event, index is " << index << std::endl;
}); });
while(! shouldStop) { while(! shouldStop) {
queue.wait(); queue.wait();
queue.process(); queue.process();
} }
}); });
// Enqueue an event from the main thread. After sleeping for 10 milliseconds, // Enqueue an event from the main thread. After sleeping for 10 milliseconds,
@ -85,20 +85,20 @@ std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::cout << "Should have triggered event with index = 2" << std::endl; std::cout << "Should have triggered event with index = 2" << std::endl;
{ {
// EventQueue::DisableQueueNotify is a RAII class that // EventQueue::DisableQueueNotify is a RAII class that
// disables waking up any waiting threads. // disables waking up any waiting threads.
// So no events should be triggered in this code block. // So no events should be triggered in this code block.
// DisableQueueNotify is useful when adding lots of events at the same time // DisableQueueNotify is useful when adding lots of events at the same time
// and only want to wake up the waiting threads after all events are added. // and only want to wake up the waiting threads after all events are added.
EQ::DisableQueueNotify disableNotify(&queue); EQ::DisableQueueNotify disableNotify(&queue);
queue.enqueue(otherEvent, 10); queue.enqueue(otherEvent, 10);
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::cout << "Should NOT trigger event with index = 10" << std::endl; std::cout << "Should NOT trigger event with index = 10" << std::endl;
queue.enqueue(otherEvent, 11); queue.enqueue(otherEvent, 11);
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::cout << "Should NOT trigger event with index = 11" << std::endl; std::cout << "Should NOT trigger event with index = 11" << std::endl;
} }
// The DisableQueueNotify object is destroyed here, and has resumed // The DisableQueueNotify object is destroyed here, and has resumed
// waking up waiting threads. So the events should be triggered. // waking up waiting threads. So the events should be triggered.

View File

@ -52,8 +52,8 @@ In brief, MSVC, GCC, Clang that has well support for C++11, or released after 20
* The library: C++11. * The library: C++11.
* To develop the library * To develop the library
* Unit tests: C++17. * Unit tests: C++17.
* Tutorials: C++11. * Tutorials: C++11.
* Benchmakrs: C++11. * Benchmakrs: C++11.
## Quick start ## Quick start
@ -101,10 +101,10 @@ Note: the method 2 doesn't work well with MingW on Windows. It works well on Lin
#include "eventpp/callbacklist.h" #include "eventpp/callbacklist.h"
eventpp::CallbackList<void (const std::string &, const bool)> callbackList; eventpp::CallbackList<void (const std::string &, const bool)> callbackList;
callbackList.append([](const std::string & s, const bool b) { callbackList.append([](const std::string & s, const bool b) {
std::cout << std::boolalpha << "Got callback 1, s is " << s << " b is " << b << std::endl; std::cout << std::boolalpha << "Got callback 1, s is " << s << " b is " << b << std::endl;
}); });
callbackList.append([](std::string s, int b) { callbackList.append([](std::string s, int b) {
std::cout << std::boolalpha << "Got callback 2, s is " << s << " b is " << b << std::endl; std::cout << std::boolalpha << "Got callback 2, s is " << s << " b is " << b << std::endl;
}); });
callbackList("Hello world", true); callbackList("Hello world", true);
``` ```
@ -114,13 +114,13 @@ callbackList("Hello world", true);
#include "eventpp/eventdispatcher.h" #include "eventpp/eventdispatcher.h"
eventpp::EventDispatcher<int, void ()> dispatcher; eventpp::EventDispatcher<int, void ()> dispatcher;
dispatcher.appendListener(3, []() { dispatcher.appendListener(3, []() {
std::cout << "Got event 3." << std::endl; std::cout << "Got event 3." << std::endl;
}); });
dispatcher.appendListener(5, []() { dispatcher.appendListener(5, []() {
std::cout << "Got event 5." << std::endl; std::cout << "Got event 5." << std::endl;
}); });
dispatcher.appendListener(5, []() { dispatcher.appendListener(5, []() {
std::cout << "Got another event 5." << std::endl; std::cout << "Got another event 5." << std::endl;
}); });
// dispatch event 3 // dispatch event 3
dispatcher.dispatch(3); dispatcher.dispatch(3);
@ -133,10 +133,10 @@ dispatcher.dispatch(5);
eventpp::EventQueue<int, void (const std::string &, const bool)> queue; eventpp::EventQueue<int, void (const std::string &, const bool)> queue;
queue.appendListener(3, [](const std::string s, bool b) { queue.appendListener(3, [](const std::string s, bool b) {
std::cout << std::boolalpha << "Got event 3, s is " << s << " b is " << b << std::endl; std::cout << std::boolalpha << "Got event 3, s is " << s << " b is " << b << std::endl;
}); });
queue.appendListener(5, [](const std::string s, bool b) { queue.appendListener(5, [](const std::string s, bool b) {
std::cout << std::boolalpha << "Got event 5, s is " << s << " b is " << b << std::endl; std::cout << std::boolalpha << "Got event 5, s is " << s << " b is " << b << std::endl;
}); });
// The listeners are not triggered during enqueue. // The listeners are not triggered during enqueue.