Overview#
This page gives the big picture: what the parts of the library are, how they depend on each other, and in which order a program uses them. Each part has its own detailed page.
The parts and their dependencies#
types.h ─────────── identifiers (qualifier_t, node_id_t, socket_id_t, socket_uuid_t, link_t),
│ socket types (socket_t), ng::Status, callback and validator signatures
│
registry.h ──────── global key -> value stores used for self-registration
small_map.h ─────── sorted vector map, used for small hot structures
│
socket.h ────────── InputSocket / OutputSocket: name, ID, types, value, allowed values, callbacks
node.h ──────────── Node: an instance in a graph, only knows the IDs of its sockets
node_definition.h ─ NodeDefinition: blueprint of a node type, registered in the NodesRegistry
│
graph.h ─────────── Graph: owns nodes, sockets, links and interface (parameters/results)
│
serialization.h ─── Graph -> bytes
deserialization.h ─ bytes -> Graph
│
graph_manager.h ─── graphs in memory + folders on the disk ("heads"); needed by proxies
│
data_bank.h ─────── storage of the runtime values, one pool per type
operator.h ──────── base class of the objects doing the computation of a node
graph_runtime.h ─── Graph -> flat list of operators bound to the data bank, and run
│
io.h ────────────── human-readable printing (ng::io::operator<<)
Everything lives in the ng namespace. Only the last three runtime headers are templates
(parameterized by the data bank type), everything else is compiled in src/.
What the library provides, and what the user provides#
nodes-graph is a mechanism: it knows how to store, link, check, save, load and execute nodes, but it doesn’t know any concrete node. A program using it provides:
What |
How |
Example in the tests |
|---|---|---|
Socket types |
One bit of |
|
Validators (optional) |
|
|
Node types |
|
|
Callbacks (optional) |
Functions in the |
|
Data types |
A |
|
Operators |
Classes derived from |
|
Life cycle of a graph#
1. static initialization node types, operators, validators, callbacks are registered
2. edition Graph::add_node / add_link / set_socket_value / expose_parameter ...
every change is checked immediately (types, cycles, validators, ...)
3. persistence (optional) GraphManager::save_graph -> <head>/a/b/c.graph
4. reuse (optional) another graph adds it as a proxy node: Graph::add_proxy_node("a.b.c")
5. execution GraphRuntime<DB> rt(graph); rt.run(); rt.get_result<T>("alias")
The graph is always valid: there is no “validate” step before saving or running.
Invalid operations are refused with a ng::Status and leave the graph unchanged.
Where things are stored#
To avoid pointer-chasing, nothing points to anything: objects reference each other by ID.
A
Graphstores four flat containers: nodes bynode_id_t, input sockets and output sockets bysocket_uuid_t(= node ID + socket ID), and links in astd::set<link_t>.A
Nodeonly stores the IDs of its sockets.A link is a pair of socket UUIDs, stored as (to, from) (see Identifiers).
At runtime, operators don’t point to each other either: each socket is bound to a
data_id_t, an index in the data bank. Two linked sockets are bound to the same index.
Reading order to get back into the code#
Identifiers — the vocabulary used everywhere.
Registries and self-registration — how node types and callbacks become available.
The Graph then Socket values, enumerations, validators — the core data structure and its rules.
Serialization format and The GraphManager — the disk.
Proxies: graphs inside graphs — graphs inside graphs.
The runtime — execution.
Tests, examples and sandbox — how to check that a change didn’t break anything.
Known limitations — what is known to be missing or fragile.