FastEngine 0.9.3
A multiplayer oriented 2D engine made with Vulkan.
Loading...
Searching...
No Matches
C_callback.inl
1/*
2 * Copyright 2024 Guillaume Guillet
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17namespace fge
18{
19
20//CallbackFunctor
21
22template<class... Types>
23CallbackFunctor<Types...>::CallbackFunctor(fge::CallbackFunctor<Types...>::CallbackFunction func) :
24 g_function(func)
25{}
26
27template<class... Types>
29{
30 this->g_function(args...);
31}
32template<class... Types>
34{
35 return this->g_function == reinterpret_cast<fge::CallbackFunctor<Types...>::CallbackFunction>(ptr);
36}
37
38//CallbackObjectFunctor
39
40template<class TObject, class... Types>
42 fge::CallbackObjectFunctor<TObject, Types...>::CallbackFunctionObject func,
43 TObject* object) :
44 g_functionObj(func),
45 g_object(object)
46{}
47
48template<class TObject, class... Types>
50{
51 ((this->g_object)->*(this->g_functionObj))(args...);
52}
53
54template<class TObject, class... Types>
56{
57 return this->g_object == reinterpret_cast<TObject*>(ptr);
58}
59
60//CallbackLambda
61
62template<class... Types>
63template<typename TLambda>
65 g_lambda(new TLambda(lambda))
66{
67 this->g_executeLambda = [](void* lambdaPtr, [[maybe_unused]] Types... arguments) {
68 if constexpr (std::is_invocable_v<TLambda, Types...>)
69 {
70 return (*reinterpret_cast<TLambda*>(lambdaPtr))(arguments...);
71 }
72 else
73 {
74 return (*reinterpret_cast<TLambda*>(lambdaPtr))();
75 }
76 };
77 this->g_deleteLambda = [](void* lambdaPtr) { delete reinterpret_cast<TLambda*>(lambdaPtr); };
78}
79template<class... Types>
81{
82 (*this->g_deleteLambda)(this->g_lambda);
83}
84
85template<class... Types>
87{
88 (*this->g_executeLambda)(this->g_lambda, args...);
89}
90template<class... Types>
91bool CallbackLambda<Types...>::check([[maybe_unused]] void* ptr)
92{
93 return false;
94}
95
96//CallbackHandler
97
98template<class... Types>
100{
101 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
102 this->detachAll();
103 for (auto& callee: this->g_callees)
104 {
105 callee._f = nullptr;
106 }
107}
108
109template<class... Types>
110fge::CallbackBase<Types...>* CallbackHandler<Types...>::add(CalleePtr&& callback, fge::Subscriber* subscriber)
111{
112 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
113
114 this->attach(subscriber);
115
116 //Search for a "mark for deletion" callee and replace it with the new one
117 for (auto& callee: this->g_callees)
118 {
119 if (callee._f == nullptr)
120 {
121 callee._f = std::move(callback);
122 callee._subscriber = subscriber;
123 return callee._f.get();
124 }
125 }
126
127 //Emplace back the new callee if there is no "mark for deletion"
128 this->g_callees.emplace_back(std::move(callback), subscriber);
129 return this->g_callees.back()._f.get();
130}
131template<class... Types>
132inline fge::CallbackFunctor<Types...>*
133CallbackHandler<Types...>::addFunctor(typename fge::CallbackFunctor<Types...>::CallbackFunction func,
134 fge::Subscriber* subscriber)
135{
136 return reinterpret_cast<fge::CallbackFunctor<Types...>*>(
137 this->add(std::make_unique<fge::CallbackFunctor<Types...>>(func), subscriber));
138}
139template<class... Types>
140template<typename TLambda>
141inline fge::CallbackLambda<Types...>* CallbackHandler<Types...>::addLambda(TLambda const& lambda,
142 fge::Subscriber* subscriber)
143{
144 return reinterpret_cast<fge::CallbackLambda<Types...>*>(
145 this->add(std::make_unique<fge::CallbackLambda<Types...>>(lambda), subscriber));
146}
147template<class... Types>
148template<class TObject>
150 typename fge::CallbackObjectFunctor<TObject, Types...>::CallbackFunctionObject func,
151 TObject* object,
152 Subscriber* subscriber)
153{
154 return reinterpret_cast<fge::CallbackObjectFunctor<TObject, Types...>*>(
155 this->add(std::make_unique<fge::CallbackObjectFunctor<TObject, Types...>>(func, object), subscriber));
156}
157
158template<class... Types>
160{
161 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
162 for (auto& callee: this->g_callees)
163 {
164 if (callee._f == nullptr)
165 {
166 continue;
167 }
168
169 if (callee._f->check(ptr))
170 {
171 this->detachOnce(callee._subscriber);
172 callee._f = nullptr;
173 }
174 }
175}
176template<class... Types>
178{
179 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
180 for (auto& callee: this->g_callees)
181 {
182 if (callee._f == nullptr)
183 {
184 continue;
185 }
186
187 if (callee._subscriber == subscriber)
188 {
189 if (this->detachOnce(callee._subscriber) == 0)
190 { //At this point, all subscribers are detached so we can end the loop
191 callee._f = nullptr;
192 break;
193 }
194 callee._f = nullptr;
195 }
196 }
197}
198template<class... Types>
200{
201 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
202 for (auto& callee: this->g_callees)
203 {
204 if (callee._f == nullptr)
205 {
206 continue;
207 }
208
209 if (callee._f.get() == callback)
210 {
211 this->detachOnce(callee._subscriber);
212 this->g_callees._f = nullptr;
213 }
214 }
215}
216
217template<class... Types>
219{
220 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
222 std::size_t eraseCount = 0;
223 for (std::size_t i = 0; i < this->g_callees.size(); ++i)
224 {
225 if (this->g_callees[i]._f == nullptr)
226 {
227 ++eraseCount;
228 continue;
229 }
230
231 if (eraseCount > 0)
232 { //We found a valid callee, we can erase the previous ones
233 this->g_callees.erase(this->g_callees.begin() + i - eraseCount, this->g_callees.begin() + i);
234 i -= eraseCount;
235 eraseCount = 0;
236 }
237
238 this->g_callees[i]._f->call(std::forward<Types>(args)...);
239
240 //While calling, the callee can remove itself or others
241 //Every erased callee is replaced by nullptr (mark for deletion)
242 //In order to avoid calling somthing that is not valid anymore
243 }
244}
245
246template<class... Types>
248{
249 if (this == &handler)
250 { //Can't hook itself
251 return;
252 }
253
254 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
255 this->add(new fge::CallbackLambda<Types...>(
256 [&handler](Types... args) { handler.call(std::forward<Types>(args)...); }),
257 subscriber);
258}
259
260template<class... Types>
263 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
264 for (auto& callee: this->g_callees)
265 {
266 if (callee._f == nullptr)
267 {
268 continue;
269 }
270
271 if (callee._subscriber == subscriber)
272 {
273 callee._f = nullptr;
274 }
275 }
277
278} // namespace fge
Base class for callbacks.
Definition C_callback.hpp:37
Callback functor.
Definition C_callback.hpp:54
bool check(void *ptr) override
Check if the given pointer is the same as the one used to construct the functor.
Definition C_callback.inl:33
void call(Types... args) override
Call the callback function with the given arguments.
Definition C_callback.inl:28
CallbackFunctor(fge::CallbackFunctor< Types... >::CallbackFunction func)
Constructor.
Definition C_callback.inl:23
This class is used to handle callbacks in a safe way.
Definition C_callback.hpp:189
void delPtr(void *ptr)
Remove a callback from the list.
Definition C_callback.inl:159
fge::CallbackFunctor< Types... > * addFunctor(typename fge::CallbackFunctor< Types... >::CallbackFunction func, fge::Subscriber *subscriber=nullptr)
Helper method to add a callback functor.
Definition C_callback.inl:133
void del(fge::CallbackBase< Types... > *callback)
Remove a callback from the list.
Definition C_callback.inl:199
fge::CallbackBase< Types... > * add(CalleePtr &&callback, fge::Subscriber *subscriber=nullptr)
Add a new callback to the list.
Definition C_callback.inl:110
void onDetach(fge::Subscriber *subscriber) override
This method is called when a subscriber is destroyed (destructor called)
Definition C_callback.inl:261
void call(Types... args)
Call all the callbacks with the given arguments.
Definition C_callback.inl:218
void hook(fge::CallbackHandler< Types... > &handler, fge::Subscriber *subscriber=nullptr)
Hook a callback handler to this handler.
Definition C_callback.inl:247
void delSub(fge::Subscriber *subscriber)
Remove a callback from the list.
Definition C_callback.inl:177
void clear()
Clear the list of callbacks.
Definition C_callback.inl:99
fge::CallbackObjectFunctor< TObject, Types... > * addObjectFunctor(typename fge::CallbackObjectFunctor< TObject, Types... >::CallbackFunctionObject func, TObject *object, Subscriber *subscriber=nullptr)
Helper method to add a callback object functor.
Definition C_callback.inl:149
fge::CallbackLambda< Types... > * addLambda(TLambda const &lambda, fge::Subscriber *subscriber=nullptr)
Helper method to add a callback lambda.
Definition C_callback.inl:141
Callback lambda (with/without capture)
Definition C_callback.hpp:93
bool check(void *ptr) override
Always return false.
Definition C_callback.inl:91
void call(Types... args) override
Call the callback function with the given arguments.
Definition C_callback.inl:86
CallbackLambda(TLambda const &lambda)
Constructor.
Definition C_callback.inl:64
Callback functor of a method with an object.
Definition C_callback.hpp:135
bool check(void *ptr) override
Check if the given object pointer is the same as the one used to construct the functor.
Definition C_callback.inl:55
void call(Types... args) override
Call the callback method with the given arguments.
Definition C_callback.inl:49
CallbackObjectFunctor(fge::CallbackObjectFunctor< TObject, Types... >::CallbackFunctionObject func, TObject *object)
Constructor.
Definition C_callback.inl:41
This class is a useful utility to "link" multiple objects around.
Definition C_subscription.hpp:150