Flow 2.0.0
Flow project: Full implementation reference.
Public Types | Static Public Member Functions | Static Private Member Functions | Private Attributes | List of all members
flow::util::Action_registry< Tag_t, Args > Class Template Reference

A registry of callbacks (actions) sharing a common signature, intended for fan-out invocation across statically-constructed singletons. More...

#include <action_registry.hpp>

Collaboration diagram for flow::util::Action_registry< Tag_t, Args >:
[legend]

Public Types

using Tag = Tag_t
 Alias for template parameter. More...
 

Static Public Member Functions

template<typename Action_func >
static void register_action (Action_func &&action)
 Registers a callback to be invoked by future execute() calls. More...
 
static void execute (const Args &... args)
 Invokes every registered callback, in registration order, passing the given arguments to each. More...
 

Static Private Member Functions

static Action_registry & get_instance ()
 Returns the singleton instance. More...
 

Private Attributes

Mutex_non_recursive m_mutex
 Protects m_actions. More...
 
std::vector< Function< void(Args...)> > m_actions
 Registered callbacks, in registration order. More...
 

Detailed Description

template<typename Tag_t, typename... Args>
class flow::util::Action_registry< Tag_t, Args >

A registry of callbacks (actions) sharing a common signature, intended for fan-out invocation across statically-constructed singletons.

Each singleton self-registers a callback during its static construction; the end user then invokes execute() once to fan out to all registered callbacks.

It is possible, and fine, to register actions from places other than singleton initializers, and the action itself is in no way required to do something singleton- or even global-related. The original motivation was for singleton self-registration, but conceivably Action_registry can be useful elsewhere.

Motivation

Consider a framework with multiple singleton subsystems, each needing a set_logger() call at startup and teardown. Without Action_registry the user must know about and call each one; and a new subsystem (possibly from a downstream project) cannot participate without modifying the framework's central code. With Action_registry each singleton registers itself, and the user's single execute() call reaches all of them – including ones the framework author never anticipated.

Usage

Define a tag type to differentiate your registry from others:

struct My_set_logger_tag {};
A registry of callbacks (actions) sharing a common signature, intended for fan-out invocation across ...

Each singleton registers during construction:

// In some singleton's static-init context (ctor, Static_state ctor, etc.):
My_set_logger_registry::register_action([](flow::log::Logger* logger_ptr)
{
Foo::static_set_logger(logger_ptr);
});
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
Definition: log.hpp:1392

The end user simply does:

My_set_logger_registry::execute(&my_logger); // startup
// Forwarded `&my_logger` to all registered actions: Executed them in order of registration.
// ... application runs ...
My_set_logger_registry::execute(nullptr); // teardown
// Forwarded `nullptr` to all registered actions: Executed them in order of registration.

Arg types

Each type in Args shall be a plain non-reference, non-const type – typically a pointer or scalar. (Pointer to const is perfectly fine: e.g., const Logger*.) execute() receives each arg by const reference and passes it, as an lvalue, to each registered callback; since the callback signature takes Args by value, a copy is made per callback invocation. For pointer/scalar types this cost is trivial. For heavier types, prefer passing a pointer to the heavy object rather than the object itself.

Thread safety

All methods are thread-safe with respect to each other. Internally a non-recursive mutex is held during both register_action() and execute(). Consequently a callback invoked by execute() must not call register_action() on the same Action_registry instantiation; doing so will deadlock (this is intentional: such a call pattern would indicate a design problem).

Template Parameters
Tag_tA tag type used solely to differentiate distinct Action_registry instantiations. Each unique Tag yields a distinct singleton registry.
ArgsThe parameter types of the action. Each registered callback has signature void (Args...). See "Arg types" above.

Definition at line 97 of file action_registry.hpp.

Member Typedef Documentation

◆ Tag

template<typename Tag_t , typename... Args>
using flow::util::Action_registry< Tag_t, Args >::Tag = Tag_t

Alias for template parameter.

Definition at line 103 of file action_registry.hpp.

Member Function Documentation

◆ execute()

template<typename Tag_t , typename... Args>
void flow::util::Action_registry< Tag_t, Args >::execute ( const Args &...  args)
static

Invokes every registered callback, in registration order, passing the given arguments to each.

Thread-safe.

Parameters
argsArguments forwarded to each registered callback.

Definition at line 165 of file action_registry.hpp.

◆ get_instance()

template<typename Tag_t , typename... Args>
Action_registry< Tag_t, Args... > & flow::util::Action_registry< Tag_t, Args >::get_instance
staticprivate

Returns the singleton instance.

Uses a function-local static, so it is safe to call during static initialization from any translation unit.

Returns
Reference to the sole instance.

Definition at line 176 of file action_registry.hpp.

◆ register_action()

template<typename Tag_t , typename... Args>
template<typename Action_func >
void flow::util::Action_registry< Tag_t, Args >::register_action ( Action_func &&  action)
static

Registers a callback to be invoked by future execute() calls.

Intended to be called from singleton constructors (static-init time or lazy-init get_instance() patterns). Thread-safe.

Template Parameters
Action_funcFunctor type matching the signature void (Args...).
Parameters
actionThe callback to register. Must not be empty.

Definition at line 157 of file action_registry.hpp.

Member Data Documentation

◆ m_actions

template<typename Tag_t , typename... Args>
std::vector<Function<void (Args...)> > flow::util::Action_registry< Tag_t, Args >::m_actions
private

Registered callbacks, in registration order.

If we wanted to add an unregister_action(), this might turn into a Linked_hash_set.

Definition at line 150 of file action_registry.hpp.

◆ m_mutex

template<typename Tag_t , typename... Args>
Mutex_non_recursive flow::util::Action_registry< Tag_t, Args >::m_mutex
mutableprivate

Protects m_actions.

Definition at line 143 of file action_registry.hpp.


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