forked from Soreepeong/XivAlexander
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Utils_ListenerManager.h
139 lines (111 loc) · 3.85 KB
/
Utils_ListenerManager.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#pragma once
#include <functional>
#include <memory>
#include <map>
#include <mutex>
#include "Utils_CallOnDestruction.h"
namespace Utils {
template <typename, typename, typename, typename...>
class _ListenerManagerImpl;
template <typename R, typename ... T>
class _ListenerManagerImplBase {
template <typename, typename, typename, typename...>
friend class _ListenerManagerImpl;
size_t m_callbackId = 0;
std::map<size_t, std::function<R(T ...)>> m_callbacks;
std::shared_ptr<std::mutex> m_lock = std::make_shared<std::mutex>();
std::shared_ptr<bool> m_destructed = std::make_shared<bool>(false);
public:
virtual ~_ListenerManagerImplBase() {
std::lock_guard lock(*m_lock);
m_callbacks.clear();
*m_destructed = true;
}
/// \brief Adds a callback function to call when an event has been fired.
/// \returns An object that will remove the callback when destructed.
virtual CallOnDestruction operator() (const std::function<R(T ...)>& fn) {
std::lock_guard lock(*m_lock);
const auto callbackId = m_callbackId++;
m_callbacks.emplace(callbackId, fn);
return CallOnDestruction([destructed = m_destructed, mutex = m_lock, callbackId, this]() {
std::lock_guard lock(*mutex);
// already destructed?
if (*destructed)
return;
m_callbacks.erase(callbackId);
});
}
protected:
/// \brief Fires an event.
/// \returns Number of callbacks called.
virtual size_t operator() (T ... t) {
std::vector<std::function<R(T ...)>> callbacks;
{
std::lock_guard lock(*m_lock);
for (const auto& cbp : m_callbacks)
callbacks.push_back(cbp.second);
}
size_t notified = 0;
for (const auto& cb : callbacks) {
cb(std::forward<T>(t)...);
notified++;
}
return notified;
}
};
template <typename F, typename R, typename ... T>
class _ListenerManagerImpl<F, R, std::enable_if_t<!std::is_same_v<R, void>>, T...> :
public _ListenerManagerImplBase<R, T...> {
friend F;
public:
/// \brief Adds a callback function to call when an event has been fired.
/// \returns An object that will remove the callback when destructed.
CallOnDestruction operator() (const std::function<R(T ...)>& fn) override {
return _ListenerManagerImplBase<R, T...>::operator()(fn);
}
protected:
/// \brief Fires an event.
/// \returns Number of callbacks called.
size_t operator() (T ... t) override {
return _ListenerManagerImplBase<R, T...>::operator()(std::forward<T>(t)...);
}
/// \brief Fires an event.
/// \returns Number of callbacks called.
size_t operator() (T ... t, const std::function<bool(size_t, R)>& stopNotifying) {
std::vector<std::function<R(T ...)>> callbacks;
{
std::lock_guard<std::mutex> lock(*this->m_lock);
for (const auto& cbp : this->m_callbacks)
callbacks.emplace(cbp.second);
}
size_t notified = 0;
for (const auto& cb : callbacks) {
const auto r = cb(std::forward<T>(t)...);
if (stopNotifying && stopNotifying(notified, r))
return;
notified++;
}
return notified;
}
};
template <typename F, typename R, typename...T>
class _ListenerManagerImpl<F, R, std::enable_if_t<std::is_same_v<R, void>>, T...> :
public _ListenerManagerImplBase<R, T...> {
friend F;
public:
/// \brief Adds a callback function to call when an event has been fired.
/// \returns An object that will remove the callback when destructed.
CallOnDestruction operator() (const std::function<R(T ...)>& fn) override {
return _ListenerManagerImplBase<R, T...>::operator()(fn);
}
protected:
/// \brief Fires an event.
/// \returns Number of callbacks called.
size_t operator() (T ... t) override {
return _ListenerManagerImplBase<R, T...>::operator()(std::forward<T>(t)...);
}
};
/// Event callback management class.
template <typename F, typename R, typename...T>
class ListenerManager : public _ListenerManagerImpl<F, R, void, T...> {};
}