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 (throws std::runtime_error unless there are exactly 3 non-empty chunks). The empty string gives null_qualifier.

  • make_qualifier("a", "b", "c") is the constexpr version, without validation.

  • as_string(q) gives back "a.b.c", as_filepath(q) gives a/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_socket is all zeros: smaller than any other ID.

  • inf_socket is all CHAR_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.

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 the GraphManager.

  • 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.