5#include <unordered_map>
9#include "game/node/callback/NodeFunction.hpp"
51 template <
typename FunctionReturnType,
typename... FunctionArgs>
77 std::scoped_lock ownerGuard(mtxSpawnedOwnerNode.first, mtxCallbacks.first);
78 if (mtxSpawnedOwnerNode.second ==
nullptr) {
88 bool bIsTopLevelBroadcast = !bIsBroadcasting.test();
89 if (bIsTopLevelBroadcast) {
91 bIsBroadcasting.test_and_set();
95 std::scoped_lock guard(mtxCallbacksToAdd.first);
96 for (
auto& [iBindingId, callback] : mtxCallbacksToAdd.second) {
97 mtxCallbacks.second[iBindingId] = std::move(callback);
99 mtxCallbacksToAdd.second.clear();
104 std::scoped_lock guard(mtxCallbacksToRemove.first);
105 for (
const auto& iBindingId : mtxCallbacksToRemove.second) {
107 auto it = mtxCallbacks.second.find(iBindingId);
108 if (it == mtxCallbacks.second.end()) [[unlikely]] {
110 "a callback with binding ID {} was marked to be removed from a "
111 "broadcaster but broadcaster does not have a callback with this ID",
115 mtxCallbacks.second.erase(it);
117 mtxCallbacksToRemove.second.clear();
121 std::erase_if(mtxCallbacks.second, [](
auto& item) { return !item.second.isNodeSpawned(); });
125 for (
auto& [iBindingId, callback] : mtxCallbacks.second) {
126 callback(std::forward<FunctionArgs>(args)...);
130 if (mtxSpawnedOwnerNode.second ==
nullptr) {
136 if (bIsTopLevelBroadcast) {
138 bIsBroadcasting.clear();
153 std::scoped_lock callbacksGuard(mtxCallbacks.first);
156 const auto iNewBindingId = iAvailableBindingId.fetch_add(1);
157 if (iNewBindingId + 1 == ULLONG_MAX) [[unlikely]] {
159 "\"next available broadcaster binding ID\" is at its maximum value: {}, another "
160 "subscribed callback will cause an overflow",
165 if (bIsBroadcasting.test()) {
169 std::scoped_lock callbacksToAddGuard(mtxCallbacksToAdd.first);
170 mtxCallbacksToAdd.second[iNewBindingId] = callback;
173 mtxCallbacks.second[iNewBindingId] = callback;
176 return iNewBindingId;
190 std::scoped_lock callbacksToAddGuard(mtxCallbacksToAdd.first);
191 auto it = mtxCallbacksToAdd.second.find(iBindingId);
192 if (it != mtxCallbacksToAdd.second.end()) {
194 mtxCallbacksToAdd.second.erase(it);
200 std::scoped_lock callbacksGuard(mtxCallbacks.first);
201 auto it = mtxCallbacks.second.find(iBindingId);
202 if (it == mtxCallbacks.second.end()) [[unlikely]] {
204 std::format(
"callback with binding ID {} was not found in the broadcaster", iBindingId));
209 if (bIsBroadcasting.test()) {
213 std::scoped_lock callbacksToRemoveGuard(mtxCallbacksToRemove.first);
214 mtxCallbacksToRemove.second.push_back(iBindingId);
217 mtxCallbacks.second.erase(it);
232 std::scoped_lock guard(mtxCallbacks.first, mtxCallbacksToAdd.first, mtxCallbacksToRemove.first);
240 const auto iCurrentPlusPending = mtxCallbacks.second.size() + mtxCallbacksToAdd.second.size();
241 const auto iPendingToBeRemoved = mtxCallbacksToRemove.second.size();
244 if (iCurrentPlusPending < iPendingToBeRemoved) [[unlikely]] {
246 "there are more callbacks to be removed than all existing callbacks plus "
247 "pending to be added: currently registered: {}, pending to be added: {}, pending to "
249 mtxCallbacks.second.size(),
250 mtxCallbacksToAdd.second.size(),
251 mtxCallbacksToRemove.second.size()));
255 return iCurrentPlusPending - iPendingToBeRemoved;
267 std::scoped_lock ownerGuard(mtxSpawnedOwnerNode.first);
270 if (mtxSpawnedOwnerNode.second !=
nullptr) {
272 "some node has notified a broadcaster about being spawned but this broadcaster already "
273 "has an owner node");
279 mtxSpawnedOwnerNode.second = pOwnerNode;
288 std::scoped_lock ownerGuard(mtxSpawnedOwnerNode.first);
291 if (mtxSpawnedOwnerNode.second != pOwnerNode) [[unlikely]] {
292 Logger::get().
error(
"some node notified a broadcaster about it being despawned but this "
293 "broadcaster's owner is not this node");
298 mtxSpawnedOwnerNode.second =
nullptr;
300 removeAllCallbacks();
307 std::scoped_lock guard(mtxCallbacks.first);
308 mtxCallbacks.second.clear();
312 std::scoped_lock guard(mtxCallbacksToAdd.first);
313 mtxCallbacksToAdd.second.clear();
317 std::scoped_lock guard(mtxCallbacksToRemove.first);
318 mtxCallbacksToRemove.second.clear();
327 std::recursive_mutex,
328 std::unordered_map<size_t,
NodeFunction<FunctionReturnType(FunctionArgs...)>>>
336 std::recursive_mutex,
337 std::unordered_map<size_t,
NodeFunction<FunctionReturnType(FunctionArgs...)>>>
350 std::atomic<size_t> iAvailableBindingId{0};
353 std::atomic_flag bIsBroadcasting{};
std::string getFullErrorMessage() const
Definition: Error.cpp:84
void showError() const
Definition: Error.cpp:102
void error(std::string_view sText, const std::source_location location=std::source_location::current()) const
Definition: Logger.cpp:75
static Logger & get()
Definition: Logger.cpp:41
void warn(std::string_view sText, const std::source_location location=std::source_location::current()) const
Definition: Logger.cpp:62
Definition: NodeFunction.hpp:11
Definition: NodeNotificationBroadcaster.hpp:16
virtual void onOwnerNodeDespawning(Node *pOwnerNode)=0
virtual void onOwnerNodeSpawning(Node *pOwnerNode)=0
std::pair< std::recursive_mutex, std::vector< size_t > > mtxCallbacksToRemove
Definition: NodeNotificationBroadcaster.hpp:344
void unsubscribe(size_t iBindingId)
Definition: NodeNotificationBroadcaster.hpp:187
std::pair< std::recursive_mutex, std::unordered_map< size_t, NodeFunction< FunctionReturnType(FunctionArgs...)> > > mtxCallbacksToAdd
Definition: NodeNotificationBroadcaster.hpp:338
size_t subscribe(const NodeFunction< FunctionReturnType(FunctionArgs...)> &callback)
Definition: NodeNotificationBroadcaster.hpp:152
void removeAllCallbacks()
Definition: NodeNotificationBroadcaster.hpp:305
std::pair< std::recursive_mutex, Node * > mtxSpawnedOwnerNode
Definition: NodeNotificationBroadcaster.hpp:347
virtual void onOwnerNodeDespawning(Node *pOwnerNode) override
Definition: NodeNotificationBroadcaster.hpp:287
size_t getSubscriberCount()
Definition: NodeNotificationBroadcaster.hpp:231
void broadcast(FunctionArgs &&... args)
Definition: NodeNotificationBroadcaster.hpp:75
std::pair< std::recursive_mutex, std::unordered_map< size_t, NodeFunction< FunctionReturnType(FunctionArgs...)> > > mtxCallbacks
Definition: NodeNotificationBroadcaster.hpp:329
virtual void onOwnerNodeSpawning(Node *pOwnerNode) override
Definition: NodeNotificationBroadcaster.hpp:266
Definition: NodeNotificationBroadcaster.hpp:45