TinyEvents is a simple header-only library for C++ that provides a basic, yet powerfull, event-dispatcher system. It is designed to be easy to use and to have minimal dependencies. It is written in C++17 and has no dependencies other than the standard library.
In TinyEvents any type can be used as an event. The events are dispatched to listeners that are registered for a specific event type. Asynchronous (deferred) dispatching using a queue is also supported. With the tinyevents::Token
helper class you can get RAII-style automatic listener removal.
#include <tinyevents/tinyevents.hpp>
#include <iostream>
struct MyEvent {
int value;
};
int main() {
tinyevents::Dispatcher dispatcher;
// Register a listener for MyEvent
auto handle = dispatcher.listen<MyEvent>([](const auto& event) {
std::cout << "Received MyEvent: " << event.value << std::endl;
});
// Dispatch an event
dispatcher.dispatch(MyEvent{11}); // Prints "Received MyEvent: 11"
// Queue events
dispatcher.queue(MyEvent{22});
dispatcher.queue(MyEvent{33});
dispatcher.process(); // Prints "Received MyEvent: 22"
// "Received MyEvent: 33"
dispatcher.remove(handle); // Remove the listener
dispatcher.dispatch(MyEvent{44}); // No listener, so nothing happens
return 0;
}
Just copy the include/tinyevents
folder to your project and add the include
folder to your include path. The library is header-only, so no compilation is needed.
If you use CMake, you can use the FetchContent
module to download the library and add it to your project. For example:
include(FetchContent)
FetchContent_Declare(
tinyevents
GIT_REPOSITORY https://github.com/KyrietS/tinyevents.git
GIT_TAG master
)
FetchContent_MakeAvailable(tinyevents)
target_link_libraries(${TARGET} PRIVATE tinyevents)
Or you can just clone this repository manually and add it as a subdirectory to your CMake project.
add_subdirectory(tinyevents)
target_link_libraries(${TARGET} PRIVATE tinyevents)
Don't forget to change the ${TARGET}
to the name of your target.
Register a listener for a specific event type. The listener will be called when an event of the specified type is dispatched.
template<typename Event>
std::uint64_t listen(const std::function<void(const Event&)>& listener)
- listener - A callable object that will be called when an event of type
Event
is dispatched. The object must be copyable.
Returns a handle that can be used to remove the listener.
Same as listen()
, but the listener will be removed after it is called once.
template<typename Event>
std::uint64_t listenOnce(const std::function<void(const Event&)>& listener)
- listener - A callable object that will be called when an event of type
Event
is dispatched. The object must be copyable.
Returns a handle that can be used to remove the listener.
Remove a listener that was previously registered using listen()
.
void remove(std::uint64_t handle)
- handle - The handle of the listener to remove.
Check if a listener is registered in the dispatcher.
bool hasListener(std::uint64_t handle)
- handle - The handle of the listener to check.
Immediately dispatch an event to all the listeners that are registered for the event type.
template<typename Event>
void dispatch(const Event& event)
- event - The event to dispatch.
Add an event to the queue. The event will be dispatched once process()
is called.
template<typename Event>
void queue(const Event& event)
- event - The event to queue. The event will be copied and stored in the queue.
Processing the queue will dispatch all the events that were queued using queue()
. The events will be dispatched in the order they were queued.
void process()
- You can safely call
listen()
andlistenOnce()
from inside a listener callback. The new listener will not be called during the current dispatching process. - You can safely call
remove()
from inside a listener callback. The listener will be removed immediately and will not be called during the current dispatching process. But keep in mind that the dispatching order is not guaranteed, so the listener may be called before it is removed. - You can safely call
dispatch()
andprocess()
from inside a listener callback. The new event will be dispatched immediately during the current dispatching process. - You can safely call
remove(handle)
for a handle that was already removed. Nothing will happen. - Handles are never reused by the same dispatcher.
tinevents::Dispatcher dispatcher;
std::uint64_t handle = dispatcher.listen<MyEvent>(myCallback);
// RAII token
tinyevents::Token token(dispatcher, handle); // When this token goes out of scope the listener
// will be automatically removed from dispatcher.
Make sure that the dispatcher is still alive when the token is destroyed.
Tests are written using Google Test. The library is fetched automatically by CMake during the configuration step of the tests.
In order to run the tests with CMake, you can use the following commands:
cmake -S tests -B tests/build
cmake --build tests/build
ctest --test-dir tests/build
Copyright © 2023-2024 KyrietS
Use of this software is granted under the terms of the MIT License.
See the LICENSE file for more details.