Toast Engine
Loading...
Searching...
No Matches
event.inl
1#pragma once
2#include "event.hpp"
3#include "toast/log.hpp"
4
5#include <mutex>
6#include <tracy/Tracy.hpp>
7#include <type_traits>
8
9namespace event {
10struct InspectorContent;
12
13template<typename T>
14void Event<T>::ensureRegistered() noexcept {
15 static const bool registered = [] {
16 EventSystem::registerEvent<T>();
17 return true;
18 }();
19 (void)registered;
20}
21
22template<typename T>
23auto EventSystem::info() noexcept -> EventInfo& {
24 Event<T>::ensureRegistered();
25 static EventInfo& cached = []() -> EventInfo& {
26 std::shared_lock lock(registration_mutex);
27 return event_data.at(std::type_index(typeid(T)));
28 }();
29 return cached;
30}
31
32template<typename T>
33auto Event<T>::subscribe(char priority, callback_t&& callback) noexcept -> iterator_t {
34 ensureRegistered();
35
36 auto cb = new callback_t(std::move(callback));
37 auto& g = EventSystem::info<T>();
38 {
39 std::scoped_lock _(g.mutex);
40 g.cached = false;
41 return g.callbacks.emplace(priority, static_cast<void*>(cb));
42 }
43}
44
45template<typename T>
46void Event<T>::unsubscribe(iterator_t it) noexcept {
47 ensureRegistered();
48
49 auto& g = EventSystem::info<T>();
50 {
51 std::scoped_lock _(EventSystem::deletion_mutex);
52 auto deleter = [](void* p) { delete static_cast<std::move_only_function<bool(T&)>*>(p); };
53 EventSystem::deletion_queue.emplace_back((*it).second, deleter);
54 }
55 {
56 std::scoped_lock _(g.mutex);
57 g.cached = false;
58 g.callbacks.erase(it);
59 }
60}
61
62template<typename T>
63void Event<T>::notify() noexcept {
64 ZoneScoped;
65
66 ensureRegistered();
67
68 auto& g = EventSystem::info<T>();
69 {
70 // build cached list of all the callbacks in order
71 // locks mutex for the shortest period possible
72 // improves cache locality
73 std::scoped_lock _(g.mutex);
74 if (not g.cached) {
75 g.cached = true;
76 g.processing.clear();
77 for (auto& [priority, callback] : g.callbacks) {
78 g.processing.emplace_back(callback);
79 }
80 }
81 }
82
83 // disptaches all of the callbacks
84 for (auto& callback : g.processing) {
85 ZoneScopedN("Callback dispatch");
86
87 bool handled = (*static_cast<callback_t*>(callback))(static_cast<T&>(*this));
88 if (handled) {
89 return;
90 }
91 }
92}
93
94template<typename T, typename... Args>
95 requires std::is_base_of_v<_detail::IEvent, T>
96void send(Args&&... args) noexcept {
97 ZoneScoped;
98
99 static_assert(std::is_constructible_v<T, Args...>, "Invalid Construtor For Type T");
100 if constexpr (
101 !std::is_same_v<std::decay_t<T>, event::InspectorContent> && !std::is_same_v<std::decay_t<T>, event::InspectorLuaContent>
102 ) {
103 // im going to disable this for now
104 // TOAST_TRACE("Events", "Sending event: {}", typeid(T).name());
105 }
106
107 // Allocate and enqueue event
108 {
109 std::scoped_lock _(EventSystem::pool_mutex);
110 void* memory = _detail::allocate(sizeof(T), alignof(T));
111 assert(memory);
112 _detail::IEvent* event = new (memory) T(std::forward<Args>(args)...);
113#ifdef DEBUG
114 // TODO: event->stacktrace = std::stacktrace::current(1);
115#endif
116 }
117}
118
119}
Public logging interface for the engine.
@ cached
The node is loaded in memory but not in use.
Definition node.hpp:56
Per-type callback registry.
Definition event.hpp:120
static std::mutex deletion_mutex
Protects the event queue memory pool during concurrent sends.
Definition event.hpp:150
static std::shared_mutex registration_mutex
Guards event_data and unsubscribe_map.
Definition event.hpp:131
static std::unordered_map< std::type_index, EventInfo > event_data
Dispatch table keyed by event type; one entry per registered event type.
Definition event.hpp:128
static std::mutex pool_mutex
Protects the event queue memory pool during concurrent sends.
Definition event.hpp:140
static std::vector< std::unique_ptr< void, void(*)(void *)> > deletion_queue
Definition event.hpp:147
Definition workspace_events.hpp:448
Definition workspace_events.hpp:473
Definition event.hpp:36