Identifiers#
All the identifiers are defined in include/nodes-graph/types.h. Most of them are fixed-size
std::array<char, N>: they are cheap to copy, compare and serialize, and never allocate.
The last byte is always '\0', so id.data() is a valid C-string. Strings that are too long are
silently truncated.
The as_* functions build an identifier from a string. The ones that don’t need validation are
constexpr, so identifiers can be compile-time constants:
constexpr ng::socket_id_t S = ng::as_socket_id("result");
constexpr ng::qualifier_t Q = ng::make_qualifier("my_app", "math", "add");
Qualifiers: qualifier_t#
A qualifier names a kind of thing that can be sorted in a hierarchy: a node type, a graph saved on
the disk, a callback. It is made of qualifier_t::N_CHUNKS (3) chunks of type qchunk_t
(QUALIFIER_CHUNK_SIZE = 28 bytes, so 27 characters), ordered from the most general to the most
specific, like a reversed domain name: nodes_graph.structural.results_interface.
as_qualifier("a.b.c")parses and validates (throwsstd::runtime_errorunless there are exactly 3 non-empty chunks). The empty string givesnull_qualifier.make_qualifier("a", "b", "c")is theconstexprversion, without validation.as_string(q)gives back"a.b.c",as_filepath(q)givesa/b/c.graph.is_complete()is true if no chunk is empty: required to save a graph.Qualifiers are totally ordered (chunk by chunk, lexicographically), so they can be keys of
std::map.
Socket local IDs: socket_id_t#
SOCKET_ID_SIZE = 24 bytes. Identifies a socket within a node: all the instances of a node type
share the same socket IDs (“a”, “b”, “sum” for an Add node).
null_socketis all zeros: smaller than any other ID.inf_socketis allCHAR_MAX: greater than any ASCII ID. Together, they bound the range of all the sockets of a node (see below).
Node instance IDs: node_id_t#
NODE_ID_SIZE = 32 bytes. Identifies a node within a graph: <last chunk of the type>#<random>,
for example add#43604. The random part is drawn in [1, MAX_NODE_RANDOM_ID] (999999) by
Node::make_random_id(), and Graph draws again until the ID is unused in the graph.
If the name is too long, it is truncated so the #index always fits.
Node::seed_random_ids(seed) makes the sequence reproducible (useful in tests).
socket_id_t and node_id_t have different sizes on purpose: they are distinct types, and a
static_assert guarantees it, so they can’t be mixed up.
Socket global IDs: socket_uuid_t#
std::pair<node_id_t, socket_id_t>, built with as_socket_uuid(node, "socket"). This is how a
socket is designated in a graph. Because the node ID comes first, all the sockets of a node are
contiguous in a std::map keyed by UUID, between (node, null_socket) and (node, inf_socket).
Graph::remove_node uses this to erase them with a single range.
Links: link_t#
std::pair<socket_uuid_t, socket_uuid_t> stored as (to, from): destination first.
Warning
as_link(from, to) takes its arguments in the natural order but stores them reversed.
link.first is the input socket, link.second the output socket.
The reason: an input socket accepts a single link, so “which link targets this input?” is the most
frequent question. With the destination first, the links of a std::set are sorted by destination
and Graph::find_link_by_input_socket answers in O(log n) with a lower_bound on
(target, (null_node, null_socket)) instead of scanning all the links.
Other types#
socket_t(uint32_t): bit mask of the types a socket accepts.null_socket_type= 0,all_socket_type= all bits. Two sockets can be linked if their masks intersect.graph_id_t(uint16_t): ID of a graph in theGraphManager.data_id_t(size_t): index of a value in a data bank.null_data(0) means “no data”.ng::Status: result of the operations that can fail normally.ng::as_string(status)gives its name.