From b55bd2f783aed12047aea7d5fc813724a57577bc Mon Sep 17 00:00:00 2001 From: slayercio Date: Tue, 18 Nov 2025 20:30:44 +0100 Subject: [PATCH] feat: added event class --- src/detail/event.hpp | 198 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 src/detail/event.hpp diff --git a/src/detail/event.hpp b/src/detail/event.hpp new file mode 100644 index 0000000..cd367a5 --- /dev/null +++ b/src/detail/event.hpp @@ -0,0 +1,198 @@ +#pragma once +#include +#include +#include +#include + +namespace fx +{ + template + class fwEvent + { + public: + using TFunc = std::function; + + public: + struct callback + { + TFunc function; + std::unique_ptr next = nullptr; + int order = 0; + size_t cookie = -1; + + callback(TFunc func) + : function(func) + { + } + + ~callback() + { + while (next) + { + next = std::move(next->next); + } + } + }; + + std::unique_ptr m_callbacks; + std::atomic m_connectCookie = 0; + public: + fwEvent() + : m_callbacks(nullptr) + { + } + + ~fwEvent() + { + Reset(); + } + + template + auto Connect(T func) + { + return ConnectInternal(func, 0); + } + + template + auto Connect(T func, int order) + { + if constexpr (std::is_same_v, bool>) + { + return ConnectInternal(func, order); + } + else + { + return ConnectInternal([=](Args... args) -> bool + { + std::invoke(func, args...); + return true; + }, order); + } + } + + void Reset() + { + m_callbacks.reset(); + } + + private: + size_t ConnectInternal(TFunc func, int order) + { + if (!func) + { + return -1; + } + + auto cookie = m_connectCookie++; + auto cb = std::unique_ptr(new callback(func)); + cb->order = order; + cb->cookie = cookie; + + if (!m_callbacks) + { + m_callbacks = std::move(cb); + } + else + { + auto cur = &m_callbacks; + callback* last = nullptr; + + while (*cur && order >= (*cur)->order) + { + last = cur->get(); + cur = &(*cur)->next; + } + + cb->next = std::move(*cur); + (!last ? m_callbacks : last->next) = std::move(cb); + } + + return cookie; + } + + public: + void Disconnect(size_t cookie) + { + if (cookie == -1) + { + return; + } + + callback* prev = nullptr; + + for (auto cb = m_callbacks.get(); cb; cb = cb->next.get()) + { + if (cb->cookie == cookie) + { + if (prev) + { + prev->next = std::move(cb->next); + } + else + { + m_callbacks = std::move(cb->next); + } + + break; + } + + prev = cb; + } + } + + auto ConnectInternal(TFunc func) + { + return ConnectInternal(func, 0); + } + + public: + operator bool() const + { + return m_callbacks.get() != nullptr; + } + + bool operator()(Args... args) const + { + if (!m_callbacks) + { + return false; + } + + decltype(m_callbacks.get()) next = {}; + + for (auto cb = m_callbacks.get(); cb; cb = next) + { + next = cb->next.get(); + + if(!std::invoke(cb->function, args...)) + { + return false; + } + } + + return true; + } + + void ForeachCallback(const std::function& func) + { + callback* prev = nullptr; + std::unique_ptr* curPtr = &m_callbacks; + + while (*curPtr) + { + callback* cur = curPtr->get(); + bool keep = func(*cur); + + if (!keep) + { + *curPtr = std::move(cur->next); + } + else + { + prev = cur; + curPtr = &cur->next; + } + } + } + }; +} \ No newline at end of file