FastEngine 0.9.4
A multiplayer oriented 2D engine made with Vulkan.
Loading...
Searching...
No Matches
C_callback.inl
1/*
2 * Copyright 2025 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>
80CallbackLambda<Types...>::~CallbackLambda()
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._markedForDeletion = true;
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._markedForDeletion)
120 {
121 //TODO: _markedForDeletion has been added in order to avoid undefined behavior when a callback remove itself
122 // while being called. But here we do the same mistake, we replace a callee that could be called at the same time.
123 // We need a better solution.
124 callee._f = std::move(callback);
125 callee._subscriber = subscriber;
126 callee._markedForDeletion = false;
127 return callee._f.get();
128 }
129 }
130
131 //Emplace back the new callee if there is no "mark for deletion"
132 this->g_callees.emplace_back(std::move(callback), subscriber);
133 return this->g_callees.back()._f.get();
134}
135template<class... Types>
136inline fge::CallbackFunctor<Types...>*
137CallbackHandler<Types...>::addFunctor(typename fge::CallbackFunctor<Types...>::CallbackFunction func,
138 fge::Subscriber* subscriber)
139{
140 return reinterpret_cast<fge::CallbackFunctor<Types...>*>(
141 this->add(std::make_unique<fge::CallbackFunctor<Types...>>(func), subscriber));
142}
143template<class... Types>
144template<typename TLambda>
145inline fge::CallbackLambda<Types...>* CallbackHandler<Types...>::addLambda(TLambda const& lambda,
146 fge::Subscriber* subscriber)
147{
148 return reinterpret_cast<fge::CallbackLambda<Types...>*>(
149 this->add(std::make_unique<fge::CallbackLambda<Types...>>(lambda), subscriber));
150}
151template<class... Types>
152template<class TObject>
154 typename fge::CallbackObjectFunctor<TObject, Types...>::CallbackFunctionObject func,
155 TObject* object,
156 Subscriber* subscriber)
157{
158 return reinterpret_cast<fge::CallbackObjectFunctor<TObject, Types...>*>(
159 this->add(std::make_unique<fge::CallbackObjectFunctor<TObject, Types...>>(func, object), subscriber));
160}
161
162template<class... Types>
164{
165 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
166 for (auto& callee: this->g_callees)
167 {
168 if (callee._markedForDeletion)
169 {
170 continue;
171 }
172
173 if (callee._f->check(ptr))
174 {
175 this->detachOnce(callee._subscriber);
176 callee._markedForDeletion = true;
177 }
178 }
179}
180template<class... Types>
182{
183 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
184 for (auto& callee: this->g_callees)
185 {
186 if (callee._markedForDeletion)
187 {
188 continue;
189 }
190
191 if (callee._subscriber == subscriber)
192 {
193 if (this->detachOnce(callee._subscriber) == 0)
194 { //At this point, all subscribers are detached so we can end the loop
195 callee._markedForDeletion = true;
196 break;
197 }
198 callee._markedForDeletion = true;
199 }
200 }
201}
202template<class... Types>
204{
205 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
206 for (auto& callee: this->g_callees)
207 {
208 if (callee._markedForDeletion)
209 {
210 continue;
211 }
212
213 if (callee._f.get() == callback)
214 {
215 this->detachOnce(callee._subscriber);
216 this->g_callees._markedForDeletion = true;
217 }
218 }
219}
220
221template<class... Types>
223{
224 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
225
226 std::size_t eraseCount = 0;
227 for (std::size_t i = 0; i < this->g_callees.size(); ++i)
228 {
229 if (this->g_callees[i]._markedForDeletion)
230 {
231 ++eraseCount;
232 continue;
233 }
234
235 if (eraseCount > 0)
236 { //We found a valid callee, we can erase the previous ones
237 this->g_callees.erase(this->g_callees.begin() + i - eraseCount, this->g_callees.begin() + i);
238 i -= eraseCount;
239 eraseCount = 0;
240 }
241
242 this->g_callees[i]._f->call(std::forward<Types>(args)...);
243
244 //While calling, the callee can remove itself or others
245 //Every erased callee is flagged (mark for deletion)
246 //In order to avoid calling something that is not valid anymore
247 }
248}
250template<class... Types>
252{
253 if (this == &handler)
254 { //Can't hook itself
255 return;
256 }
257
258 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
260 [&handler](Types... args) { handler.call(std::forward<Types>(args)...); }),
261 subscriber);
263
264template<class... Types>
266{
267 std::scoped_lock<std::recursive_mutex> const lck(this->g_mutex);
268 for (auto& callee: this->g_callees)
269 {
270 if (callee._markedForDeletion)
271 {
272 continue;
273 }
274
275 if (callee._subscriber == subscriber)
277 callee._markedForDeletion = true;
278 }
279 }
280}
281
282} // 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:163
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:137
void del(fge::CallbackBase< Types... > *callback)
Remove a callback from the list.
Definition C_callback.inl:203
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:265
void call(Types... args)
Call all the callbacks with the given arguments.
Definition C_callback.inl:222
void hook(fge::CallbackHandler< Types... > &handler, fge::Subscriber *subscriber=nullptr)
Hook a callback handler to this handler.
Definition C_callback.inl:251
void delSub(fge::Subscriber *subscriber)
Remove a callback from the list.
Definition C_callback.inl:181
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:153
fge::CallbackLambda< Types... > * addLambda(TLambda const &lambda, fge::Subscriber *subscriber=nullptr)
Helper method to add a callback lambda.
Definition C_callback.inl:145
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
fge::Subscription::SubscriberCount detachOnce(fge::Subscriber *subscriber)
Detach only once a specific subscriber.
fge::Subscription::SubscriberCount attach(fge::Subscriber *subscriber)
Attach a specific subscriber.
void detachAll()
Detach all subscribers.