feat: added event class

This commit is contained in:
2025-11-18 20:30:44 +01:00
parent 989f7f4d73
commit b55bd2f783

198
src/detail/event.hpp Normal file
View File

@@ -0,0 +1,198 @@
#pragma once
#include <memory>
#include <functional>
#include <atomic>
#include <cstdint>
namespace fx
{
template<typename... Args>
class fwEvent
{
public:
using TFunc = std::function<bool(Args...)>;
public:
struct callback
{
TFunc function;
std::unique_ptr<callback> 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<callback> m_callbacks;
std::atomic<size_t> m_connectCookie = 0;
public:
fwEvent()
: m_callbacks(nullptr)
{
}
~fwEvent()
{
Reset();
}
template<typename T>
auto Connect(T func)
{
return ConnectInternal(func, 0);
}
template<typename T>
auto Connect(T func, int order)
{
if constexpr (std::is_same_v<std::invoke_result_t<T, Args...>, 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<callback>(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<bool(callback&)>& func)
{
callback* prev = nullptr;
std::unique_ptr<callback>* 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;
}
}
}
};
}