feat: added event class
This commit is contained in:
198
src/detail/event.hpp
Normal file
198
src/detail/event.hpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user