Moved away from shared pointers in event handlers - didn't make sense to expose the event management implementation to handlers.

Also some other bits of tidying.
This commit is contained in:
Nav
2021-06-22 03:06:20 +01:00
parent 139e880646
commit a7df862d36
19 changed files with 193 additions and 212 deletions

View File

@@ -12,23 +12,14 @@ void EventListener::clearAllCallbacks() {
this->eventTypeToCallbacksMapping.getReference().clear();
}
void EventListener::registerEvent(GenericEventPointer event) {
auto eventName = event->getName();
Logger::debug("Event \"" + eventName + "\" (" + std::to_string(event->id)
void EventListener::registerEvent(SharedGenericEventPointer event) {
auto eventType = event->getName();
Logger::debug("Event \"" + eventType + "\" (" + std::to_string(event->id)
+ ") registered for listener " + this->name);
auto queueLock = this->eventQueueByEventType.acquireLock();
auto& eventQueueByType = this->eventQueueByEventType.getReference();
if (!eventQueueByType.contains(eventName)) {
eventQueueByType.insert(
std::pair<std::string, std::queue<GenericEventPointer>>(
eventName,
std::queue<GenericEventPointer>()
)
);
}
eventQueueByType[eventName].push(event);
eventQueueByType[eventType].push(std::move(event));
this->eventQueueByEventTypeCV.notify_all();
if (this->interruptEventNotifier != nullptr && this->interruptEventNotifier->isInitialised()) {
@@ -36,26 +27,26 @@ void EventListener::registerEvent(GenericEventPointer event) {
}
}
std::vector<GenericEventPointer> EventListener::getEvents() {
std::vector<SharedGenericEventPointer> EventListener::getEvents() {
auto queueLock = this->eventQueueByEventType.acquireLock();
auto& eventQueueByType = this->eventQueueByEventType.getReference();
std::vector<GenericEventPointer> output;
std::vector<SharedGenericEventPointer> output;
for (auto& eventQueue: eventQueueByType) {
if (eventQueue.second.size() > 0) {
output.push_back(eventQueue.second.front());
if (!eventQueue.second.empty()) {
output.push_back(std::move(eventQueue.second.front()));
eventQueue.second.pop();
}
}
std::sort(output.begin(), output.end(), [](GenericEventPointer a, GenericEventPointer b) {
std::sort(output.begin(), output.end(), [](const SharedGenericEventPointer& a, const SharedGenericEventPointer& b) {
return a->id < b->id;
});
return output;
}
void EventListener::dispatchEvent(GenericEventPointer event) {
void EventListener::dispatchEvent(const SharedGenericEventPointer& event) {
auto eventName = event->getName();
Logger::debug("Dispatching event " + eventName + " (" + std::to_string(event->id) + ").");
// Dispatch the event to all registered handlers
@@ -64,7 +55,7 @@ void EventListener::dispatchEvent(GenericEventPointer event) {
mappingLock.unlock();
for (auto& callback : callbacks) {
callback(event);
callback(*(event.get()));
}
}
@@ -80,12 +71,12 @@ void EventListener::waitAndDispatch(int msTimeout) {
auto queueLock = this->eventQueueByEventType.acquireLock();
auto& eventQueueByType = this->eventQueueByEventType.getReference();
auto registeredEventTypes = this->getRegisteredEventTypeNames();
std::optional<GenericEventPointer> event;
std::optional<SharedGenericEventPointer> event;
auto eventsFound = [&registeredEventTypes, &event, &eventQueueByType]() -> bool {
for (auto& eventQueue: eventQueueByType) {
if (registeredEventTypes.find(eventQueue.first) != registeredEventTypes.end()
&& eventQueue.second.size() > 0
&& !eventQueue.second.empty()
) {
return true;
}

View File

@@ -5,6 +5,7 @@
#include <functional>
#include <queue>
#include <memory>
#include <utility>
#include <variant>
#include <optional>
#include <mutex>
@@ -50,7 +51,7 @@ namespace Bloom
std::string name;
static inline std::atomic<std::size_t> lastId = 0;
std::size_t id = ++(this->lastId);
std::size_t id = ++(EventListener::lastId);
/**
* Holds all events registered to this listener.
@@ -58,26 +59,26 @@ namespace Bloom
* Events are grouped by event type name, and removed from their queue just *before* the dispatching to
* registered handlers begins.
*/
SyncSafe<std::map<std::string, std::queue<Events::GenericEventPointer>>> eventQueueByEventType;
SyncSafe<std::map<std::string, std::queue<Events::SharedGenericEventPointer>>> eventQueueByEventType;
std::condition_variable eventQueueByEventTypeCV;
/**
* A mapping of event type names to a vector of callback functions. Events will be dispatched to these
* callback functions, during a call to EventListener::dispatchEvent().
*
* Each callback will be passed an std::shared_ptr<const EventType> of the event (we wrap all registered
* callbacks in a lambda, where we perform a downcast before invoking the callback.
* See EventListener::registerCallbackForEventType() for more)
* Each callback will be passed a reference to the event (we wrap all registered callbacks in a lambda, where
* we perform a downcast before invoking the callback. See EventListener::registerCallbackForEventType()
* for more)
*/
SyncSafe<std::map<std::string, std::vector<std::function<void(Events::GenericEventPointer)>>>> eventTypeToCallbacksMapping;
SyncSafe<std::map<std::string, std::vector<std::function<void(Events::GenericEventRef)>>>> eventTypeToCallbacksMapping;
SyncSafe<std::set<std::string>> registeredEventTypes;
std::shared_ptr<EventNotifier> interruptEventNotifier = nullptr;
std::vector<Events::GenericEventPointer> getEvents();
std::vector<Events::SharedGenericEventPointer> getEvents();
public:
explicit EventListener(const std::string& name): name(name) {};
explicit EventListener(std::string name): name(std::move(name)) {};
std::size_t getId() const {
return this->id;
@@ -95,10 +96,10 @@ namespace Bloom
*
* @param event
*/
void registerEvent(Events::GenericEventPointer event);
void registerEvent(Events::SharedGenericEventPointer event);
void setInterruptEventNotifier(std::shared_ptr<EventNotifier> interruptEventNotifier) {
this->interruptEventNotifier = interruptEventNotifier;
this->interruptEventNotifier = std::move(interruptEventNotifier);
}
/**
@@ -109,33 +110,18 @@ namespace Bloom
* @param callback
*/
template<class EventType>
void registerCallbackForEventType(std::function<void(std::shared_ptr<const EventType>)> callback) {
void registerCallbackForEventType(std::function<void(Events::EventRef<EventType>)> callback) {
// We encapsulate the callback in a lambda to handle the downcasting.
std::function<void(Events::GenericEventPointer)> parentCallback =
[callback] (Events::GenericEventPointer event) {
std::function<void(Events::GenericEventRef)> parentCallback =
[callback] (Events::GenericEventRef event) {
// Downcast the event to the expected type
callback(std::dynamic_pointer_cast<const EventType>(event));
callback(dynamic_cast<Events::EventRef<EventType>>(event));
}
;
auto mappingLock = this->eventTypeToCallbacksMapping.acquireLock();
auto& mapping = this->eventTypeToCallbacksMapping.getReference();
if (mapping.find(EventType::name) == mapping.end()) {
/*
* Multiple callbacks can be registered for a single event type.
*
* We have no callbacks for this event type registered in this listener, so setup
* the type name to callback vector mapping.
*/
mapping.insert(
std::pair<std::string, std::vector<std::function<void(Events::GenericEventPointer)>>>(
EventType::name,
std::vector<std::function<void(Events::GenericEventPointer)>>()
)
);
}
mapping[EventType::name].push_back(parentCallback);
auto registeredEventTypesLock = this->registeredEventTypes.acquireLock();
this->registeredEventTypes.getReference().insert(EventType::name);
@@ -201,20 +187,20 @@ namespace Bloom
std::optional<int> correlationId = std::nullopt
) {
// Different return types, depending on how many event type arguments are passed in.
using MonoType = std::optional<Events::EventPointer<EventTypeA>>;
using MonoType = std::optional<Events::SharedEventPointer<EventTypeA>>;
using BiVariantType = std::optional<
std::variant<
std::monostate,
Events::EventPointer<EventTypeA>,
Events::EventPointer<EventTypeB>
Events::SharedEventPointer<EventTypeA>,
Events::SharedEventPointer<EventTypeB>
>
>;
using TriVariantType = std::optional<
std::variant<
std::monostate,
Events::EventPointer<EventTypeA>,
Events::EventPointer<EventTypeB>,
Events::EventPointer<EventTypeC>
Events::SharedEventPointer<EventTypeA>,
Events::SharedEventPointer<EventTypeB>,
Events::SharedEventPointer<EventTypeC>
>
>;
using ReturnType = typename std::conditional<
@@ -262,14 +248,14 @@ namespace Bloom
}
}
Events::GenericEventPointer foundEvent = nullptr;
Events::SharedGenericEventPointer foundEvent = nullptr;
auto eventsFound = [&eventTypeNames, &eventQueueByType, &correlationId, &foundEvent]() -> bool {
for (const auto& eventTypeName : eventTypeNames) {
if (eventQueueByType.find(eventTypeName) != eventQueueByType.end()
&& eventQueueByType.find(eventTypeName)->second.size() > 0
&& !eventQueueByType.find(eventTypeName)->second.empty()
) {
auto& queue = eventQueueByType.find(eventTypeName)->second;
while (queue.size() > 0) {
while (!queue.empty()) {
auto event = queue.front();
if (!correlationId.has_value()
@@ -347,7 +333,7 @@ namespace Bloom
*/
void waitAndDispatch(int msTimeout = 0);
void dispatchEvent(Events::GenericEventPointer event);
void dispatchEvent(const Events::SharedGenericEventPointer& event);
void dispatchCurrentEvents();

View File

@@ -53,7 +53,7 @@ namespace Bloom
*
* @param event
*/
void triggerEvent(Events::GenericEventPointer event);
void triggerEvent(Events::SharedGenericEventPointer event);
};
}

View File

@@ -14,21 +14,17 @@ namespace Bloom::Events
class Event
{
private:
QDateTime createdTimestamp = DateTime::currentDateTime();
static inline std::atomic<int> lastEventId = 0;
public:
int id = ++(this->lastEventId);
int id = ++(Event::lastEventId);
QDateTime createdTimestamp = DateTime::currentDateTime();
std::optional<int> correlationId;
static inline const std::string name = "GenericEvent";
virtual std::string getName() const {
[[nodiscard]] virtual std::string getName() const {
return Event::name;
}
long getCreatedEpochTimestamp() const {
return this->createdTimestamp.toMSecsSinceEpoch();
}
};
}

View File

@@ -44,7 +44,11 @@
namespace Bloom::Events
{
template <class EventType>
using EventPointer = std::shared_ptr<const EventType>;
using SharedEventPointer = std::shared_ptr<const EventType>;
using GenericEventPointer = EventPointer<Event>;
template <class EventType>
using EventRef = const EventType&;
using SharedGenericEventPointer = SharedEventPointer<Event>;
using GenericEventRef = EventRef<Event>;
}