Loading...
Searching...
No Matches
ml::DeferredOperationsManager< Derived > Class Template Reference

CRTP base that gives a manager safe deferred-operation support. More...

#include <DeferredOperationsManager.h>

Static Public Member Functions

static void clearPending ()
 Discard all pending operations without executing them.
static bool isBusy ()
 Return true if the manager is currently iterating.
static void processPending ()
 Flush all pending operations immediately.

Static Protected Member Functions

static void beginBusy ()
 Signal that iteration has begun.
static void deferOrExecute (std::function< void()> operation)
 Execute operation now if safe, otherwise queue it.
static void endBusy ()
 Signal that iteration has ended; flush pending operations.

Static Protected Attributes

static int busyDepth = 0
 Iteration nesting depth. Operations are deferred while this is > 0.
static std::vector< std::function< void()> > pendingOperations
 Queue of operations pending until the current iteration completes.

Detailed Description

template<typename Derived>
class ml::DeferredOperationsManager< Derived >

CRTP base that gives a manager safe deferred-operation support.

Several Malena managers own collections that are iterated during event firing, update ticks, or draw calls. If user code (e.g., a click callback) tries to remove an element from the collection while it is being iterated, the result is undefined behavior — typically a crash.

DeferredOperationsManager solves this with a simple pattern:

  • Wrap any iteration with beginBusy() / endBusy().
  • Wrap any destructive operation (removal, unsubscribe, unload) with deferOrExecute().
  • When endBusy() decrements the depth counter to zero, all queued operations are flushed automatically.

Because the pattern uses CRTP, each derived manager gets its own independent static busyDepth counter and pendingOperations queue. EventsManager, MessageManager, CoreManager, and PluginManager all inherit from this class for exactly that reason.

Nested calls are fully supported: beginBusy() increments the depth and endBusy() only flushes when the depth returns to zero.

Implementing a new deferred manager

class MyManager : public DeferredOperationsManager<MyManager>
{
static void fireAll()
{
for (auto* item : _items)
item->notify();
endBusy(); // flushes any remove() calls made during notify()
}
static void remove(Item* item)
{
deferOrExecute([item]{ doRemove(item); });
}
};
CRTP base that gives a manager safe deferred-operation support.
static void endBusy()
Signal that iteration has ended; flush pending operations.
static void deferOrExecute(std::function< void()> operation)
Execute operation now if safe, otherwise queue it.
static void beginBusy()
Signal that iteration has begun.
Template Parameters
DerivedThe concrete manager class (CRTP parameter).
See also
CoreManager, EventsManager, MessageManager, PluginManager

DeferredOperationsManager.

Definition at line 65 of file DeferredOperationsManager.h.

Member Function Documentation

◆ beginBusy()

template<typename Derived>
void ml::DeferredOperationsManager< Derived >::beginBusy ( )
staticprotected

Signal that iteration has begun.

Increments the busy-depth counter. Multiple nested calls are safe — operations remain deferred until the outermost endBusy() is reached.

◆ clearPending()

template<typename Derived>
void ml::DeferredOperationsManager< Derived >::clearPending ( )
static

Discard all pending operations without executing them.

Use during application shutdown or full reset when executing the queued operations would be unsafe (e.g., the objects they reference have already been destroyed).

◆ deferOrExecute()

template<typename Derived>
void ml::DeferredOperationsManager< Derived >::deferOrExecute ( std::function< void()> operation)
staticprotected

Execute operation now if safe, otherwise queue it.

If busyDepth > 0 the operation is appended to pendingOperations and will run when the current iteration completes. If the manager is idle the operation executes immediately.

Parameters
operationThe callable to execute or defer.

◆ endBusy()

template<typename Derived>
void ml::DeferredOperationsManager< Derived >::endBusy ( )
staticprotected

Signal that iteration has ended; flush pending operations.

Decrements the busy-depth counter. When the counter reaches zero, all operations in pendingOperations are executed in FIFO order and the queue is cleared.

◆ isBusy()

template<typename Derived>
bool ml::DeferredOperationsManager< Derived >::isBusy ( )
static

Return true if the manager is currently iterating.

Can be used by external code that needs to know whether a destructive operation will be deferred.

Returns
true when busyDepth > 0.

◆ processPending()

template<typename Derived>
void ml::DeferredOperationsManager< Derived >::processPending ( )
static

Flush all pending operations immediately.

Normally called automatically by endBusy(). Provided as a public escape hatch for unusual teardown sequences.

Warning
Calling this while isBusy() is true can cause iterator invalidation in the currently running loop. Only call manually when you are certain it is safe.

Member Data Documentation

◆ busyDepth

template<typename Derived>
int ml::DeferredOperationsManager< Derived >::busyDepth = 0
inlinestaticprotected

Iteration nesting depth. Operations are deferred while this is > 0.

Definition at line 69 of file DeferredOperationsManager.h.

◆ pendingOperations

template<typename Derived>
std::vector<std::function<void()> > ml::DeferredOperationsManager< Derived >::pendingOperations
inlinestaticprotected

Queue of operations pending until the current iteration completes.

Definition at line 72 of file DeferredOperationsManager.h.


The documentation for this class was generated from the following file: