Add foundation event dispatcher tests
This commit is contained in:
97
src/foundation/event.cpp
Normal file
97
src/foundation/event.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "foundation/event.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace pp::foundation {
|
||||
|
||||
EventDispatcher::EventDispatcher(std::size_t max_subscriptions) noexcept
|
||||
: max_subscriptions_(max_subscriptions)
|
||||
{
|
||||
subscriptions_.reserve(std::min(max_subscriptions_, max_event_subscriptions));
|
||||
}
|
||||
|
||||
std::size_t EventDispatcher::size() const noexcept
|
||||
{
|
||||
return subscriptions_.size();
|
||||
}
|
||||
|
||||
bool EventDispatcher::empty() const noexcept
|
||||
{
|
||||
return subscriptions_.empty();
|
||||
}
|
||||
|
||||
std::size_t EventDispatcher::max_subscriptions() const noexcept
|
||||
{
|
||||
return max_subscriptions_;
|
||||
}
|
||||
|
||||
Result<std::uint64_t> EventDispatcher::subscribe(std::uint32_t type, EventCallback callback, void* user_data)
|
||||
{
|
||||
if (max_subscriptions_ == 0U || max_subscriptions_ > max_event_subscriptions) {
|
||||
return Result<std::uint64_t>::failure(
|
||||
Status::out_of_range("event dispatcher capacity is outside the configured range"));
|
||||
}
|
||||
|
||||
if (type == 0U) {
|
||||
return Result<std::uint64_t>::failure(Status::invalid_argument("event type must not be zero"));
|
||||
}
|
||||
|
||||
if (callback == nullptr) {
|
||||
return Result<std::uint64_t>::failure(Status::invalid_argument("event callback must not be null"));
|
||||
}
|
||||
|
||||
if (subscriptions_.size() >= max_subscriptions_) {
|
||||
return Result<std::uint64_t>::failure(Status::out_of_range("event dispatcher is full"));
|
||||
}
|
||||
|
||||
const auto id = next_subscription_id_++;
|
||||
subscriptions_.push_back(EventSubscription {
|
||||
.id = id,
|
||||
.type = type,
|
||||
.callback = callback,
|
||||
.user_data = user_data,
|
||||
});
|
||||
|
||||
return Result<std::uint64_t>::success(id);
|
||||
}
|
||||
|
||||
Status EventDispatcher::unsubscribe(std::uint64_t subscription_id) noexcept
|
||||
{
|
||||
const auto found = std::find_if(
|
||||
subscriptions_.begin(),
|
||||
subscriptions_.end(),
|
||||
[subscription_id](const EventSubscription& subscription) {
|
||||
return subscription.id == subscription_id;
|
||||
});
|
||||
|
||||
if (found == subscriptions_.end()) {
|
||||
return Status::out_of_range("event subscription id was not found");
|
||||
}
|
||||
|
||||
subscriptions_.erase(found);
|
||||
return Status::success();
|
||||
}
|
||||
|
||||
std::size_t EventDispatcher::publish(const Event& event) const noexcept
|
||||
{
|
||||
if (event.type == 0U) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t delivered = 0;
|
||||
for (const auto& subscription : subscriptions_) {
|
||||
if (subscription.type == event.type) {
|
||||
subscription.callback(event, subscription.user_data);
|
||||
++delivered;
|
||||
}
|
||||
}
|
||||
|
||||
return delivered;
|
||||
}
|
||||
|
||||
void EventDispatcher::clear() noexcept
|
||||
{
|
||||
subscriptions_.clear();
|
||||
}
|
||||
|
||||
}
|
||||
48
src/foundation/event.h
Normal file
48
src/foundation/event.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "foundation/result.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace pp::foundation {
|
||||
|
||||
constexpr std::size_t max_event_subscriptions = 65536;
|
||||
|
||||
struct Event {
|
||||
std::uint32_t type = 0;
|
||||
std::uint64_t source_id = 0;
|
||||
std::uint64_t frame_id = 0;
|
||||
std::uint64_t payload_u64 = 0;
|
||||
};
|
||||
|
||||
using EventCallback = void (*)(const Event& event, void* user_data) noexcept;
|
||||
|
||||
struct EventSubscription {
|
||||
std::uint64_t id = 0;
|
||||
std::uint32_t type = 0;
|
||||
EventCallback callback = nullptr;
|
||||
void* user_data = nullptr;
|
||||
};
|
||||
|
||||
class EventDispatcher {
|
||||
public:
|
||||
explicit EventDispatcher(std::size_t max_subscriptions = max_event_subscriptions) noexcept;
|
||||
|
||||
[[nodiscard]] std::size_t size() const noexcept;
|
||||
[[nodiscard]] bool empty() const noexcept;
|
||||
[[nodiscard]] std::size_t max_subscriptions() const noexcept;
|
||||
|
||||
[[nodiscard]] Result<std::uint64_t> subscribe(std::uint32_t type, EventCallback callback, void* user_data);
|
||||
[[nodiscard]] Status unsubscribe(std::uint64_t subscription_id) noexcept;
|
||||
[[nodiscard]] std::size_t publish(const Event& event) const noexcept;
|
||||
void clear() noexcept;
|
||||
|
||||
private:
|
||||
std::size_t max_subscriptions_ = max_event_subscriptions;
|
||||
std::uint64_t next_subscription_id_ = 1;
|
||||
std::vector<EventSubscription> subscriptions_;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user