Skip to content
GraphContainsNode

GraphContainsNode

Description

Check whether graph currently contains the provided node id.

Marked nodes still count as present until GraphCommitChanges is called. This is the safe probe to use before deciding whether an old stored id is still live.

Parameters

Name Direction Description
g in Graph to query.
node_id in Node id to check.

Success

Returns true when node_id currently refers to a live node (slot occupied, generation matching, and not yet committed for deletion). The graph is not modified.

Failure

Returns false when the id refers to a freed or stale slot (mismatched generation). The graph is not modified.

Usage example (Cross-references)

Usage examples (Cross-references)
        }
    
        bool result  = GraphContainsNode(&graph, b) && (graph.pending_delete_count == 1);
        u64  removed = GraphCommitChanges(&graph);
        result = result && (GraphNodeCount(&graph) == 2);
        result = result && (GraphEdgeCount(&graph) == 1);
        result = result && !GraphContainsNode(&graph, b);
        result = result && (GraphOutDegree(&graph, a) == 0);
        result = result && (GraphInDegree(&graph, a) == 1);
        result      = result && !GraphUnmarkNodeForDeletion(node);
        result      = result && (GraphCommitChanges(&graph) == 0);
        result      = result && GraphContainsNode(&graph, a);
        result      = result && (GraphNodeCount(&graph) == 1);
        result      = result && GraphNodeMarkedForDeletion(GraphGetNode(&graph, b));
        result      = result && (GraphCommitChanges(&graph) == 2);
        result      = result && !GraphContainsNode(&graph, b);
        result      = result && (GraphNodeCount(&graph) == 3);
        result      = result && (GraphEdgeCount(&graph) == 0);
        bool result = GraphMarkNodeForDeletion(GraphGetNode(&graph, b));
        result      = result && (GraphCommitChanges(&graph) == 1);
        result      = result && !GraphContainsNode(&graph, b);
    
        GraphNodeId reused = GraphAddNodeR(&graph, 99);
    
        bool result = (committed == 1);
        result      = result && !GraphContainsNode(&graph, b);
        result      = result && GraphContainsNode(&graph, a);
        result      = result && GraphContainsNode(&graph, c);
        bool result = (committed == 1);
        result      = result && !GraphContainsNode(&graph, b);
        result      = result && GraphContainsNode(&graph, a);
        result      = result && GraphContainsNode(&graph, c);
        result      = result && GraphHasEdge(&graph, a, c);
        result      = result && !GraphContainsNode(&graph, b);
        result      = result && GraphContainsNode(&graph, a);
        result      = result && GraphContainsNode(&graph, c);
        result      = result && GraphHasEdge(&graph, a, c);
        result      = result && (GraphOutDegree(&graph, a) == 1);
        bool result = GraphMarkNodeForDeletion(GraphGetNode(&graph, b));
        result      = result && (GraphCommitChanges(&graph) == 1);
        result      = result && !GraphContainsNode(&graph, b);
        (void)a;
        // slot carries a bogus visit_count and validation aborts here.
        GraphNodeId c = GraphAddNodeR(&graph, 30);
        result        = result && GraphContainsNode(&graph, c);
        result        = result && (GraphNodeCount(&graph) == 1);
        // slot accounting is inconsistent, so validation aborts before this runs.
        GraphNodeId c = GraphAddNodeR(&graph, 30);
        result        = result && GraphContainsNode(&graph, c);
        result        = result && (GraphNodeCount(&graph) == 1);
        u64  removed = GraphCommitChanges(&graph);
        result       = result && (removed == 1);
        result       = result && !GraphContainsNode(&graph, b);
    
        // Second commit: a free slot (b's) is present. The marked/unmarked passes
    
        result = result && (removed == 1);
        result = result && !GraphContainsNode(&graph, a);
        result = result && GraphContainsNode(&graph, c);
        result = result && (GraphNodeCount(&graph) == 1);
        result = result && (removed == 1);
        result = result && !GraphContainsNode(&graph, a);
        result = result && GraphContainsNode(&graph, c);
        result = result && (GraphNodeCount(&graph) == 1);
        result = result && (GraphEdgeCount(&graph) == 0);
    
        bool result = (removed == 1);
        result      = result && !GraphContainsNode(&graph, a);
        result      = result && GraphContainsNode(&graph, c);
        bool result = (removed == 1);
        result      = result && !GraphContainsNode(&graph, a);
        result      = result && GraphContainsNode(&graph, c);
    
        GraphDeinit(&graph);
        // Real: only a was deleted; c remains live (and still marked).
        bool result = (removed == 1);
        result      = result && !GraphContainsNode(&graph, a);
        result      = result && GraphContainsNode(&graph, c);
        result      = result && GraphNodeMarkedForDeletion(GraphGetNode(&graph, c));
        bool result = (removed == 1);
        result      = result && !GraphContainsNode(&graph, a);
        result      = result && GraphContainsNode(&graph, c);
        result      = result && GraphNodeMarkedForDeletion(GraphGetNode(&graph, c));
    
        result = result && GraphNodeCount(&graph) == 0 && GraphEdgeCount(&graph) == 0 && GraphEmpty(&graph);
        result = result && !GraphContainsNode(&graph, first_id) && !GraphContainsNode(&graph, second_id);
        result = result && !GraphContainsNode(&graph, third_id);
        // intentional bypass: no public accessors for `slots`, `free_indices`,
        result = result && GraphNodeCount(&graph) == 0 && GraphEdgeCount(&graph) == 0 && GraphEmpty(&graph);
        result = result && !GraphContainsNode(&graph, first_id) && !GraphContainsNode(&graph, second_id);
        result = result && !GraphContainsNode(&graph, third_id);
        // intentional bypass: no public accessors for `slots`, `free_indices`,
        // `pending_delete_count`, or `pending_edge_removals`; this test asserts
        ValidateGraph(&graph);
    
        result = result && GraphContainsNode(&graph, a) && GraphContainsNode(&graph, c);
        result = result && !GraphContainsNode(&graph, b);
    
        result = result && GraphContainsNode(&graph, a) && GraphContainsNode(&graph, c);
        result = result && !GraphContainsNode(&graph, b);
    
        GraphDeinit(&graph);
        result = result && GraphNodeGetId(node) == node_id;
        result = result && GraphNodeIndex(node) == 0;
        result = result && GraphContainsNode(&graph, node_id);
    
        GraphDeinit(&graph);
    
        bool result = GraphNodeCount(&graph) == 3 && GraphEdgeCount(&graph) == 3 && !GraphEmpty(&graph);
        result = result && GraphContainsNode(&graph, a) && GraphContainsNode(&graph, b) && GraphContainsNode(&graph, c);
        result = result && GraphNodeAt(&graph, b) == 25;
        result = result && GraphNodeData(&graph, node_b) == 25;
    // it as contained (true) -- a deterministic divergence.
    static bool test_contains_node_rejects_index_equal_to_slot_count(void) {
        WriteFmt("Testing GraphContainsNode rejects index == slot count\n");
    
        DefaultAllocator alloc = DefaultAllocatorInit();
        GraphNodeId b = GraphAddNodeR(&graph, 20);
    
        bool result = GraphContainsNode(&graph, a);
        result      = result && GraphContainsNode(&graph, b);
    
        bool result = GraphContainsNode(&graph, a);
        result      = result && GraphContainsNode(&graph, b);
    
        // intentional bypass: no public setter shrinks the slot array. Dropping one
        // Real code rejects b as out of bounds; the `>`-mutant reads the occupied
        // slot and wrongly reports it contained.
        result = result && !GraphContainsNode(&graph, b);
    
        // Restore the length so GraphDeinit walks a consistent slot array.
    // report as contained.
    static bool test_contains_node_free_slot_with_matching_generation(void) {
        WriteFmt("Testing GraphContainsNode rejects a freed slot whose generation matches\n");
    
        DefaultAllocator alloc = DefaultAllocatorInit();
        GraphNodeId a = GraphAddNodeR(&graph, 10);
    
        bool result = GraphContainsNode(&graph, a);
    
        // Delete + commit: slot 0 becomes free and its generation is bumped to
        result = result && GraphMarkNodeForDeletion(GraphGetNode(&graph, a));
        result = result && (GraphCommitChanges(&graph) == 1);
        result = result && !GraphContainsNode(&graph, a);
    
        // Construct an id that targets the now-free slot 0 with its current
        // occupancy term forced truthy + generation matches => wrongly contained.
        GraphNodeId free_slot_id = make_raw_node_id(GraphNodeIdIndex(a), GraphNodeIdGeneration(a) + 1);
        result                   = result && !GraphContainsNode(&graph, free_slot_id);
    
        GraphDeinit(&graph);
        // re-run the deep slot-accounting scan (which would itself reject the
        // corruption below in both real and mutated builds).
        (void)GraphContainsNode(&graph, b);
    
        // intentional bypass: no public setter shrinks the slot array. Removing one
Last updated on