mirror of
https://github.com/wqking/eventpp.git
synced 2024-12-25 23:30:49 +08:00
tab->spaces in documents for easier read
This commit is contained in:
parent
05f3dc8249
commit
6e5f6ee45d
26
doc/anyid.md
26
doc/anyid.md
@ -54,9 +54,9 @@ A typical implementation of `Digester`:
|
||||
template <typename T>
|
||||
struct MyDigest
|
||||
{
|
||||
TheDigestTypeSuchAsSizeT operator() (const T & value) const {
|
||||
// compute the digest of value and return the digest.
|
||||
}
|
||||
TheDigestTypeSuchAsSizeT operator() (const T & value) const {
|
||||
// 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.
|
||||
@ -65,12 +65,12 @@ A typical implementation of `Storage`:
|
||||
```c++
|
||||
struct MyStorage
|
||||
{
|
||||
template <typename T>
|
||||
MyStorage(const T & value) {
|
||||
// store the value
|
||||
}
|
||||
|
||||
// any other member functions can be added, such as getting the underlying value.
|
||||
template <typename T>
|
||||
MyStorage(const T & value) {
|
||||
// store the value
|
||||
}
|
||||
|
||||
// any other member functions can be added, such as getting the underlying value.
|
||||
};
|
||||
```
|
||||
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.
|
||||
struct MyStorage
|
||||
{
|
||||
MyStorage(const int value) {}
|
||||
MyStorage(const std::string & value) {}
|
||||
|
||||
// any other member functions can be added, such as getting the underlying value.
|
||||
MyStorage(const int value) {}
|
||||
MyStorage(const std::string & value) {}
|
||||
|
||||
// any other member functions can be added, such as getting the underlying value.
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -70,74 +70,74 @@ Below is the example code to demonstrate how to use `argumentAdapter`. There are
|
||||
// Define the event types
|
||||
enum class EventType
|
||||
{
|
||||
// for MouseEvent
|
||||
mouse,
|
||||
// for MouseEvent
|
||||
mouse,
|
||||
|
||||
// for KeyEvent
|
||||
key,
|
||||
// for KeyEvent
|
||||
key,
|
||||
|
||||
// for MessageEvent
|
||||
message,
|
||||
// for MessageEvent
|
||||
message,
|
||||
|
||||
// For either MouseEvent or KeyEvent, we use this type to demonstrate
|
||||
// how to use conditionalFunctor
|
||||
input,
|
||||
// For either MouseEvent or KeyEvent, we use this type to demonstrate
|
||||
// how to use conditionalFunctor
|
||||
input,
|
||||
};
|
||||
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
Event() {
|
||||
}
|
||||
Event() {
|
||||
}
|
||||
|
||||
// Make the Event polymorphism so we can use dynamic_cast to detect
|
||||
// if it's a MouseEvent or KeyEvent
|
||||
virtual ~Event() {
|
||||
}
|
||||
// Make the Event polymorphism so we can use dynamic_cast to detect
|
||||
// if it's a MouseEvent or KeyEvent
|
||||
virtual ~Event() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class MouseEvent : public Event
|
||||
{
|
||||
public:
|
||||
MouseEvent(const int x, const int y)
|
||||
: x(x), y(y)
|
||||
{
|
||||
}
|
||||
MouseEvent(const int x, const int y)
|
||||
: x(x), y(y)
|
||||
{
|
||||
}
|
||||
|
||||
int getX() const { return x; }
|
||||
int getY() const { return y; }
|
||||
int getX() const { return x; }
|
||||
int getY() const { return y; }
|
||||
|
||||
private:
|
||||
int x;
|
||||
int y;
|
||||
int x;
|
||||
int y;
|
||||
};
|
||||
|
||||
class KeyEvent : public Event
|
||||
{
|
||||
public:
|
||||
explicit KeyEvent(const int key)
|
||||
: key(key)
|
||||
{
|
||||
}
|
||||
explicit KeyEvent(const int key)
|
||||
: key(key)
|
||||
{
|
||||
}
|
||||
|
||||
int getKey() const { return key; }
|
||||
int getKey() const { return key; }
|
||||
|
||||
private:
|
||||
int key;
|
||||
int key;
|
||||
};
|
||||
|
||||
class MessageEvent : public Event
|
||||
{
|
||||
public:
|
||||
explicit MessageEvent(const std::string & message)
|
||||
: message(message) {
|
||||
}
|
||||
explicit MessageEvent(const std::string & message)
|
||||
: message(message) {
|
||||
}
|
||||
|
||||
std::string getMessage() const { return message; }
|
||||
std::string getMessage() const { return message; }
|
||||
|
||||
private:
|
||||
std::string message;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
// A free function that will be added as listener later.
|
||||
@ -145,61 +145,61 @@ private:
|
||||
// lambda, functor object, std::function, free function, etc.
|
||||
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()
|
||||
{
|
||||
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 &'
|
||||
//eventDispatcher.appendListener(mouseEventId, [](const MouseEvent & e) {});
|
||||
// This can't compile because a 'const Event &' can be passed to 'const MouseEvent &'
|
||||
//eventDispatcher.appendListener(mouseEventId, [](const MouseEvent & e) {});
|
||||
|
||||
// This compiles. eventpp::argumentAdapter creates a functor object that static_cast
|
||||
// 'const Event &' to 'const MouseEvent &' automatically.
|
||||
// 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
|
||||
// the type. This rule also applies to other functor object.
|
||||
eventDispatcher.appendListener(
|
||||
EventType::mouse,
|
||||
eventpp::argumentAdapter<void(const MouseEvent &)>([](const MouseEvent & e) {
|
||||
std::cout << "Received MouseEvent in lambda, x=" << e.getX() << " y=" << e.getY() << std::endl;
|
||||
})
|
||||
);
|
||||
eventDispatcher.appendListener(
|
||||
EventType::message,
|
||||
eventpp::argumentAdapter<void(const MessageEvent &)>([](const MessageEvent & e) {
|
||||
std::cout << "Received MessageEvent in lambda, message=" << e.getMessage() << std::endl;
|
||||
})
|
||||
);
|
||||
// This compiles. eventpp::argumentAdapter creates a functor object that static_cast
|
||||
// 'const Event &' to 'const MouseEvent &' automatically.
|
||||
// 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
|
||||
// the type. This rule also applies to other functor object.
|
||||
eventDispatcher.appendListener(
|
||||
EventType::mouse,
|
||||
eventpp::argumentAdapter<void(const MouseEvent &)>([](const MouseEvent & e) {
|
||||
std::cout << "Received MouseEvent in lambda, x=" << e.getX() << " y=" << e.getY() << std::endl;
|
||||
})
|
||||
);
|
||||
eventDispatcher.appendListener(
|
||||
EventType::message,
|
||||
eventpp::argumentAdapter<void(const MessageEvent &)>([](const MessageEvent & e) {
|
||||
std::cout << "Received MessageEvent in lambda, message=" << e.getMessage() << std::endl;
|
||||
})
|
||||
);
|
||||
|
||||
// callback 2 -- std::function
|
||||
// We don't need to pass the function type to eventpp::argumentAdapter because it can
|
||||
// deduce the type from the std::function
|
||||
eventDispatcher.appendListener(
|
||||
EventType::key,
|
||||
eventpp::argumentAdapter(std::function<void(const KeyEvent &)>([](const KeyEvent & e) {
|
||||
std::cout << "Received KeyEvent in std::function, key=" << e.getKey() << std::endl;
|
||||
}))
|
||||
);
|
||||
// callback 2 -- std::function
|
||||
// We don't need to pass the function type to eventpp::argumentAdapter because it can
|
||||
// deduce the type from the std::function
|
||||
eventDispatcher.appendListener(
|
||||
EventType::key,
|
||||
eventpp::argumentAdapter(std::function<void(const KeyEvent &)>([](const KeyEvent & e) {
|
||||
std::cout << "Received KeyEvent in std::function, key=" << e.getKey() << std::endl;
|
||||
}))
|
||||
);
|
||||
|
||||
// callback 3 -- free function
|
||||
// We don't need to pass the function type to eventpp::argumentAdapter because it can
|
||||
// deduce the type from the free function
|
||||
eventDispatcher.appendListener(
|
||||
EventType::mouse,
|
||||
eventpp::argumentAdapter(tutorialArgumentAdapterFreeFunction)
|
||||
);
|
||||
// callback 3 -- free function
|
||||
// We don't need to pass the function type to eventpp::argumentAdapter because it can
|
||||
// deduce the type from the free function
|
||||
eventDispatcher.appendListener(
|
||||
EventType::mouse,
|
||||
eventpp::argumentAdapter(tutorialArgumentAdapterFreeFunction)
|
||||
);
|
||||
|
||||
eventDispatcher.dispatch(EventType::mouse, MouseEvent(3, 5));
|
||||
eventDispatcher.dispatch(EventType::key, KeyEvent(255));
|
||||
eventDispatcher.dispatch(EventType::message, MessageEvent("Hello, argumentAdapter"));
|
||||
// In syntax we can dispatch KeyEvent under EventType::mouse, in our case,
|
||||
// the EventType::mouse listener casts KeyEvent to MouseEvent, which is invalid object,
|
||||
// and the listener will either use garbled data, or crash.
|
||||
//eventDispatcher.dispatch(EventType::mouse, KeyEvent(255));
|
||||
eventDispatcher.dispatch(EventType::mouse, MouseEvent(3, 5));
|
||||
eventDispatcher.dispatch(EventType::key, KeyEvent(255));
|
||||
eventDispatcher.dispatch(EventType::message, MessageEvent("Hello, argumentAdapter"));
|
||||
// In syntax we can dispatch KeyEvent under EventType::mouse, in our case,
|
||||
// the EventType::mouse listener casts KeyEvent to MouseEvent, which is invalid object,
|
||||
// and the listener will either use garbled data, or crash.
|
||||
//eventDispatcher.dispatch(EventType::mouse, KeyEvent(255));
|
||||
}
|
||||
|
||||
void example2()
|
||||
@ -212,25 +212,25 @@ eventpp::EventDispatcher<EventType, void(const Event &)> eventDispatcher;
|
||||
|
||||
// listener 1
|
||||
eventDispatcher.appendListener(
|
||||
EventType::input,
|
||||
eventpp::conditionalFunctor(
|
||||
eventpp::argumentAdapter<void(const MouseEvent &)>([](const MouseEvent & e) {
|
||||
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 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; }
|
||||
)
|
||||
EventType::input,
|
||||
eventpp::conditionalFunctor(
|
||||
eventpp::argumentAdapter<void(const MouseEvent &)>([](const MouseEvent & e) {
|
||||
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 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; }
|
||||
)
|
||||
);
|
||||
// listener 2
|
||||
eventDispatcher.appendListener(
|
||||
EventType::input,
|
||||
eventpp::conditionalFunctor(
|
||||
eventpp::argumentAdapter<void(const KeyEvent &)>([](const KeyEvent & e) {
|
||||
std::cout << "Received KeyEvent in conditional tutorial, key=" << e.getKey() << std::endl;
|
||||
}),
|
||||
[](const Event & e) { return dynamic_cast<const KeyEvent *>(&e) != nullptr; }
|
||||
)
|
||||
EventType::input,
|
||||
eventpp::conditionalFunctor(
|
||||
eventpp::argumentAdapter<void(const KeyEvent &)>([](const KeyEvent & e) {
|
||||
std::cout << "Received KeyEvent in conditional tutorial, key=" << e.getKey() << std::endl;
|
||||
}),
|
||||
[](const Event & e) { return dynamic_cast<const KeyEvent *>(&e) != nullptr; }
|
||||
)
|
||||
);
|
||||
|
||||
// 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
|
||||
// 'std::shared_ptr<Event>' to 'std::shared_ptr<MouseEvent>' automatically.
|
||||
eventQueue.appendListener(
|
||||
EventType::mouse,
|
||||
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;
|
||||
})
|
||||
EventType::mouse,
|
||||
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;
|
||||
})
|
||||
);
|
||||
|
||||
eventQueue.enqueue(EventType::mouse, std::make_shared<MouseEvent>(3, 5));
|
||||
|
408
doc/benchmark.md
408
doc/benchmark.md
@ -8,40 +8,40 @@ Time unit: milliseconds (unless explicitly specified)
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Iterations</th>
|
||||
<th>Queue size</th>
|
||||
<th>Event count</th>
|
||||
<th>Event Types</th>
|
||||
<th>Listener count</th>
|
||||
<th>Time of single threading</th>
|
||||
<th>Time of multi threading</th>
|
||||
<th>Iterations</th>
|
||||
<th>Queue size</th>
|
||||
<th>Event count</th>
|
||||
<th>Event Types</th>
|
||||
<th>Listener count</th>
|
||||
<th>Time of single threading</th>
|
||||
<th>Time of multi threading</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>100k</td>
|
||||
<td>100</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>401</td>
|
||||
<td>1146</td>
|
||||
<td>100k</td>
|
||||
<td>100</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>401</td>
|
||||
<td>1146</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>100k</td>
|
||||
<td>1000</td>
|
||||
<td>100M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>4012</td>
|
||||
<td>11467</td>
|
||||
<td>100k</td>
|
||||
<td>1000</td>
|
||||
<td>100M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>4012</td>
|
||||
<td>11467</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>100k</td>
|
||||
<td>1000</td>
|
||||
<td>100M</td>
|
||||
<td>1000</td>
|
||||
<td>1000</td>
|
||||
<td>4102</td>
|
||||
<td>11600</td>
|
||||
<td>100k</td>
|
||||
<td>1000</td>
|
||||
<td>100M</td>
|
||||
<td>1000</td>
|
||||
<td>1000</td>
|
||||
<td>4102</td>
|
||||
<td>11600</td>
|
||||
</tr>
|
||||
<table>
|
||||
|
||||
@ -53,107 +53,107 @@ The EventQueue is processed in one thread. The Single/Multi threading in the tab
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Mutex</th>
|
||||
<th>Enqueue threads</th>
|
||||
<th>Process threads</th>
|
||||
<th>Event count</th>
|
||||
<th>Event Types</th>
|
||||
<th>Listener count</th>
|
||||
<th>Time</th>
|
||||
<th>Mutex</th>
|
||||
<th>Enqueue threads</th>
|
||||
<th>Process threads</th>
|
||||
<th>Event count</th>
|
||||
<th>Event Types</th>
|
||||
<th>Listener count</th>
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>std::mutex</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>2283</td>
|
||||
<td>std::mutex</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>2283</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SpinLock</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>1692</td>
|
||||
<td>SpinLock</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>1692</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>std::mutex</td>
|
||||
<td>1</td>
|
||||
<td>3</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>3446</td>
|
||||
<td>std::mutex</td>
|
||||
<td>1</td>
|
||||
<td>3</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>3446</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SpinLock</td>
|
||||
<td>1</td>
|
||||
<td>3</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>3025</td>
|
||||
<td>SpinLock</td>
|
||||
<td>1</td>
|
||||
<td>3</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>3025</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>std::mutex</td>
|
||||
<td>2</td>
|
||||
<td>2</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>4000</td>
|
||||
<td>std::mutex</td>
|
||||
<td>2</td>
|
||||
<td>2</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>4000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SpinLock</td>
|
||||
<td>2</td>
|
||||
<td>2</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>3076</td>
|
||||
<td>SpinLock</td>
|
||||
<td>2</td>
|
||||
<td>2</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>3076</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>std::mutex</td>
|
||||
<td>4</td>
|
||||
<td>4</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>1971</td>
|
||||
<td>std::mutex</td>
|
||||
<td>4</td>
|
||||
<td>4</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>1971</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SpinLock</td>
|
||||
<td>4</td>
|
||||
<td>4</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>1755</td>
|
||||
<td>SpinLock</td>
|
||||
<td>4</td>
|
||||
<td>4</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>1755</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>std::mutex</td>
|
||||
<td>16</td>
|
||||
<td>16</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>928</td>
|
||||
<td>std::mutex</td>
|
||||
<td>16</td>
|
||||
<td>16</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>928</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SpinLock</td>
|
||||
<td>16</td>
|
||||
<td>16</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>2082</td>
|
||||
<td>SpinLock</td>
|
||||
<td>16</td>
|
||||
<td>16</td>
|
||||
<td>10M</td>
|
||||
<td>100</td>
|
||||
<td>100</td>
|
||||
<td>2082</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -172,123 +172,123 @@ Iterations: 100,000,000
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Function</th>
|
||||
<th>Compiler</th>
|
||||
<th>Native invoking</th>
|
||||
<th>CallbackList single threading</th>
|
||||
<th>CallbackList multi threading</th>
|
||||
<th>Function</th>
|
||||
<th>Compiler</th>
|
||||
<th>Native invoking</th>
|
||||
<th>CallbackList single threading</th>
|
||||
<th>CallbackList multi threading</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td rowspan="2">Inline global function</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>217</td>
|
||||
<td>1501</td>
|
||||
<td>6921</td>
|
||||
<td rowspan="2">Inline global function</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>217</td>
|
||||
<td>1501</td>
|
||||
<td>6921</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GCC 7.2</td>
|
||||
<td>187</td>
|
||||
<td>1489</td>
|
||||
<td>4463</td>
|
||||
<td>GCC 7.2</td>
|
||||
<td>187</td>
|
||||
<td>1489</td>
|
||||
<td>4463</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td rowspan="2">Non-inline global function</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>241</td>
|
||||
<td>1526</td>
|
||||
<td>6544</td>
|
||||
<td rowspan="2">Non-inline global function</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>241</td>
|
||||
<td>1526</td>
|
||||
<td>6544</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GCC 7.2</td>
|
||||
<td>233</td>
|
||||
<td>1488</td>
|
||||
<td>4787</td>
|
||||
<td>GCC 7.2</td>
|
||||
<td>233</td>
|
||||
<td>1488</td>
|
||||
<td>4787</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td rowspan="2">Function object</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>194</td>
|
||||
<td>1498</td>
|
||||
<td>6433</td>
|
||||
<td rowspan="2">Function object</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>194</td>
|
||||
<td>1498</td>
|
||||
<td>6433</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GCC 7.2</td>
|
||||
<td>212</td>
|
||||
<td>1485</td>
|
||||
<td>4951</td>
|
||||
<td>GCC 7.2</td>
|
||||
<td>212</td>
|
||||
<td>1485</td>
|
||||
<td>4951</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td rowspan="2">Member virtual function</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>207</td>
|
||||
<td>1533</td>
|
||||
<td>6558</td>
|
||||
<td rowspan="2">Member virtual function</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>207</td>
|
||||
<td>1533</td>
|
||||
<td>6558</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GCC 7.2</td>
|
||||
<td>212</td>
|
||||
<td>1485</td>
|
||||
<td>4489</td>
|
||||
<td>GCC 7.2</td>
|
||||
<td>212</td>
|
||||
<td>1485</td>
|
||||
<td>4489</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td rowspan="2">Member non-virtual function</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>214</td>
|
||||
<td>1533</td>
|
||||
<td>6390</td>
|
||||
<td rowspan="2">Member non-virtual function</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>214</td>
|
||||
<td>1533</td>
|
||||
<td>6390</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GCC 7.2</td>
|
||||
<td>211</td>
|
||||
<td>1486</td>
|
||||
<td>4872</td>
|
||||
<td>GCC 7.2</td>
|
||||
<td>211</td>
|
||||
<td>1486</td>
|
||||
<td>4872</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td rowspan="2">Member non-inline virtual function</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>206</td>
|
||||
<td>1522</td>
|
||||
<td>6578</td>
|
||||
<td rowspan="2">Member non-inline virtual function</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>206</td>
|
||||
<td>1522</td>
|
||||
<td>6578</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GCC 7.2</td>
|
||||
<td>182</td>
|
||||
<td>1666</td>
|
||||
<td>4593</td>
|
||||
<td>GCC 7.2</td>
|
||||
<td>182</td>
|
||||
<td>1666</td>
|
||||
<td>4593</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td rowspan="2">Member non-inline non-virtual function</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>206</td>
|
||||
<td>1491</td>
|
||||
<td>6992</td>
|
||||
<td rowspan="2">Member non-inline non-virtual function</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>206</td>
|
||||
<td>1491</td>
|
||||
<td>6992</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GCC 7.2</td>
|
||||
<td>205</td>
|
||||
<td>1486</td>
|
||||
<td>4490</td>
|
||||
<td>GCC 7.2</td>
|
||||
<td>205</td>
|
||||
<td>1486</td>
|
||||
<td>4490</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td rowspan="2">All functions</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>1374</td>
|
||||
<td>10951</td>
|
||||
<td>29973</td>
|
||||
<td rowspan="2">All functions</td>
|
||||
<td>MSVC 2017</td>
|
||||
<td>1374</td>
|
||||
<td>10951</td>
|
||||
<td>29973</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GCC 7.2</td>
|
||||
<td>1223</td>
|
||||
<td>9770</td>
|
||||
<td>22958</td>
|
||||
<td>GCC 7.2</td>
|
||||
<td>1223</td>
|
||||
<td>9770</td>
|
||||
<td>22958</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
@ -306,40 +306,40 @@ volatile int globalValue = 0;
|
||||
|
||||
void globalFunction(int a, const int b)
|
||||
{
|
||||
globalValue += a + b;
|
||||
globalValue += a + b;
|
||||
}
|
||||
|
||||
NON_INLINE void nonInlineGlobalFunction(int a, const int b)
|
||||
{
|
||||
globalValue += a + b;
|
||||
globalValue += a + b;
|
||||
}
|
||||
|
||||
struct FunctionObject
|
||||
{
|
||||
void operator() (int a, const int b)
|
||||
{
|
||||
globalValue += a + b;
|
||||
}
|
||||
void operator() (int a, const int b)
|
||||
{
|
||||
globalValue += a + b;
|
||||
}
|
||||
|
||||
virtual void virFunc(int a, const int b)
|
||||
{
|
||||
globalValue += a + b;
|
||||
}
|
||||
virtual void virFunc(int a, const int b)
|
||||
{
|
||||
globalValue += a + b;
|
||||
}
|
||||
|
||||
void nonVirFunc(int a, const int b)
|
||||
{
|
||||
globalValue += a + b;
|
||||
}
|
||||
void nonVirFunc(int a, const int b)
|
||||
{
|
||||
globalValue += a + b;
|
||||
}
|
||||
|
||||
NON_INLINE virtual void nonInlineVirFunc(int a, const int b)
|
||||
{
|
||||
globalValue += a + b;
|
||||
}
|
||||
NON_INLINE virtual void nonInlineVirFunc(int a, const int b)
|
||||
{
|
||||
globalValue += a + b;
|
||||
}
|
||||
|
||||
NON_INLINE void nonInlineNonVirFunc(int a, const int b)
|
||||
{
|
||||
globalValue += a + b;
|
||||
}
|
||||
NON_INLINE void nonInlineNonVirFunc(int a, const int b)
|
||||
{
|
||||
globalValue += a + b;
|
||||
}
|
||||
};
|
||||
|
||||
#undef NON_INLINE
|
||||
|
@ -35,8 +35,8 @@ eventpp/callbacklist.h
|
||||
|
||||
```c++
|
||||
template <
|
||||
typename Prototype,
|
||||
typename Policies = DefaultPolicies
|
||||
typename Prototype,
|
||||
typename Policies = DefaultPolicies
|
||||
>
|
||||
class CallbackList;
|
||||
```
|
||||
|
@ -10,14 +10,14 @@ For example,
|
||||
eventpp::CallbackList<void(int)> callbackList;
|
||||
|
||||
callbackList.append(
|
||||
eventpp::conditionalFunctor(
|
||||
[](const int value) {
|
||||
std::cout << "We should get value 1." << here;
|
||||
},
|
||||
[](const int value) {
|
||||
return value == 1;
|
||||
}
|
||||
)
|
||||
eventpp::conditionalFunctor(
|
||||
[](const int value) {
|
||||
std::cout << "We should get value 1." << here;
|
||||
},
|
||||
[](const int value) {
|
||||
return value == 1;
|
||||
}
|
||||
)
|
||||
);
|
||||
callbackList(2); // not trigger the callback
|
||||
callbackList(1); // trigger the callback
|
||||
@ -44,34 +44,34 @@ eventpp::CallbackList<void(int)> callbackList;
|
||||
|
||||
std::vector<int> dataList(3);
|
||||
callbackList.append(
|
||||
eventpp::conditionalFunctor(
|
||||
[&dataList](const int index) {
|
||||
++dataList[index];
|
||||
},
|
||||
[](const int index) {
|
||||
return index == 0;
|
||||
}
|
||||
)
|
||||
eventpp::conditionalFunctor(
|
||||
[&dataList](const int index) {
|
||||
++dataList[index];
|
||||
},
|
||||
[](const int index) {
|
||||
return index == 0;
|
||||
}
|
||||
)
|
||||
);
|
||||
callbackList.append(
|
||||
eventpp::conditionalFunctor(
|
||||
[&dataList](const int index) {
|
||||
++dataList[index];
|
||||
},
|
||||
[](const int index) {
|
||||
return index == 1;
|
||||
}
|
||||
)
|
||||
eventpp::conditionalFunctor(
|
||||
[&dataList](const int index) {
|
||||
++dataList[index];
|
||||
},
|
||||
[](const int index) {
|
||||
return index == 1;
|
||||
}
|
||||
)
|
||||
);
|
||||
callbackList.append(
|
||||
eventpp::conditionalFunctor(
|
||||
[&dataList](const int index) {
|
||||
++dataList[index];
|
||||
},
|
||||
[](const int index) {
|
||||
return index == 2;
|
||||
}
|
||||
)
|
||||
eventpp::conditionalFunctor(
|
||||
[&dataList](const int index) {
|
||||
++dataList[index];
|
||||
},
|
||||
[](const int index) {
|
||||
return index == 2;
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
REQUIRE(dataList == std::vector<int>{ 0, 0, 0 });
|
||||
|
@ -49,47 +49,47 @@ Constructs an instance of ConditionalRemover.
|
||||
```c++
|
||||
template <typename Condition>
|
||||
typename DispatcherType::Handle appendListener(
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const Condition & condition
|
||||
);
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const Condition & condition
|
||||
);
|
||||
|
||||
template <typename Condition>
|
||||
typename DispatcherType::Handle prependListener(
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const Condition & condition
|
||||
);
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const Condition & condition
|
||||
);
|
||||
|
||||
template <typename Condition>
|
||||
typename DispatcherType::Handle insertListener(
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const typename DispatcherType::Handle & before,
|
||||
const Condition & condition
|
||||
);
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const typename DispatcherType::Handle & before,
|
||||
const Condition & condition
|
||||
);
|
||||
```
|
||||
|
||||
**Member functions for CallbackList**
|
||||
```c++
|
||||
template <typename Condition>
|
||||
typename CallbackListType::Handle append(
|
||||
const typename CallbackListType::Callback & listener,
|
||||
const Condition & condition
|
||||
);
|
||||
const typename CallbackListType::Callback & listener,
|
||||
const Condition & condition
|
||||
);
|
||||
|
||||
template <typename Condition>
|
||||
typename CallbackListType::Handle prepend(
|
||||
const typename CallbackListType::Callback & listener,
|
||||
const Condition & condition
|
||||
);
|
||||
const typename CallbackListType::Callback & listener,
|
||||
const Condition & condition
|
||||
);
|
||||
|
||||
template <typename Condition>
|
||||
typename CallbackListType::Handle insert(
|
||||
const typename CallbackListType::Callback & listener,
|
||||
const typename CallbackListType::Handle & before,
|
||||
const Condition & condition
|
||||
);
|
||||
const typename CallbackListType::Callback & listener,
|
||||
const typename CallbackListType::Handle & before,
|
||||
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.
|
||||
@ -126,26 +126,26 @@ eventpp::EventDispatcher<int, void ()> dispatcher;
|
||||
constexpr int event = 3;
|
||||
|
||||
dispatcher.appendListener(event, []() {
|
||||
// listener A
|
||||
// listener A
|
||||
});
|
||||
|
||||
// Note the ConditionalRemover instance returned by conditionalRemover is invoked
|
||||
// prependListener and destroyed immediately.
|
||||
std::string removeWho;
|
||||
eventpp::conditionalRemover(dispatcher).prependListener(event, [&dataList]() {
|
||||
// listener B
|
||||
// listener B
|
||||
}, [&removeWho]() -> bool {
|
||||
return removeWho == "removeB";
|
||||
return removeWho == "removeB";
|
||||
});
|
||||
auto handle = eventpp::conditionalRemover(dispatcher).appendListener(event, [&dataList]() {
|
||||
// listener C
|
||||
// listener C
|
||||
}, [&removeWho]() -> bool {
|
||||
return removeWho == "removeC";
|
||||
return removeWho == "removeC";
|
||||
});
|
||||
eventpp::conditionalRemover(dispatcher).insertListener(event, [&dataList]() {
|
||||
// listener D
|
||||
// listener D
|
||||
}, handle, [&removeWho]() -> bool {
|
||||
return removeWho == "removeD";
|
||||
return removeWho == "removeD";
|
||||
});
|
||||
|
||||
dispatcher.dispatch(event);
|
||||
|
@ -48,42 +48,42 @@ Constructs an instance of CounterRemover.
|
||||
**Member functions for EventDispatcher and EventQueue**
|
||||
```c++
|
||||
typename DispatcherType::Handle appendListener(
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const int triggerCount = 1
|
||||
);
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const int triggerCount = 1
|
||||
);
|
||||
|
||||
typename DispatcherType::Handle prependListener(
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const int triggerCount = 1
|
||||
);
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const int triggerCount = 1
|
||||
);
|
||||
|
||||
typename DispatcherType::Handle insertListener(
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const typename DispatcherType::Handle & before,
|
||||
const int triggerCount = 1
|
||||
);
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const typename DispatcherType::Handle & before,
|
||||
const int triggerCount = 1
|
||||
);
|
||||
```
|
||||
|
||||
**Member functions for CallbackList**
|
||||
```c++
|
||||
typename CallbackListType::Handle append(
|
||||
const typename CallbackListType::Callback & listener,
|
||||
const int triggerCount = 1
|
||||
);
|
||||
const typename CallbackListType::Callback & listener,
|
||||
const int triggerCount = 1
|
||||
);
|
||||
|
||||
typename CallbackListType::Handle prepend(
|
||||
const typename CallbackListType::Callback & listener,
|
||||
const int triggerCount = 1
|
||||
);
|
||||
const typename CallbackListType::Callback & listener,
|
||||
const int triggerCount = 1
|
||||
);
|
||||
|
||||
typename CallbackListType::Handle insert(
|
||||
const typename CallbackListType::Callback & listener,
|
||||
const typename CallbackListType::Handle & before,
|
||||
const int triggerCount = 1
|
||||
);
|
||||
const typename CallbackListType::Callback & listener,
|
||||
const typename CallbackListType::Handle & before,
|
||||
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.
|
||||
@ -110,19 +110,19 @@ eventpp::EventDispatcher<int, void ()> dispatcher;
|
||||
constexpr int event = 3;
|
||||
|
||||
dispatcher.appendListener(event, []() {
|
||||
// listener A
|
||||
// listener A
|
||||
});
|
||||
|
||||
// Note the CounterRemover instance returned by counterRemover is invoked
|
||||
// prependListener and destroyed immediately.
|
||||
eventpp::counterRemover(dispatcher).prependListener(event, []() {
|
||||
// listener B
|
||||
// listener B
|
||||
});
|
||||
auto handle = eventpp::counterRemover(dispatcher).appendListener(event, []() {
|
||||
// listener C
|
||||
// listener C
|
||||
}, 2);
|
||||
eventpp::counterRemover(dispatcher).insertListener(event, []() {
|
||||
// listener D
|
||||
// listener D
|
||||
}, handle, 3);
|
||||
|
||||
dispatcher.dispatch(event);
|
||||
|
@ -34,9 +34,9 @@ eventpp/eventdispatcher.h
|
||||
|
||||
```c++
|
||||
template <
|
||||
typename Event,
|
||||
typename Prototype,
|
||||
typename Policies = DefaultPolicies
|
||||
typename Event,
|
||||
typename Prototype,
|
||||
typename Policies = DefaultPolicies
|
||||
>
|
||||
class EventDispatcher;
|
||||
```
|
||||
|
@ -15,23 +15,23 @@ class Event
|
||||
class EventMouseDown : public Event
|
||||
{
|
||||
public:
|
||||
int getX() const;
|
||||
int getY() const;
|
||||
int getButton() const;
|
||||
|
||||
int getX() const;
|
||||
int getY() const;
|
||||
int getButton() const;
|
||||
|
||||
private:
|
||||
int x;
|
||||
int y;
|
||||
int button;
|
||||
int x;
|
||||
int y;
|
||||
int button;
|
||||
};
|
||||
|
||||
class EventKeyDown : public Event
|
||||
{
|
||||
public:
|
||||
int getKey() const;
|
||||
|
||||
int getKey() const;
|
||||
|
||||
private:
|
||||
int key;
|
||||
int key;
|
||||
};
|
||||
|
||||
```
|
||||
@ -62,8 +62,8 @@ The macro always generates a default constructor and a constructor that takes al
|
||||
Code examples:
|
||||
```c++
|
||||
EVENTPP_MAKE_EVENT(
|
||||
EventDraw, Event, EventType::draw,
|
||||
(std::string, getText, setText), (int, getX), (double, getSize)
|
||||
EventDraw, Event, EventType::draw,
|
||||
(std::string, getText, setText), (int, getX), (double, getSize)
|
||||
);
|
||||
```
|
||||
Generates class like (in pseudo code),
|
||||
@ -71,45 +71,45 @@ Generates class like (in pseudo code),
|
||||
class EventDraw : public Event
|
||||
{
|
||||
public:
|
||||
EventDraw(const std::string & text, const int x, const double size)
|
||||
: Event(EventType::draw), text(text), x(x), size(size)
|
||||
{
|
||||
}
|
||||
|
||||
const std::string & getText() const {
|
||||
return text;
|
||||
}
|
||||
|
||||
void setText(const std::string & value) {
|
||||
text = value;
|
||||
}
|
||||
|
||||
const int getX() const {
|
||||
return x;
|
||||
}
|
||||
|
||||
const double getSize() const {
|
||||
return size;
|
||||
}
|
||||
EventDraw(const std::string & text, const int x, const double size)
|
||||
: Event(EventType::draw), text(text), x(x), size(size)
|
||||
{
|
||||
}
|
||||
|
||||
const std::string & getText() const {
|
||||
return text;
|
||||
}
|
||||
|
||||
void setText(const std::string & value) {
|
||||
text = value;
|
||||
}
|
||||
|
||||
const int getX() const {
|
||||
return x;
|
||||
}
|
||||
|
||||
const double getSize() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string text;
|
||||
int x;
|
||||
double size;
|
||||
std::string text;
|
||||
int x;
|
||||
double size;
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
```c++
|
||||
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>`.
|
||||
|
||||
```c++
|
||||
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)`.
|
||||
|
@ -33,9 +33,9 @@ eventpp/eventqueue.h
|
||||
|
||||
```c++
|
||||
template <
|
||||
typename Event,
|
||||
typename Prototype,
|
||||
typename Policies = DefaultPolicies
|
||||
typename Event,
|
||||
typename Prototype,
|
||||
typename Policies = DefaultPolicies
|
||||
>
|
||||
class EventQueue;
|
||||
```
|
||||
@ -49,16 +49,16 @@ EventQueue has the exactly same template parameters with EventDispatcher. Please
|
||||
```c++
|
||||
struct EventQueue::QueuedEvent
|
||||
{
|
||||
EventType event;
|
||||
std::tuple<ArgTypes...> arguments;
|
||||
|
||||
// get the event
|
||||
EventType getEvent() const;
|
||||
EventType event;
|
||||
std::tuple<ArgTypes...> arguments;
|
||||
|
||||
// get the event
|
||||
EventType getEvent() const;
|
||||
|
||||
// get the argument of index N
|
||||
// same as std::get<N>(queuedEvent.arguments)
|
||||
template <std::size_t N>
|
||||
NthArgType getArgument() const;
|
||||
// get the argument of index N
|
||||
// same as std::get<N>(queuedEvent.arguments)
|
||||
template <std::size_t N>
|
||||
NthArgType getArgument() const;
|
||||
};
|
||||
```
|
||||
`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,
|
||||
```c++
|
||||
for(;;) {
|
||||
eventQueue.wait();
|
||||
eventQueue.process();
|
||||
eventQueue.wait();
|
||||
eventQueue.process();
|
||||
}
|
||||
```
|
||||
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++
|
||||
std::atomic<bool> shouldStop(false);
|
||||
for(;;) {
|
||||
while(! eventQueue.waitFor(std::chrono::milliseconds(10)) && ! shouldStop.load()) ;
|
||||
if(shouldStop.load()) {
|
||||
break;
|
||||
}
|
||||
while(! eventQueue.waitFor(std::chrono::milliseconds(10)) && ! shouldStop.load()) ;
|
||||
if(shouldStop.load()) {
|
||||
break;
|
||||
}
|
||||
|
||||
eventQueue.process();
|
||||
eventQueue.process();
|
||||
}
|
||||
```
|
||||
|
||||
@ -206,8 +206,8 @@ Retrieve an event from the queue. The event is returned in `queuedEvent`.
|
||||
```c++
|
||||
struct EventQueue::QueuedEvent
|
||||
{
|
||||
TheEventType event;
|
||||
std::tuple<ArgumentTypes...> arguments;
|
||||
TheEventType event;
|
||||
std::tuple<ArgumentTypes...> arguments;
|
||||
};
|
||||
```
|
||||
`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 ()>;
|
||||
EQ queue;
|
||||
{
|
||||
EQ::DisableQueueNotify disableNotify(&queue);
|
||||
// any blocking threads will not be waken up by the below two lines.
|
||||
queue.enqueue(1);
|
||||
queue.enqueue(2);
|
||||
EQ::DisableQueueNotify disableNotify(&queue);
|
||||
// any blocking threads will not be waken up by the below two lines.
|
||||
queue.enqueue(1);
|
||||
queue.enqueue(2);
|
||||
}
|
||||
// any blocking threads are waken up here immediately.
|
||||
|
||||
|
@ -9,9 +9,9 @@ eventpp/utilities/eventutil.h
|
||||
```c++
|
||||
template <typename DispatcherType>
|
||||
bool removeListener(
|
||||
DispatcherType & dispatcher,
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener
|
||||
DispatcherType & dispatcher,
|
||||
const typename DispatcherType::Event & event,
|
||||
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.
|
||||
@ -21,8 +21,8 @@ This function requires the listener be able to be compared with equal operator (
|
||||
```c++
|
||||
template <typename CallbackListType>
|
||||
bool removeListener(
|
||||
CallbackListType & callbackList,
|
||||
const typename CallbackListType::Callback & callback
|
||||
CallbackListType & callbackList,
|
||||
const typename CallbackListType::Callback & callback
|
||||
);
|
||||
```
|
||||
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++
|
||||
template <typename DispatcherType>
|
||||
bool hasListener(
|
||||
DispatcherType & dispatcher,
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener
|
||||
DispatcherType & dispatcher,
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener
|
||||
);
|
||||
```
|
||||
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++
|
||||
template <typename DispatcherType>
|
||||
bool hasAnyListener(
|
||||
DispatcherType & dispatcher,
|
||||
const typename DispatcherType::Event & event
|
||||
DispatcherType & dispatcher,
|
||||
const typename DispatcherType::Event & event
|
||||
);
|
||||
```
|
||||
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++
|
||||
template <typename CallbackListType>
|
||||
bool hasListener(
|
||||
CallbackListType & callbackList,
|
||||
const typename CallbackListType::Callback & callback
|
||||
CallbackListType & callbackList,
|
||||
const typename CallbackListType::Callback & callback
|
||||
);
|
||||
```
|
||||
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++
|
||||
template <typename CallbackListType>
|
||||
bool hasAnyListener(
|
||||
CallbackListType & callbackList
|
||||
CallbackListType & callbackList
|
||||
);
|
||||
```
|
||||
The function finds any callback in `callbackList`, returns true if it finds any one, otherwise returns false.
|
||||
|
52
doc/faq.md
52
doc/faq.md
@ -58,7 +58,7 @@ For example,
|
||||
class MyEventDispatcher : public EventDispatcher<blah blah>
|
||||
{
|
||||
public:
|
||||
virtual ~MyEventDispatcher();
|
||||
virtual ~MyEventDispatcher();
|
||||
};
|
||||
|
||||
class MyClass : public MyEventDispatcher
|
||||
@ -86,22 +86,22 @@ eventpp::CallbackList<void ()> mainLoopTasks;
|
||||
|
||||
void mainLoop()
|
||||
{
|
||||
for(;;) {
|
||||
// Do any stuff in the loop
|
||||
|
||||
mainLoopTasks();
|
||||
}
|
||||
for(;;) {
|
||||
// Do any stuff in the loop
|
||||
|
||||
mainLoopTasks();
|
||||
}
|
||||
}
|
||||
|
||||
class MyEventQueue : public eventpp::EventQueue<blah blah>
|
||||
{
|
||||
public:
|
||||
MyEventQueue()
|
||||
{
|
||||
mainLoopTasks.append([this]() {
|
||||
process();
|
||||
});
|
||||
}
|
||||
MyEventQueue()
|
||||
{
|
||||
mainLoopTasks.append([this]() {
|
||||
process();
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
@ -118,25 +118,25 @@ eventpp::CallbackList<void ()> mainLoopTasks;
|
||||
|
||||
void threadMain()
|
||||
{
|
||||
while(! stopped) {
|
||||
ioService.poll();
|
||||
mainLoopTasks();
|
||||
sleepSomeTime();
|
||||
}
|
||||
|
||||
ioService.run();
|
||||
mainLoopTasks();
|
||||
while(! stopped) {
|
||||
ioService.poll();
|
||||
mainLoopTasks();
|
||||
sleepSomeTime();
|
||||
}
|
||||
|
||||
ioService.run();
|
||||
mainLoopTasks();
|
||||
}
|
||||
|
||||
class MyEventQueue : public eventpp::EventQueue<blah blah>
|
||||
{
|
||||
public:
|
||||
MyEventQueue()
|
||||
{
|
||||
mainLoopTasks.append([this]() {
|
||||
process();
|
||||
});
|
||||
}
|
||||
MyEventQueue()
|
||||
{
|
||||
mainLoopTasks.append([this]() {
|
||||
process();
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -32,8 +32,8 @@ eventpp/hetercallbacklist.h
|
||||
|
||||
```c++
|
||||
template <
|
||||
typename PrototypeList,
|
||||
typename Policies = DefaultPolicies
|
||||
typename PrototypeList,
|
||||
typename Policies = DefaultPolicies
|
||||
>
|
||||
class HeterCallbackList;
|
||||
```
|
||||
|
@ -31,9 +31,9 @@ eventpp/hetereventdispatcher.h
|
||||
|
||||
```c++
|
||||
template <
|
||||
typename Event,
|
||||
typename PrototypeList,
|
||||
typename Policies = DefaultPolicies
|
||||
typename Event,
|
||||
typename PrototypeList,
|
||||
typename Policies = DefaultPolicies
|
||||
>
|
||||
class HeterEventDispatcher;
|
||||
```
|
||||
|
@ -31,9 +31,9 @@ eventpp/eventqueue.h
|
||||
|
||||
```c++
|
||||
template <
|
||||
typename Event,
|
||||
typename PrototypeList,
|
||||
typename Policies = DefaultPolicies
|
||||
typename Event,
|
||||
typename PrototypeList,
|
||||
typename Policies = DefaultPolicies
|
||||
>
|
||||
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,
|
||||
```c++
|
||||
for(;;) {
|
||||
eventQueue.wait();
|
||||
eventQueue.process();
|
||||
eventQueue.wait();
|
||||
eventQueue.process();
|
||||
}
|
||||
```
|
||||
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++
|
||||
std::atomic<bool> shouldStop(false);
|
||||
for(;;) {
|
||||
while(! eventQueue.waitFor(std::chrono::milliseconds(10)) && ! shouldStop.load()) ;
|
||||
if(shouldStop.load()) {
|
||||
break;
|
||||
}
|
||||
while(! eventQueue.waitFor(std::chrono::milliseconds(10)) && ! shouldStop.load()) ;
|
||||
if(shouldStop.load()) {
|
||||
break;
|
||||
}
|
||||
|
||||
eventQueue.process();
|
||||
eventQueue.process();
|
||||
}
|
||||
```
|
||||
|
||||
@ -177,10 +177,10 @@ Sample code
|
||||
using EQ = eventpp::HeterEventQueue<int, void ()>;
|
||||
EQ queue;
|
||||
{
|
||||
EQ::DisableQueueNotify disableNotify(&queue);
|
||||
// any blocking threads will not be waken up by the below two lines.
|
||||
queue.enqueue(1);
|
||||
queue.enqueue(2);
|
||||
EQ::DisableQueueNotify disableNotify(&queue);
|
||||
// any blocking threads will not be waken up by the below two lines.
|
||||
queue.enqueue(1);
|
||||
queue.enqueue(2);
|
||||
}
|
||||
// any blocking threads are waken up here immediately.
|
||||
|
||||
|
@ -30,22 +30,22 @@ eventpp/hetereventqueue.h
|
||||
|
||||
```c++
|
||||
template <
|
||||
typename PrototypeList,
|
||||
typename Policies = DefaultPolicies
|
||||
typename PrototypeList,
|
||||
typename Policies = DefaultPolicies
|
||||
>
|
||||
class HeterCallbackList;
|
||||
|
||||
template <
|
||||
typename Event,
|
||||
typename PrototypeList,
|
||||
typename Policies = DefaultPolicies
|
||||
typename Event,
|
||||
typename PrototypeList,
|
||||
typename Policies = DefaultPolicies
|
||||
>
|
||||
class HeterEventDispatcher;
|
||||
|
||||
template <
|
||||
typename Event,
|
||||
typename PrototypeList,
|
||||
typename Policies = DefaultPolicies
|
||||
typename Event,
|
||||
typename PrototypeList,
|
||||
typename Policies = DefaultPolicies
|
||||
>
|
||||
class HeterEventQueue;
|
||||
```
|
||||
@ -54,22 +54,22 @@ For comparison, below are the template parameters for the homogeneous counterpar
|
||||
|
||||
```c++
|
||||
template <
|
||||
typename Prototype,
|
||||
typename Policies = DefaultPolicies
|
||||
typename Prototype,
|
||||
typename Policies = DefaultPolicies
|
||||
>
|
||||
class CallbackList;
|
||||
|
||||
template <
|
||||
typename Event,
|
||||
typename Prototype,
|
||||
typename Policies = DefaultPolicies
|
||||
typename Event,
|
||||
typename Prototype,
|
||||
typename Policies = DefaultPolicies
|
||||
>
|
||||
class EventDispatcher;
|
||||
|
||||
template <
|
||||
typename Event,
|
||||
typename Prototype,
|
||||
typename Policies = DefaultPolicies
|
||||
typename Event,
|
||||
typename Prototype,
|
||||
typename Policies = DefaultPolicies
|
||||
>
|
||||
class EventQueue;
|
||||
```
|
||||
|
@ -28,22 +28,22 @@ EventDispatcher is ideal when there are many kinds of events, or the number of e
|
||||
```c++
|
||||
enum class MyEventType
|
||||
{
|
||||
redraw,
|
||||
mouseDown,
|
||||
mouseUp,
|
||||
//... maybe 200 other events here
|
||||
redraw,
|
||||
mouseDown,
|
||||
mouseUp,
|
||||
//... maybe 200 other events here
|
||||
};
|
||||
|
||||
struct MyEvent {
|
||||
MyEventType type;
|
||||
// data that all events may need
|
||||
MyEventType type;
|
||||
// data that all events may need
|
||||
};
|
||||
|
||||
struct MyEventPolicies
|
||||
{
|
||||
static MyEventType getEvent(const MyEvent & e) {
|
||||
return e.type;
|
||||
}
|
||||
static MyEventType getEvent(const MyEvent & e) {
|
||||
return e.type;
|
||||
}
|
||||
};
|
||||
|
||||
eventpp::EventDispatcher<MyEventType, void(const MyEvent &), MyEventPolicies> dispatcher;
|
||||
|
@ -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,
|
||||
```c++
|
||||
struct MyPolicies {
|
||||
using Mixins = eventpp::MixinList<eventpp::MixinFilter>;
|
||||
using Mixins = eventpp::MixinList<eventpp::MixinFilter>;
|
||||
};
|
||||
eventpp::EventDispatcher<int, void (), MyPolicies> dispatcher;
|
||||
```
|
||||
@ -121,19 +121,19 @@ Return true if the filter is removed successfully.
|
||||
**Code**
|
||||
```c++
|
||||
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;
|
||||
|
||||
dispatcher.appendListener(3, [](const int e, const int i, const std::string & s) {
|
||||
std::cout
|
||||
<< "Got event 3, i was 1 but actural is " << i
|
||||
<< " s was Hello but actural is " << s
|
||||
<< std::endl
|
||||
;
|
||||
std::cout
|
||||
<< "Got event 3, i was 1 but actural is " << i
|
||||
<< " s was Hello but actural is " << s
|
||||
<< std::endl
|
||||
;
|
||||
});
|
||||
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.
|
||||
@ -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
|
||||
// and listeners will see the modified values.
|
||||
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;
|
||||
i = 38;
|
||||
s = "Hi";
|
||||
std::cout << "Filter 1, changed i is " << i << " s is " << s << std::endl;
|
||||
return true;
|
||||
std::cout << "Filter 1, e is " << e << " passed in i is " << i << " s is " << s << std::endl;
|
||||
i = 38;
|
||||
s = "Hi";
|
||||
std::cout << "Filter 1, changed i is " << i << " s is " << s << std::endl;
|
||||
return true;
|
||||
});
|
||||
|
||||
// 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.
|
||||
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;
|
||||
if(e == 5) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
std::cout << "Filter 2, e is " << e << " passed in i is " << i << " s is " << s << std::endl;
|
||||
if(e == 5) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// The third filter just prints the input arguments.
|
||||
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;
|
||||
return true;
|
||||
std::cout << "Filter 3, e is " << e << " passed in i is " << i << " s is " << s << std::endl;
|
||||
return true;
|
||||
});
|
||||
|
||||
// Dispatch the events, the first argument is always the event type.
|
||||
|
@ -43,10 +43,10 @@ Its default implementation `OrderedQueueListCompare` looks like,
|
||||
```c++
|
||||
struct OrderedQueueListCompare
|
||||
{
|
||||
template <typename T>
|
||||
bool operator() (const T & a, const T & b) const {
|
||||
return a.event < b.event;
|
||||
}
|
||||
template <typename T>
|
||||
bool operator() (const T & a, const T & b) const {
|
||||
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.
|
||||
@ -56,8 +56,8 @@ The typename T is actually the `EventQueue::QueuedEvent`. But since `OrderedQueu
|
||||
```c++
|
||||
struct QueuedEvent
|
||||
{
|
||||
EventType event;
|
||||
std::tuple<Args> arguments;
|
||||
EventType event;
|
||||
std::tuple<Args> arguments;
|
||||
};
|
||||
```
|
||||
`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.
|
||||
struct MyEvent
|
||||
{
|
||||
int e;
|
||||
int priority;
|
||||
int e;
|
||||
int priority;
|
||||
};
|
||||
|
||||
// The comparison function object used by eventpp::OrderedQueueList.
|
||||
// The function compares the event by priority.
|
||||
struct MyCompare
|
||||
{
|
||||
template <typename T>
|
||||
bool operator() (const T & a, const T & b) const {
|
||||
return std::get<0>(a.arguments).priority > std::get<0>(b.arguments).priority;
|
||||
}
|
||||
template <typename T>
|
||||
bool operator() (const T & a, const T & b) const {
|
||||
return std::get<0>(a.arguments).priority > std::get<0>(b.arguments).priority;
|
||||
}
|
||||
};
|
||||
|
||||
// Define the EventQueue policy
|
||||
struct MyPolicy
|
||||
{
|
||||
template <typename Item>
|
||||
using QueueList = eventpp::OrderedQueueList<Item, MyCompare >;
|
||||
template <typename Item>
|
||||
using QueueList = eventpp::OrderedQueueList<Item, MyCompare >;
|
||||
|
||||
static int getEvent(const MyEvent & event) {
|
||||
return event.e;
|
||||
}
|
||||
static int getEvent(const MyEvent & event) {
|
||||
return event.e;
|
||||
}
|
||||
};
|
||||
|
||||
void main()
|
||||
{
|
||||
using EQ = eventpp::EventQueue<int, void(const MyEvent &), MyPolicy>;
|
||||
EQ queue;
|
||||
using EQ = eventpp::EventQueue<int, void(const MyEvent &), MyPolicy>;
|
||||
EQ queue;
|
||||
|
||||
queue.appendListener(3, [](const MyEvent & event) {
|
||||
std::cout << "Get event " << event.e << "(should be 3)." << " priority: " << event.priority << std::endl;
|
||||
});
|
||||
queue.appendListener(5, [](const MyEvent & event) {
|
||||
std::cout << "Get event " << event.e << "(should be 5)." << " priority: " << event.priority << std::endl;
|
||||
});
|
||||
queue.appendListener(7, [](const MyEvent & event) {
|
||||
std::cout << "Get event " << event.e << "(should be 7)." << " priority: " << event.priority << std::endl;
|
||||
});
|
||||
queue.appendListener(3, [](const MyEvent & event) {
|
||||
std::cout << "Get event " << event.e << "(should be 3)." << " priority: " << event.priority << std::endl;
|
||||
});
|
||||
queue.appendListener(5, [](const MyEvent & event) {
|
||||
std::cout << "Get event " << event.e << "(should be 5)." << " priority: " << event.priority << std::endl;
|
||||
});
|
||||
queue.appendListener(7, [](const MyEvent & event) {
|
||||
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.
|
||||
// After the queue processes, the events will be processed from higher priority to lower priority.
|
||||
queue.enqueue(MyEvent{ 5, 100 });
|
||||
queue.enqueue(MyEvent{ 5, 200 });
|
||||
queue.enqueue(MyEvent{ 7, 300 });
|
||||
queue.enqueue(MyEvent{ 7, 400 });
|
||||
queue.enqueue(MyEvent{ 3, 500 });
|
||||
queue.enqueue(MyEvent{ 3, 600 });
|
||||
// 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.
|
||||
queue.enqueue(MyEvent{ 5, 100 });
|
||||
queue.enqueue(MyEvent{ 5, 200 });
|
||||
queue.enqueue(MyEvent{ 7, 300 });
|
||||
queue.enqueue(MyEvent{ 7, 400 });
|
||||
queue.enqueue(MyEvent{ 3, 500 });
|
||||
queue.enqueue(MyEvent{ 3, 600 });
|
||||
|
||||
queue.process();
|
||||
queue.process();
|
||||
}
|
||||
|
||||
```
|
||||
|
132
doc/policies.md
132
doc/policies.md
@ -42,39 +42,39 @@ Sample code
|
||||
```c++
|
||||
// Define an Event to hold all parameters.
|
||||
struct MyEvent {
|
||||
int type;
|
||||
std::string message;
|
||||
int param;
|
||||
int type;
|
||||
std::string message;
|
||||
int param;
|
||||
};
|
||||
|
||||
// Define policies to let the dispatcher knows how to
|
||||
// extract the event type.
|
||||
struct MyEventPolicies
|
||||
{
|
||||
static int getEvent(const MyEvent & e, bool /*b*/) {
|
||||
return e.type;
|
||||
}
|
||||
static int getEvent(const MyEvent & e, bool /*b*/) {
|
||||
return e.type;
|
||||
}
|
||||
};
|
||||
|
||||
// Pass MyEventPolicies as the third template argument of EventDispatcher.
|
||||
// Note: the first template argument is the event type type int, not MyEvent.
|
||||
eventpp::EventDispatcher<
|
||||
int,
|
||||
void (const MyEvent &, bool),
|
||||
MyEventPolicies
|
||||
int,
|
||||
void (const MyEvent &, bool),
|
||||
MyEventPolicies
|
||||
> dispatcher;
|
||||
|
||||
// Add a listener.
|
||||
// Note: the first argument is the event type of type int, not MyEvent.
|
||||
dispatcher.appendListener(3, [](const MyEvent & e, bool b) {
|
||||
std::cout
|
||||
<< std::boolalpha
|
||||
<< "Got event 3" << std::endl
|
||||
<< "Event::type is " << e.type << std::endl
|
||||
<< "Event::message is " << e.message << std::endl
|
||||
<< "Event::param is " << e.param << std::endl
|
||||
<< "b is " << b << std::endl
|
||||
;
|
||||
std::cout
|
||||
<< std::boolalpha
|
||||
<< "Got event 3" << std::endl
|
||||
<< "Event::type is " << e.type << std::endl
|
||||
<< "Event::message is " << e.message << std::endl
|
||||
<< "Event::param is " << e.param << std::endl
|
||||
<< "b is " << b << std::endl
|
||||
;
|
||||
});
|
||||
|
||||
// Dispatch the event.
|
||||
@ -93,35 +93,35 @@ Sample code
|
||||
|
||||
```c++
|
||||
struct MyEvent {
|
||||
MyEvent() : type(0), canceled(false) {
|
||||
}
|
||||
explicit MyEvent(const int type)
|
||||
: type(type), canceled(false) {
|
||||
}
|
||||
MyEvent() : type(0), canceled(false) {
|
||||
}
|
||||
explicit MyEvent(const int type)
|
||||
: type(type), canceled(false) {
|
||||
}
|
||||
|
||||
int type;
|
||||
mutable bool canceled;
|
||||
int type;
|
||||
mutable bool canceled;
|
||||
};
|
||||
|
||||
struct MyEventPolicies
|
||||
{
|
||||
static int getEvent(const MyEvent & e) {
|
||||
return e.type;
|
||||
}
|
||||
static int getEvent(const MyEvent & e) {
|
||||
return e.type;
|
||||
}
|
||||
|
||||
static bool canContinueInvoking(const MyEvent & e) {
|
||||
return ! e.canceled;
|
||||
}
|
||||
static bool canContinueInvoking(const MyEvent & e) {
|
||||
return ! e.canceled;
|
||||
}
|
||||
};
|
||||
|
||||
eventpp::EventDispatcher<int, void (const MyEvent &), MyEventPolicies> dispatcher;
|
||||
|
||||
dispatcher.appendListener(3, [](const MyEvent & e) {
|
||||
std::cout << "Got event 3" << std::endl;
|
||||
e.canceled = true;
|
||||
std::cout << "Got event 3" << std::endl;
|
||||
e.canceled = true;
|
||||
});
|
||||
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));
|
||||
@ -158,12 +158,12 @@ A typical `Threading` type looks like
|
||||
```c++
|
||||
struct MultipleThreading
|
||||
{
|
||||
using Mutex = std::mutex;
|
||||
using Mutex = std::mutex;
|
||||
|
||||
template <typename T>
|
||||
using Atomic = std::atomic<T>;
|
||||
template <typename 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.
|
||||
@ -177,15 +177,15 @@ Below is the sample code for how to use `SpinLock`
|
||||
```c++
|
||||
struct MultipleThreadingSpinLock
|
||||
{
|
||||
using Mutex = eventpp::SpinLock;
|
||||
using Mutex = eventpp::SpinLock;
|
||||
|
||||
template <typename T>
|
||||
using Atomic = std::atomic<T>;
|
||||
template <typename T>
|
||||
using Atomic = std::atomic<T>;
|
||||
|
||||
using ConditionVariable = std::condition_variable;
|
||||
using ConditionVariable = std::condition_variable;
|
||||
};
|
||||
struct MyEventPolicies {
|
||||
using Threading = MultipleThreadingSpinLock;
|
||||
using Threading = MultipleThreadingSpinLock;
|
||||
};
|
||||
eventpp::EventDispatcher<int, void (), MyEventPolicies> dispatcher;
|
||||
eventpp::CallbackList<void (), MyEventPolicies> callbackList;
|
||||
@ -194,18 +194,18 @@ eventpp::CallbackList<void (), MyEventPolicies> callbackList;
|
||||
`eventpp` provides a shortcut template class to customize the threading.
|
||||
```c++
|
||||
template <
|
||||
typename Mutex_,
|
||||
template <typename > class Atomic_ = std::atomic,
|
||||
typename ConditionVariable_ = std::condition_variable
|
||||
typename Mutex_,
|
||||
template <typename > class Atomic_ = std::atomic,
|
||||
typename ConditionVariable_ = std::condition_variable
|
||||
>
|
||||
struct GeneralThreading
|
||||
{
|
||||
using Mutex = Mutex_;
|
||||
using Mutex = Mutex_;
|
||||
|
||||
template <typename T>
|
||||
using Atomic = Atomic_<T>;
|
||||
template <typename 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++
|
||||
struct MyEventPolicies {
|
||||
using Threading = eventpp::GeneralThreading<eventpp::SpinLock>;
|
||||
using Threading = eventpp::GeneralThreading<eventpp::SpinLock>;
|
||||
};
|
||||
eventpp::EventDispatcher<int, void (), MyEventPolicies> dispatcher;
|
||||
eventpp::CallbackList<void (), MyEventPolicies> callbackList;
|
||||
@ -270,12 +270,12 @@ Examples to demonstrate argument passing mode
|
||||
```c++
|
||||
struct MyPolicies
|
||||
{
|
||||
using ArgumentPassingMode = ArgumentPassingAutoDetect;
|
||||
using ArgumentPassingMode = ArgumentPassingAutoDetect;
|
||||
};
|
||||
eventpp::EventDispatcher<
|
||||
int,
|
||||
void(int, const std::string &),
|
||||
MyPolicies
|
||||
int,
|
||||
void(int, const std::string &),
|
||||
MyPolicies
|
||||
> dispatcher;
|
||||
// or just
|
||||
//eventpp::EventDispatcher<int, void(int, const std::string &)> dispatcher;
|
||||
@ -286,12 +286,12 @@ dispatcher.dispatch(3, 8, "hello"); // Compile OK
|
||||
```c++
|
||||
struct MyPolicies
|
||||
{
|
||||
using ArgumentPassingMode = ArgumentPassingIncludeEvent;
|
||||
using ArgumentPassingMode = ArgumentPassingIncludeEvent;
|
||||
};
|
||||
eventpp::EventDispatcher<
|
||||
int,
|
||||
void(int, const std::string &),
|
||||
MyPolicies
|
||||
int,
|
||||
void(int, const std::string &),
|
||||
MyPolicies
|
||||
> dispatcher;
|
||||
dispatcher.dispatch(3, "hello"); // Compile OK
|
||||
//dispatcher.dispatch(3, 8, "hello"); // Compile failure
|
||||
@ -300,12 +300,12 @@ dispatcher.dispatch(3, "hello"); // Compile OK
|
||||
```c++
|
||||
struct MyPolicies
|
||||
{
|
||||
using ArgumentPassingMode = ArgumentPassingExcludeEvent;
|
||||
using ArgumentPassingMode = ArgumentPassingExcludeEvent;
|
||||
};
|
||||
eventpp::EventDispatcher<
|
||||
int,
|
||||
void(int, const std::string &),
|
||||
MyPolicies
|
||||
int,
|
||||
void(int, const std::string &),
|
||||
MyPolicies
|
||||
> dispatcher;
|
||||
//dispatcher.dispatch(3, "hello"); // Compile failure
|
||||
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++
|
||||
struct MyPolicies //the struct name doesn't matter
|
||||
{
|
||||
template <typename ...Args>
|
||||
static int getEvent(const MyEvent & e, const Args &...) {
|
||||
return e.type;
|
||||
}
|
||||
template <typename ...Args>
|
||||
static int getEvent(const MyEvent & e, const Args &...) {
|
||||
return e.type;
|
||||
}
|
||||
};
|
||||
EventDispatcher<int, void(const MyEvent &), MyPolicies> dispatcher;
|
||||
```
|
||||
|
@ -58,24 +58,24 @@ void reset();
|
||||
void setDispatcher(DispatcherType & dispatcher);
|
||||
|
||||
typename DispatcherType::Handle appendListener(
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener
|
||||
);
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener
|
||||
);
|
||||
|
||||
typename DispatcherType::Handle prependListener(
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener
|
||||
);
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener
|
||||
);
|
||||
|
||||
typename DispatcherType::Handle insertListener(
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const typename DispatcherType::Handle & before
|
||||
);
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Callback & listener,
|
||||
const typename DispatcherType::Handle & before
|
||||
);
|
||||
bool removeListener(
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Handle handle
|
||||
);
|
||||
const typename DispatcherType::Event & event,
|
||||
const typename DispatcherType::Handle handle
|
||||
);
|
||||
```
|
||||
|
||||
**Member functions for CallbackList**
|
||||
@ -85,17 +85,17 @@ void reset();
|
||||
void setCallbackList(CallbackListType & callbackList);
|
||||
|
||||
typename CallbackListType::Handle append(
|
||||
const typename CallbackListType::Callback & callback
|
||||
);
|
||||
const typename CallbackListType::Callback & callback
|
||||
);
|
||||
|
||||
typename CallbackListType::Handle prepend(
|
||||
const typename CallbackListType::Callback & callback
|
||||
);
|
||||
const typename CallbackListType::Callback & callback
|
||||
);
|
||||
|
||||
typename CallbackListType::Handle insert(
|
||||
const typename CallbackListType::Callback & callback,
|
||||
const typename CallbackListType::Handle & before
|
||||
);
|
||||
const typename CallbackListType::Callback & callback,
|
||||
const typename CallbackListType::Handle & before
|
||||
);
|
||||
bool remove(const typename CallbackListType::Handle handle);
|
||||
```
|
||||
|
||||
@ -119,39 +119,39 @@ using Remover = eventpp::ScopedRemover<eventpp::EventDispatcher<int, void ()> >;
|
||||
constexpr int event = 3;
|
||||
|
||||
dispatcher.appendListener(event, [&dataList]() {
|
||||
// listener A
|
||||
// listener A
|
||||
});
|
||||
|
||||
{
|
||||
Remover r1(dispatcher);
|
||||
r1.prependListener(event, [&dataList]() {
|
||||
// listener B
|
||||
});
|
||||
{
|
||||
Remover r2(dispatcher);
|
||||
auto handle = r2.appendListener(event, [&dataList]() {
|
||||
// listener C
|
||||
});
|
||||
{
|
||||
Remover r3(dispatcher);
|
||||
r3.insertListener(event, [&dataList]() {
|
||||
// listener D
|
||||
}, handle);
|
||||
Remover r1(dispatcher);
|
||||
r1.prependListener(event, [&dataList]() {
|
||||
// listener B
|
||||
});
|
||||
{
|
||||
Remover r2(dispatcher);
|
||||
auto handle = r2.appendListener(event, [&dataList]() {
|
||||
// listener C
|
||||
});
|
||||
{
|
||||
Remover r3(dispatcher);
|
||||
r3.insertListener(event, [&dataList]() {
|
||||
// listener D
|
||||
}, handle);
|
||||
|
||||
dispatcher.dispatch(event);
|
||||
// All listeners were triggered.
|
||||
}
|
||||
|
||||
// listener D was removed
|
||||
dispatcher.dispatch(event);
|
||||
// All listeners were triggered.
|
||||
}
|
||||
|
||||
// listener D was removed
|
||||
|
||||
dispatcher.dispatch(event);
|
||||
// Listeners A, B, C were triggered.
|
||||
}
|
||||
dispatcher.dispatch(event);
|
||||
// Listeners A, B, C were triggered.
|
||||
}
|
||||
|
||||
// listener C was removed
|
||||
// listener C was removed
|
||||
|
||||
dispatcher.dispatch(event);
|
||||
// Listeners A, B were triggered.
|
||||
dispatcher.dispatch(event);
|
||||
// Listeners A, B were triggered.
|
||||
}
|
||||
|
||||
// listener B was removed
|
||||
@ -173,12 +173,12 @@ SomeDispatcher someDispatcher;
|
||||
|
||||
class MyClass
|
||||
{
|
||||
MyClass()
|
||||
{
|
||||
someDispatcher.appendListener(SomeEvent, callback of myListener);
|
||||
}
|
||||
|
||||
void myListener() {}
|
||||
MyClass()
|
||||
{
|
||||
someDispatcher.appendListener(SomeEvent, callback of myListener);
|
||||
}
|
||||
|
||||
void myListener() {}
|
||||
};
|
||||
```
|
||||
|
||||
@ -191,14 +191,14 @@ SomeDispatcher someDispatcher;
|
||||
|
||||
class MyClass
|
||||
{
|
||||
MyClass() : scopedRemover(someDispatcher)
|
||||
{
|
||||
scopedRemover.appendListener(SomeEvent, callback of myListener);
|
||||
}
|
||||
|
||||
void myListener() {}
|
||||
MyClass() : scopedRemover(someDispatcher)
|
||||
{
|
||||
scopedRemover.appendListener(SomeEvent, callback of myListener);
|
||||
}
|
||||
|
||||
void myListener() {}
|
||||
|
||||
eventpp::ScopedRemover<SomeDispatcher> scopedRemover;
|
||||
eventpp::ScopedRemover<SomeDispatcher> scopedRemover;
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -19,10 +19,10 @@ eventpp::CallbackList<void ()> callbackList;
|
||||
// Lambda is not required, any function or std::function
|
||||
// or whatever function object with the required prototype is fine.
|
||||
callbackList.append([]() {
|
||||
std::cout << "Got callback 1." << std::endl;
|
||||
std::cout << "Got callback 1." << std::endl;
|
||||
});
|
||||
callbackList.append([]() {
|
||||
std::cout << "Got callback 2." << std::endl;
|
||||
std::cout << "Got callback 2." << std::endl;
|
||||
});
|
||||
|
||||
// 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.
|
||||
```c++
|
||||
callbackList.append([]() {
|
||||
std::cout << "Got callback 1." << std::endl;
|
||||
std::cout << "Got callback 1." << std::endl;
|
||||
});
|
||||
```
|
||||
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;
|
||||
|
||||
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.
|
||||
// It would be fine as long as the arguments are compatible with the callbacklist.
|
||||
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
|
||||
@ -96,13 +96,13 @@ CL::Handle handle2;
|
||||
|
||||
// Add some callbacks.
|
||||
callbackList.append([]() {
|
||||
std::cout << "Got callback 1." << std::endl;
|
||||
std::cout << "Got callback 1." << std::endl;
|
||||
});
|
||||
handle2 = callbackList.append([]() {
|
||||
std::cout << "Got callback 2." << std::endl;
|
||||
std::cout << "Got callback 2." << std::endl;
|
||||
});
|
||||
callbackList.append([]() {
|
||||
std::cout << "Got callback 3." << std::endl;
|
||||
std::cout << "Got callback 3." << std::endl;
|
||||
});
|
||||
|
||||
callbackList.remove(handle2);
|
||||
@ -127,30 +127,30 @@ CL callbackList;
|
||||
|
||||
// Add some callbacks.
|
||||
callbackList.append([]() {
|
||||
std::cout << "Got callback 1." << std::endl;
|
||||
std::cout << "Got callback 1." << std::endl;
|
||||
});
|
||||
callbackList.append([]() {
|
||||
std::cout << "Got callback 2." << std::endl;
|
||||
std::cout << "Got callback 2." << std::endl;
|
||||
});
|
||||
callbackList.append([]() {
|
||||
std::cout << "Got callback 3." << std::endl;
|
||||
std::cout << "Got callback 3." << std::endl;
|
||||
});
|
||||
|
||||
// Now call forEach to remove the second callback
|
||||
// The forEach callback prototype is void(const CallbackList::Handle & handle, const CallbackList::Callback & callback)
|
||||
int index = 0;
|
||||
callbackList.forEach([&callbackList, &index](const CL::Handle & handle, const CL::Callback & callback) {
|
||||
std::cout << "forEach(Handle, Callback), invoked " << index << std::endl;
|
||||
if(index == 1) {
|
||||
callbackList.remove(handle);
|
||||
std::cout << "forEach(Handle, Callback), removed second callback" << std::endl;
|
||||
}
|
||||
++index;
|
||||
std::cout << "forEach(Handle, Callback), invoked " << index << std::endl;
|
||||
if(index == 1) {
|
||||
callbackList.remove(handle);
|
||||
std::cout << "forEach(Handle, Callback), removed second callback" << std::endl;
|
||||
}
|
||||
++index;
|
||||
});
|
||||
|
||||
// The forEach callback prototype can also be void(const CallbackList::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
|
||||
|
@ -22,13 +22,13 @@ eventpp::EventDispatcher<int, void ()> dispatcher;
|
||||
// Lambda is not required, any function or std::function
|
||||
// or whatever function object with the required prototype is fine.
|
||||
dispatcher.appendListener(3, []() {
|
||||
std::cout << "Got event 3." << std::endl;
|
||||
std::cout << "Got event 3." << std::endl;
|
||||
});
|
||||
dispatcher.appendListener(5, []() {
|
||||
std::cout << "Got event 5." << std::endl;
|
||||
std::cout << "Got event 5." << std::endl;
|
||||
});
|
||||
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.
|
||||
@ -53,7 +53,7 @@ The *prototype* is C++ function type, such as `void (int)`, `void (const std::st
|
||||
Now let's add a listener.
|
||||
```c++
|
||||
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*.
|
||||
@ -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;
|
||||
|
||||
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.
|
||||
// It would be find as long as the arguments is compatible with the dispatcher.
|
||||
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) {
|
||||
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.
|
||||
@ -107,39 +107,39 @@ The listener's prototype is not required to be same as the dispatcher, it's fine
|
||||
```c++
|
||||
// Define an Event to hold all parameters.
|
||||
struct MyEvent {
|
||||
int type;
|
||||
std::string message;
|
||||
int param;
|
||||
int type;
|
||||
std::string message;
|
||||
int param;
|
||||
};
|
||||
|
||||
// Define policies to let the dispatcher knows how to
|
||||
// extract the event type.
|
||||
struct MyEventPolicies
|
||||
{
|
||||
static int getEvent(const MyEvent & e, bool /*b*/) {
|
||||
return e.type;
|
||||
}
|
||||
static int getEvent(const MyEvent & e, bool /*b*/) {
|
||||
return e.type;
|
||||
}
|
||||
};
|
||||
|
||||
// Pass MyEventPolicies as the third template argument of EventDispatcher.
|
||||
// Note: the first template argument is the event type type int, not MyEvent.
|
||||
eventpp::EventDispatcher<
|
||||
int,
|
||||
void (const MyEvent &, bool),
|
||||
MyEventPolicies
|
||||
int,
|
||||
void (const MyEvent &, bool),
|
||||
MyEventPolicies
|
||||
> dispatcher;
|
||||
|
||||
// Add a listener.
|
||||
// Note: the first argument is the event type of type int, not MyEvent.
|
||||
dispatcher.appendListener(3, [](const MyEvent & e, bool b) {
|
||||
std::cout
|
||||
<< std::boolalpha
|
||||
<< "Got event 3" << std::endl
|
||||
<< "Event::type is " << e.type << std::endl
|
||||
<< "Event::message is " << e.message << std::endl
|
||||
<< "Event::param is " << e.param << std::endl
|
||||
<< "b is " << b << std::endl
|
||||
;
|
||||
std::cout
|
||||
<< std::boolalpha
|
||||
<< "Got event 3" << std::endl
|
||||
<< "Event::type is " << e.type << std::endl
|
||||
<< "Event::message is " << e.message << std::endl
|
||||
<< "Event::param is " << e.param << std::endl
|
||||
<< "b is " << b << std::endl
|
||||
;
|
||||
});
|
||||
|
||||
// Dispatch the event.
|
||||
|
@ -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;
|
||||
|
||||
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.
|
||||
// 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) {
|
||||
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) {
|
||||
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.
|
||||
@ -59,19 +59,19 @@ constexpr int otherEvent = 2;
|
||||
// Start a thread to process the event queue.
|
||||
// All listeners are invoked in that thread.
|
||||
std::thread thread([stopEvent, otherEvent, &queue]() {
|
||||
volatile bool shouldStop = false;
|
||||
queue.appendListener(stopEvent, [&shouldStop](int) {
|
||||
shouldStop = true;
|
||||
});
|
||||
queue.appendListener(otherEvent, [](const int index) {
|
||||
std::cout << "Got event, index is " << index << std::endl;
|
||||
});
|
||||
volatile bool shouldStop = false;
|
||||
queue.appendListener(stopEvent, [&shouldStop](int) {
|
||||
shouldStop = true;
|
||||
});
|
||||
queue.appendListener(otherEvent, [](const int index) {
|
||||
std::cout << "Got event, index is " << index << std::endl;
|
||||
});
|
||||
|
||||
while(! shouldStop) {
|
||||
queue.wait();
|
||||
while(! shouldStop) {
|
||||
queue.wait();
|
||||
|
||||
queue.process();
|
||||
}
|
||||
queue.process();
|
||||
}
|
||||
});
|
||||
|
||||
// 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;
|
||||
|
||||
{
|
||||
// EventQueue::DisableQueueNotify is a RAII class that
|
||||
// disables waking up any waiting threads.
|
||||
// So no events should be triggered in this code block.
|
||||
// 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.
|
||||
EQ::DisableQueueNotify disableNotify(&queue);
|
||||
// EventQueue::DisableQueueNotify is a RAII class that
|
||||
// disables waking up any waiting threads.
|
||||
// So no events should be triggered in this code block.
|
||||
// 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.
|
||||
EQ::DisableQueueNotify disableNotify(&queue);
|
||||
|
||||
queue.enqueue(otherEvent, 10);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
std::cout << "Should NOT trigger event with index = 10" << std::endl;
|
||||
|
||||
queue.enqueue(otherEvent, 11);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
std::cout << "Should NOT trigger event with index = 11" << std::endl;
|
||||
queue.enqueue(otherEvent, 10);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
std::cout << "Should NOT trigger event with index = 10" << std::endl;
|
||||
|
||||
queue.enqueue(otherEvent, 11);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
std::cout << "Should NOT trigger event with index = 11" << std::endl;
|
||||
}
|
||||
// The DisableQueueNotify object is destroyed here, and has resumed
|
||||
// waking up waiting threads. So the events should be triggered.
|
||||
|
18
readme.md
18
readme.md
@ -52,8 +52,8 @@ In brief, MSVC, GCC, Clang that has well support for C++11, or released after 20
|
||||
* The library: C++11.
|
||||
* To develop the library
|
||||
* Unit tests: C++17.
|
||||
* Tutorials: C++11.
|
||||
* Benchmakrs: C++11.
|
||||
* Tutorials: C++11.
|
||||
* Benchmakrs: C++11.
|
||||
|
||||
## 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"
|
||||
eventpp::CallbackList<void (const std::string &, const bool)> callbackList;
|
||||
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) {
|
||||
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);
|
||||
```
|
||||
@ -114,13 +114,13 @@ callbackList("Hello world", true);
|
||||
#include "eventpp/eventdispatcher.h"
|
||||
eventpp::EventDispatcher<int, void ()> dispatcher;
|
||||
dispatcher.appendListener(3, []() {
|
||||
std::cout << "Got event 3." << std::endl;
|
||||
std::cout << "Got event 3." << std::endl;
|
||||
});
|
||||
dispatcher.appendListener(5, []() {
|
||||
std::cout << "Got event 5." << std::endl;
|
||||
std::cout << "Got event 5." << std::endl;
|
||||
});
|
||||
dispatcher.appendListener(5, []() {
|
||||
std::cout << "Got another event 5." << std::endl;
|
||||
std::cout << "Got another event 5." << std::endl;
|
||||
});
|
||||
// dispatch event 3
|
||||
dispatcher.dispatch(3);
|
||||
@ -133,10 +133,10 @@ dispatcher.dispatch(5);
|
||||
eventpp::EventQueue<int, void (const std::string &, const bool)> queue;
|
||||
|
||||
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) {
|
||||
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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user