Registries and self-registration#
ng::Registry<Key, Value> (registry.h) is a std::map wrapped in a singleton: there is
exactly one instance per (Key, Value) pair, reachable with instance().
Alias ( |
Key -> Value |
Used by |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Rules:
An entry is never overwritten:
register_entryreturnsfalseif the key exists.get(key)throwsstd::out_of_range;get_safe(key, default)doesn’t.There is no way to unregister: the registries are meant to be filled once, at startup.
Self-registration at static initialization#
The usual pattern registers entries from a .cc file, in an anonymous namespace, by initializing a
dummy variable:
namespace {
bool registered = ng::NodesRegistry::instance().register_entry(MY_QUALIFIER, make_definition());
}
Nothing has to call a “register everything” function: linking the .cc file is enough.
Two pitfalls come with it:
Static libraries drop it. If the file is in a static library and nothing references one of its symbols, the linker doesn’t include it and the registration never happens. That’s why the library and the test elements are CMake
OBJECTlibraries.Static initialization order. The order of initialization between
.ccfiles is unspecified. A registration must not depend on a global defined in another file. The registries themselves are function-local statics (instance()), so they are always constructed on first use. Qualifiers used as keys should beconstexpr(ng::make_qualifier) rather than globals initialized withng::as_qualifier(...), which run at an unknown time.
Callbacks are referenced by qualifier#
A socket doesn’t store a function pointer but the qualifier of a callback. The function is looked up in the registry each time the callback is triggered. This is what makes callbacks serializable: a saved graph contains qualifiers, and the program reading it provides the functions. A qualifier with no registered function is silently ignored.