Decouple graph's API
This commit is contained in:
+132
-111
@@ -3,7 +3,6 @@
|
|||||||
#include "../src/wapp/wapp.h"
|
#include "../src/wapp/wapp.h"
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
wp_intern WpLogger _log = { .name = wpStr8LitRo("dag_man") };
|
wp_intern WpLogger _log = { .name = wpStr8LitRo("dag_man") };
|
||||||
@@ -65,8 +64,6 @@ typedef struct {
|
|||||||
u64 index;
|
u64 index;
|
||||||
u64 generation;
|
u64 generation;
|
||||||
} PrNodeId;
|
} PrNodeId;
|
||||||
typedef PrNodeId *PrNodeIdArray;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
union {
|
union {
|
||||||
WpStr8 path;
|
WpStr8 path;
|
||||||
@@ -87,21 +84,20 @@ typedef struct PrGraphEdge PrGraphEdge;
|
|||||||
struct PrGraphEdge {
|
struct PrGraphEdge {
|
||||||
PrGraphEdge *next_forward;
|
PrGraphEdge *next_forward;
|
||||||
PrGraphEdge *next_backward;
|
PrGraphEdge *next_backward;
|
||||||
PrNodeId source;
|
u64 source_idx;
|
||||||
PrNodeId target;
|
u64 target_idx;
|
||||||
};
|
};
|
||||||
typedef PrGraphEdge *PrGraphEdgeArray;
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
* Graph node — compact adjacency head (two pointers, no dead fields)
|
* Graph vertex — compact adjacency head (two pointers + active flag)
|
||||||
* -------------------------------------------------------------------------*/
|
* -------------------------------------------------------------------------*/
|
||||||
|
|
||||||
typedef struct PrGraphNode PrGraphNode;
|
typedef struct PrGraphVertex PrGraphVertex;
|
||||||
struct PrGraphNode {
|
struct PrGraphVertex {
|
||||||
PrGraphEdge *next_forward;
|
PrGraphEdge *next_forward;
|
||||||
PrGraphEdge *next_backward;
|
PrGraphEdge *next_backward;
|
||||||
|
b8 active;
|
||||||
};
|
};
|
||||||
typedef PrGraphNode *PrGraphNodeArray;
|
typedef PrGraphVertex *PrGraphVertexArray;
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
* PrGraph — owns only topology (edges + adjacency heads)
|
* PrGraph — owns only topology (edges + adjacency heads)
|
||||||
@@ -109,8 +105,10 @@ typedef PrGraphNode *PrGraphNodeArray;
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PrPool edge_pool;
|
PrPool edge_pool;
|
||||||
PrGraphNodeArray graph_nodes;
|
PrGraphVertexArray vertices;
|
||||||
u64 capacity;
|
u64 capacity;
|
||||||
|
u64 max_vertex_ever;
|
||||||
|
u64 vertex_count;
|
||||||
} PrGraph;
|
} PrGraph;
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
@@ -137,13 +135,15 @@ wp_intern PrNodeId prNodeManagerGetNode(const PrNodeManager *mgr, u64 index);
|
|||||||
wp_intern PrNodeId prNodeManagerAddNode(PrNodeManager *mgr, PrNodeType type);
|
wp_intern PrNodeId prNodeManagerAddNode(PrNodeManager *mgr, PrNodeType type);
|
||||||
wp_intern void prNodeManagerRemoveNode(PrNodeManager *mgr, PrNodeId id);
|
wp_intern void prNodeManagerRemoveNode(PrNodeManager *mgr, PrNodeId id);
|
||||||
wp_intern void prNodeManagerAddEdge(PrNodeManager *mgr, PrNodeId from, PrNodeId to);
|
wp_intern void prNodeManagerAddEdge(PrNodeManager *mgr, PrNodeId from, PrNodeId to);
|
||||||
|
wp_intern void prNodeManagerDumpGraph(const PrNodeManager *mgr);
|
||||||
|
|
||||||
wp_intern void prGraphInit(PrGraph *graph, WpAllocator *allocator, u64 capacity);
|
wp_intern void prGraphInit(PrGraph *graph, WpAllocator *allocator, u64 capacity);
|
||||||
wp_intern void prGraphAddEdge(PrNodeManager *mgr, PrGraph *graph, u64 from_idx, u64 to_idx);
|
wp_intern void prGraphAddVertex(PrGraph *graph, u64 idx);
|
||||||
wp_intern void prGraphRemoveEdges(PrGraph *graph, u64 idx);
|
wp_intern void prGraphRemoveVertex(PrGraph *graph, u64 idx);
|
||||||
wp_intern PrNodeIdArray prGraphTopologicalSort(const PrNodeManager *mgr, const PrGraph *graph,
|
wp_intern b8 prGraphAddEdge(PrGraph *graph, u64 from_idx, u64 to_idx);
|
||||||
const WpAllocator *allocator);
|
wp_intern b8 prGraphEdgeExists(const PrGraph *graph, u64 from_idx, u64 to_idx);
|
||||||
wp_intern void prGraphDump(const PrNodeManager *mgr, const PrGraph *graph);
|
wp_intern u64 prGraphVertexCount(const PrGraph *graph);
|
||||||
|
wp_intern WpU64Array prGraphTopologicalSort(const PrGraph *graph, const WpAllocator *allocator);
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
* PrNodeManager implementation
|
* PrNodeManager implementation
|
||||||
@@ -196,17 +196,18 @@ wp_intern PrNodeId prNodeManagerAddNode(PrNodeManager *mgr, PrNodeType type) {
|
|||||||
memset(&node->params, 0, sizeof(node->params));
|
memset(&node->params, 0, sizeof(node->params));
|
||||||
|
|
||||||
mgr->count++;
|
mgr->count++;
|
||||||
|
|
||||||
if (idx + 1 > mgr->max_count_ever) { mgr->max_count_ever = idx + 1; }
|
if (idx + 1 > mgr->max_count_ever) { mgr->max_count_ever = idx + 1; }
|
||||||
|
|
||||||
|
prGraphAddVertex(&mgr->graph, idx);
|
||||||
|
|
||||||
return (PrNodeId){ .index = idx, .generation = node->generation };
|
return (PrNodeId){ .index = idx, .generation = node->generation };
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern void prNodeManagerRemoveNode(PrNodeManager *mgr, PrNodeId id) {
|
wp_intern void prNodeManagerRemoveNode(PrNodeManager *mgr, PrNodeId id) {
|
||||||
if (!prNodeManagerIsActiveNode(mgr, id)) { return; }
|
if (!prNodeManagerIsActiveNode(mgr, id)) { return; }
|
||||||
|
|
||||||
/* Tear down all edges incident to this node */
|
/* Tear down all edges incident to this node and mark vertex inactive */
|
||||||
prGraphRemoveEdges(&mgr->graph, id.index);
|
prGraphRemoveVertex(&mgr->graph, id.index);
|
||||||
|
|
||||||
/* Return node slot to free list with bumped generation */
|
/* Return node slot to free list with bumped generation */
|
||||||
PrNode *node = &mgr->nodes[id.index];
|
PrNode *node = &mgr->nodes[id.index];
|
||||||
@@ -219,7 +220,8 @@ wp_intern void prNodeManagerRemoveNode(PrNodeManager *mgr, PrNodeId id) {
|
|||||||
wp_intern void prNodeManagerAddEdge(PrNodeManager *mgr, PrNodeId from, PrNodeId to) {
|
wp_intern void prNodeManagerAddEdge(PrNodeManager *mgr, PrNodeId from, PrNodeId to) {
|
||||||
if (!prNodeManagerIsActiveNode(mgr, from) || !prNodeManagerIsActiveNode(mgr, to)) { return; }
|
if (!prNodeManagerIsActiveNode(mgr, from) || !prNodeManagerIsActiveNode(mgr, to)) { return; }
|
||||||
if (from.index == to.index) { return; }
|
if (from.index == to.index) { return; }
|
||||||
prGraphAddEdge(mgr, &mgr->graph, from.index, to.index);
|
if (prGraphEdgeExists(&mgr->graph, from.index, to.index)) { return; }
|
||||||
|
prGraphAddEdge(&mgr->graph, from.index, to.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
@@ -227,30 +229,32 @@ wp_intern void prNodeManagerAddEdge(PrNodeManager *mgr, PrNodeId from, PrNodeId
|
|||||||
* -------------------------------------------------------------------------*/
|
* -------------------------------------------------------------------------*/
|
||||||
|
|
||||||
wp_intern void prGraphInit(PrGraph *graph, WpAllocator *allocator, u64 capacity) {
|
wp_intern void prGraphInit(PrGraph *graph, WpAllocator *allocator, u64 capacity) {
|
||||||
graph->graph_nodes = wpArrayAllocCapacity(PrGraphNode, allocator, capacity, WP_ARRAY_INIT_FILLED);
|
graph->vertices = wpArrayAllocCapacity(PrGraphVertex, allocator, capacity, WP_ARRAY_INIT_FILLED);
|
||||||
graph->capacity = capacity;
|
graph->capacity = capacity;
|
||||||
|
graph->max_vertex_ever = 0;
|
||||||
|
graph->vertex_count = 0;
|
||||||
|
|
||||||
if (!graph->graph_nodes) {
|
if (!graph->vertices) {
|
||||||
graph->capacity = 0;
|
graph->capacity = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prPoolInit(&graph->edge_pool, allocator, sizeof(PrGraphEdge));
|
prPoolInit(&graph->edge_pool, allocator, sizeof(PrGraphEdge));
|
||||||
memset(graph->graph_nodes, 0, capacity * sizeof(PrGraphNode));
|
memset(graph->vertices, 0, capacity * sizeof(PrGraphVertex));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- internal: unlink edge helpers (raw indices, caller guarantees validity) -- */
|
/* --- internal: unlink edge helpers (raw indices, caller guarantees validity) -- */
|
||||||
|
|
||||||
wp_intern void _unlinkForward(PrGraph *graph, u64 from_idx, PrGraphEdge *edge) {
|
wp_intern void _unlinkForward(PrGraph *graph, u64 from_idx, PrGraphEdge *edge) {
|
||||||
PrGraphNode *gnode = &graph->graph_nodes[from_idx];
|
PrGraphVertex *vtx = &graph->vertices[from_idx];
|
||||||
PrGraphEdge *curr = gnode->next_forward;
|
PrGraphEdge *curr = vtx->next_forward;
|
||||||
PrGraphEdge *prev = NULL;
|
PrGraphEdge *prev = NULL;
|
||||||
while (curr) {
|
while (curr) {
|
||||||
if (curr == edge) {
|
if (curr == edge) {
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev->next_forward = curr->next_forward;
|
prev->next_forward = curr->next_forward;
|
||||||
} else {
|
} else {
|
||||||
gnode->next_forward = curr->next_forward;
|
vtx->next_forward = curr->next_forward;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -260,15 +264,15 @@ wp_intern void _unlinkForward(PrGraph *graph, u64 from_idx, PrGraphEdge *edge) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wp_intern void _unlinkBackward(PrGraph *graph, u64 to_idx, PrGraphEdge *edge) {
|
wp_intern void _unlinkBackward(PrGraph *graph, u64 to_idx, PrGraphEdge *edge) {
|
||||||
PrGraphNode *gnode = &graph->graph_nodes[to_idx];
|
PrGraphVertex *vtx = &graph->vertices[to_idx];
|
||||||
PrGraphEdge *curr = gnode->next_backward;
|
PrGraphEdge *curr = vtx->next_backward;
|
||||||
PrGraphEdge *prev = NULL;
|
PrGraphEdge *prev = NULL;
|
||||||
while (curr) {
|
while (curr) {
|
||||||
if (curr == edge) {
|
if (curr == edge) {
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prev->next_backward = curr->next_backward;
|
prev->next_backward = curr->next_backward;
|
||||||
} else {
|
} else {
|
||||||
gnode->next_backward = curr->next_backward;
|
vtx->next_backward = curr->next_backward;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -277,21 +281,66 @@ wp_intern void _unlinkBackward(PrGraph *graph, u64 to_idx, PrGraphEdge *edge) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --- vertex lifecycle ------------------------------------------------- */
|
||||||
|
|
||||||
|
wp_intern void prGraphAddVertex(PrGraph *graph, u64 idx) {
|
||||||
|
graph->vertices[idx].active = true;
|
||||||
|
graph->vertex_count++;
|
||||||
|
if (idx >= graph->max_vertex_ever) {
|
||||||
|
graph->max_vertex_ever = idx + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_intern void prGraphRemoveVertex(PrGraph *graph, u64 idx) {
|
||||||
|
PrGraphVertex *vtx = &graph->vertices[idx];
|
||||||
|
if (!vtx->active) { return; }
|
||||||
|
|
||||||
|
/* Free outgoing edges: unlink from each target's backward list */
|
||||||
|
PrGraphEdge *curr = vtx->next_forward;
|
||||||
|
while (curr) {
|
||||||
|
PrGraphEdge *next = curr->next_forward;
|
||||||
|
_unlinkBackward(graph, curr->target_idx, curr);
|
||||||
|
prPoolFree(&graph->edge_pool, curr);
|
||||||
|
curr = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free incoming edges: unlink from each source's forward list */
|
||||||
|
curr = vtx->next_backward;
|
||||||
|
while (curr) {
|
||||||
|
PrGraphEdge *next = curr->next_backward;
|
||||||
|
_unlinkForward(graph, curr->source_idx, curr);
|
||||||
|
prPoolFree(&graph->edge_pool, curr);
|
||||||
|
curr = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
vtx->next_forward = NULL;
|
||||||
|
vtx->next_backward = NULL;
|
||||||
|
vtx->active = false;
|
||||||
|
graph->vertex_count--;
|
||||||
|
}
|
||||||
|
|
||||||
/* --- edge management -------------------------------------------------- */
|
/* --- edge management -------------------------------------------------- */
|
||||||
|
|
||||||
wp_intern void prGraphAddEdge(PrNodeManager *mgr, PrGraph *graph, u64 from_idx, u64 to_idx) {
|
wp_intern b8 prGraphEdgeExists(const PrGraph *graph, u64 from_idx, u64 to_idx) {
|
||||||
|
PrGraphVertex *vtx = &graph->vertices[from_idx];
|
||||||
|
PrGraphEdge *curr = vtx->next_forward;
|
||||||
|
while (curr) {
|
||||||
|
if (curr->target_idx == to_idx) { return true; }
|
||||||
|
curr = curr->next_forward;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_intern b8 prGraphAddEdge(PrGraph *graph, u64 from_idx, u64 to_idx) {
|
||||||
PrGraphEdge *edge = (PrGraphEdge *)prPoolAlloc(&graph->edge_pool);
|
PrGraphEdge *edge = (PrGraphEdge *)prPoolAlloc(&graph->edge_pool);
|
||||||
if (!edge) { return; }
|
if (!edge) { return false; }
|
||||||
|
|
||||||
PrNodeId from_id = prNodeManagerGetNode(mgr, from_idx);
|
edge->source_idx = from_idx;
|
||||||
PrNodeId to_id = prNodeManagerGetNode(mgr, to_idx);
|
edge->target_idx = to_idx;
|
||||||
|
|
||||||
edge->source = from_id;
|
|
||||||
edge->target = to_id;
|
|
||||||
|
|
||||||
/* Link into adjacency chains */
|
/* Link into adjacency chains */
|
||||||
PrGraphNode *src = &graph->graph_nodes[from_idx];
|
PrGraphVertex *src = &graph->vertices[from_idx];
|
||||||
PrGraphNode *dst = &graph->graph_nodes[to_idx];
|
PrGraphVertex *dst = &graph->vertices[to_idx];
|
||||||
edge->next_forward = src->next_forward;
|
edge->next_forward = src->next_forward;
|
||||||
edge->next_backward = dst->next_backward;
|
edge->next_backward = dst->next_backward;
|
||||||
src->next_forward = edge;
|
src->next_forward = edge;
|
||||||
@@ -299,37 +348,19 @@ wp_intern void prGraphAddEdge(PrNodeManager *mgr, PrGraph *graph, u64 from_idx,
|
|||||||
|
|
||||||
/* Check whether the new edge created a cycle */
|
/* Check whether the new edge created a cycle */
|
||||||
WpAllocator scratch = wpMemArenaAllocatorInitZero(KiB(16));
|
WpAllocator scratch = wpMemArenaAllocatorInitZero(KiB(16));
|
||||||
PrNodeIdArray sorted = prGraphTopologicalSort(mgr, graph, &scratch);
|
WpU64Array sorted = prGraphTopologicalSort(graph, &scratch);
|
||||||
u64 sorted_cnt = sorted ? wpArrayCount(sorted) : 0;
|
u64 sorted_n = sorted ? wpArrayCount(sorted) : 0;
|
||||||
if (sorted_cnt < mgr->count) {
|
if (sorted_n < graph->vertex_count) {
|
||||||
_unlinkForward(graph, from_idx, edge);
|
_unlinkForward(graph, from_idx, edge);
|
||||||
_unlinkBackward(graph, to_idx, edge);
|
_unlinkBackward(graph, to_idx, edge);
|
||||||
prPoolFree(&graph->edge_pool, edge);
|
prPoolFree(&graph->edge_pool, edge);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
wp_intern void prGraphRemoveEdges(PrGraph *graph, u64 idx) {
|
wp_intern u64 prGraphVertexCount(const PrGraph *graph) {
|
||||||
PrGraphNode *gnode = &graph->graph_nodes[idx];
|
return graph->vertex_count;
|
||||||
|
|
||||||
/* Free outgoing edges: unlink from each target's backward list */
|
|
||||||
PrGraphEdge *curr = gnode->next_forward;
|
|
||||||
while (curr) {
|
|
||||||
PrGraphEdge *next = curr->next_forward;
|
|
||||||
_unlinkBackward(graph, curr->target.index, curr);
|
|
||||||
prPoolFree(&graph->edge_pool, curr);
|
|
||||||
curr = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free incoming edges: unlink from each source's forward list */
|
|
||||||
curr = gnode->next_backward;
|
|
||||||
while (curr) {
|
|
||||||
PrGraphEdge *next = curr->next_backward;
|
|
||||||
_unlinkForward(graph, curr->source.index, curr);
|
|
||||||
prPoolFree(&graph->edge_pool, curr);
|
|
||||||
curr = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
gnode->next_forward = gnode->next_backward = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
@@ -339,12 +370,11 @@ wp_intern void prGraphRemoveEdges(PrGraph *graph, u64 idx) {
|
|||||||
* is less than mgr->count, the graph contains a cycle.
|
* is less than mgr->count, the graph contains a cycle.
|
||||||
* -------------------------------------------------------------------------*/
|
* -------------------------------------------------------------------------*/
|
||||||
|
|
||||||
wp_intern PrNodeIdArray prGraphTopologicalSort(const PrNodeManager *mgr, const PrGraph *graph,
|
wp_intern WpU64Array prGraphTopologicalSort(const PrGraph *graph, const WpAllocator *allocator) {
|
||||||
const WpAllocator *allocator) {
|
if (graph->vertex_count == 0) { return NULL; }
|
||||||
if (mgr->count == 0) { return NULL; }
|
if (!graph->vertices || graph->capacity == 0) { return NULL; }
|
||||||
if (!mgr->nodes || graph->capacity == 0) { return NULL; }
|
|
||||||
|
|
||||||
PrNodeIdArray result = wpArrayAllocCapacity(PrNodeId, allocator, mgr->count, WP_ARRAY_INIT_NONE);
|
WpU64Array result = wpArrayAllocCapacity(u64, allocator, graph->vertex_count, WP_ARRAY_INIT_NONE);
|
||||||
if (!result) { return NULL; }
|
if (!result) { return NULL; }
|
||||||
|
|
||||||
WpAllocator local_arena = wpMemArenaAllocatorInitZero(KiB(16));
|
WpAllocator local_arena = wpMemArenaAllocatorInitZero(KiB(16));
|
||||||
@@ -353,23 +383,20 @@ wp_intern PrNodeIdArray prGraphTopologicalSort(const PrNodeManager *mgr, const P
|
|||||||
if (!in_degree) { return result; }
|
if (!in_degree) { return result; }
|
||||||
memset(in_degree, 0, wpArrayCapacity(in_degree) * sizeof(u64));
|
memset(in_degree, 0, wpArrayCapacity(in_degree) * sizeof(u64));
|
||||||
|
|
||||||
for (u64 i = 0; i < mgr->max_count_ever; i++) {
|
for (u64 i = 0; i < graph->max_vertex_ever; i++) {
|
||||||
PrNodeId id = prNodeManagerGetNode(mgr, i);
|
if (!graph->vertices[i].active) { continue; }
|
||||||
if (!prNodeManagerIsActiveNode(mgr, id)) { continue; }
|
|
||||||
|
|
||||||
PrGraphNode *gnode = &graph->graph_nodes[i];
|
PrGraphEdge *curr = graph->vertices[i].next_forward;
|
||||||
PrGraphEdge *curr = gnode->next_forward;
|
|
||||||
while (curr) {
|
while (curr) {
|
||||||
in_degree[curr->target.index]++;
|
in_degree[curr->target_idx]++;
|
||||||
curr = curr->next_forward;
|
curr = curr->next_forward;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WpQueue queue = wpQueueAlloc(u64, &local_arena, mgr->count);
|
WpQueue queue = wpQueueAlloc(u64, &local_arena, graph->vertex_count);
|
||||||
|
|
||||||
for (u64 i = 0; i < mgr->max_count_ever; i++) {
|
for (u64 i = 0; i < graph->max_vertex_ever; i++) {
|
||||||
PrNodeId id = prNodeManagerGetNode(mgr, i);
|
if (!graph->vertices[i].active) { continue; }
|
||||||
if (!prNodeManagerIsActiveNode(mgr, id)) { continue; }
|
|
||||||
if (in_degree[i] == 0) {
|
if (in_degree[i] == 0) {
|
||||||
wpQueuePush(u64, &queue, &i);
|
wpQueuePush(u64, &queue, &i);
|
||||||
}
|
}
|
||||||
@@ -379,13 +406,11 @@ wp_intern PrNodeIdArray prGraphTopologicalSort(const PrNodeManager *mgr, const P
|
|||||||
u64 *node_idx = wpQueuePop(u64, &queue);
|
u64 *node_idx = wpQueuePop(u64, &queue);
|
||||||
if (!node_idx) { break; }
|
if (!node_idx) { break; }
|
||||||
|
|
||||||
PrNodeId id = prNodeManagerGetNode(mgr, *node_idx);
|
wpArrayAppendCapped(u64, result, node_idx);
|
||||||
wpArrayAppendCapped(PrNodeId, result, &id);
|
|
||||||
|
|
||||||
PrGraphNode *gnode = &graph->graph_nodes[*node_idx];
|
PrGraphEdge *curr = graph->vertices[*node_idx].next_forward;
|
||||||
PrGraphEdge *curr = gnode->next_forward;
|
|
||||||
while (curr) {
|
while (curr) {
|
||||||
u64 target_idx = curr->target.index;
|
u64 target_idx = curr->target_idx;
|
||||||
if (in_degree[target_idx] > 0) {
|
if (in_degree[target_idx] > 0) {
|
||||||
in_degree[target_idx]--;
|
in_degree[target_idx]--;
|
||||||
if (in_degree[target_idx] == 0) {
|
if (in_degree[target_idx] == 0) {
|
||||||
@@ -403,26 +428,24 @@ wp_intern PrNodeIdArray prGraphTopologicalSort(const PrNodeManager *mgr, const P
|
|||||||
* Dump
|
* Dump
|
||||||
* -------------------------------------------------------------------------*/
|
* -------------------------------------------------------------------------*/
|
||||||
|
|
||||||
wp_intern void prGraphDump(const PrNodeManager *mgr, const PrGraph *graph) {
|
wp_intern void prNodeManagerDumpGraph(const PrNodeManager *mgr) {
|
||||||
|
const PrGraph *graph = &mgr->graph;
|
||||||
printf("==============INPUTS==============\n");
|
printf("==============INPUTS==============\n");
|
||||||
for (u64 i = 0; i < mgr->max_count_ever; ++i) {
|
for (u64 i = 0; i < mgr->max_count_ever; ++i) {
|
||||||
PrNodeId id = prNodeManagerGetNode(mgr, i);
|
PrNodeId id = prNodeManagerGetNode(mgr, i);
|
||||||
if (!prNodeManagerIsActiveNode(mgr, id)) { continue; }
|
if (!prNodeManagerIsActiveNode(mgr, id)) { continue; }
|
||||||
|
|
||||||
PrGraphNode *gnode = &graph->graph_nodes[i];
|
|
||||||
|
|
||||||
printf("%" PRIu64 ":", id.index + 1);
|
printf("%" PRIu64 ":", id.index + 1);
|
||||||
|
|
||||||
if (!(gnode->next_backward)) {
|
PrGraphEdge *curr = graph->vertices[i].next_backward;
|
||||||
|
if (!curr) {
|
||||||
printf(" (none)");
|
printf(" (none)");
|
||||||
} else {
|
} else {
|
||||||
PrGraphEdge *curr = gnode->next_backward;
|
do {
|
||||||
while (curr) {
|
printf(" %" PRIu64, curr->source_idx + 1);
|
||||||
printf(" %" PRIu64, curr->source.index + 1);
|
|
||||||
curr = curr->next_backward;
|
curr = curr->next_backward;
|
||||||
|
} while (curr);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,20 +454,17 @@ wp_intern void prGraphDump(const PrNodeManager *mgr, const PrGraph *graph) {
|
|||||||
PrNodeId id = prNodeManagerGetNode(mgr, i);
|
PrNodeId id = prNodeManagerGetNode(mgr, i);
|
||||||
if (!prNodeManagerIsActiveNode(mgr, id)) { continue; }
|
if (!prNodeManagerIsActiveNode(mgr, id)) { continue; }
|
||||||
|
|
||||||
PrGraphNode *gnode = &graph->graph_nodes[i];
|
|
||||||
|
|
||||||
printf("%" PRIu64 ":", id.index + 1);
|
printf("%" PRIu64 ":", id.index + 1);
|
||||||
|
|
||||||
if (!(gnode->next_forward)) {
|
PrGraphEdge *curr = graph->vertices[i].next_forward;
|
||||||
|
if (!curr) {
|
||||||
printf(" (none)");
|
printf(" (none)");
|
||||||
} else {
|
} else {
|
||||||
PrGraphEdge *curr = gnode->next_forward;
|
do {
|
||||||
while (curr) {
|
printf(" %" PRIu64, curr->target_idx + 1);
|
||||||
printf(" %" PRIu64, curr->target.index + 1);
|
|
||||||
curr = curr->next_forward;
|
curr = curr->next_forward;
|
||||||
|
} while (curr);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -476,24 +496,24 @@ i32 main(void) {
|
|||||||
prNodeManagerAddEdge(&mgr, n3, n4);
|
prNodeManagerAddEdge(&mgr, n3, n4);
|
||||||
prNodeManagerAddEdge(&mgr, n3, n5);
|
prNodeManagerAddEdge(&mgr, n3, n5);
|
||||||
|
|
||||||
prGraphDump(&mgr, &mgr.graph);
|
prNodeManagerDumpGraph(&mgr);
|
||||||
|
|
||||||
prNodeManagerRemoveNode(&mgr, n3);
|
prNodeManagerRemoveNode(&mgr, n3);
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
prGraphDump(&mgr, &mgr.graph);
|
prNodeManagerDumpGraph(&mgr);
|
||||||
|
|
||||||
PrNodeId n6 = prNodeManagerAddNode(&mgr, PR_NODE_TYPE_READ);
|
PrNodeId n6 = prNodeManagerAddNode(&mgr, PR_NODE_TYPE_READ);
|
||||||
|
|
||||||
prNodeManagerAddEdge(&mgr, n4, n6);
|
prNodeManagerAddEdge(&mgr, n4, n6);
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
prGraphDump(&mgr, &mgr.graph);
|
prNodeManagerDumpGraph(&mgr);
|
||||||
|
|
||||||
prNodeManagerRemoveNode(&mgr, n5);
|
prNodeManagerRemoveNode(&mgr, n5);
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
prGraphDump(&mgr, &mgr.graph);
|
prNodeManagerDumpGraph(&mgr);
|
||||||
|
|
||||||
PrNodeId n7 = prNodeManagerAddNode(&mgr, PR_NODE_TYPE_READ);
|
PrNodeId n7 = prNodeManagerAddNode(&mgr, PR_NODE_TYPE_READ);
|
||||||
|
|
||||||
@@ -501,7 +521,7 @@ i32 main(void) {
|
|||||||
prNodeManagerAddEdge(&mgr, n2, n7);
|
prNodeManagerAddEdge(&mgr, n2, n7);
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
prGraphDump(&mgr, &mgr.graph);
|
prNodeManagerDumpGraph(&mgr);
|
||||||
|
|
||||||
PrNodeId n8 = prNodeManagerAddNode(&mgr, PR_NODE_TYPE_READ);
|
PrNodeId n8 = prNodeManagerAddNode(&mgr, PR_NODE_TYPE_READ);
|
||||||
|
|
||||||
@@ -509,7 +529,7 @@ i32 main(void) {
|
|||||||
prNodeManagerAddEdge(&mgr, n7, n8);
|
prNodeManagerAddEdge(&mgr, n7, n8);
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
prGraphDump(&mgr, &mgr.graph);
|
prNodeManagerDumpGraph(&mgr);
|
||||||
|
|
||||||
printf("\n=== Try adding cycle 8→1 (should be rejected) ===\n");
|
printf("\n=== Try adding cycle 8→1 (should be rejected) ===\n");
|
||||||
prNodeManagerAddEdge(&mgr, n8, n1);
|
prNodeManagerAddEdge(&mgr, n8, n1);
|
||||||
@@ -520,20 +540,21 @@ i32 main(void) {
|
|||||||
printf("\n=== Try adding cycle 7→2 (should be rejected) ===\n\n");
|
printf("\n=== Try adding cycle 7→2 (should be rejected) ===\n\n");
|
||||||
prNodeManagerAddEdge(&mgr, n7, n2);
|
prNodeManagerAddEdge(&mgr, n7, n2);
|
||||||
|
|
||||||
prGraphDump(&mgr, &mgr.graph);
|
prNodeManagerDumpGraph(&mgr);
|
||||||
|
|
||||||
printf("\n=== Topological sort ===\n");
|
printf("\n=== Topological sort ===\n");
|
||||||
PrNodeId *sorted = prGraphTopologicalSort(&mgr, &mgr.graph, &arena);
|
WpU64Array sorted = prGraphTopologicalSort(&mgr.graph, &arena);
|
||||||
if (sorted) {
|
if (sorted) {
|
||||||
u64 n = wpArrayCount(sorted);
|
u64 n = wpArrayCount(sorted);
|
||||||
printf(" count: %llu / %llu active\n",
|
printf(" count: %llu / %llu active\n",
|
||||||
(unsigned long long)n,
|
(unsigned long long)n,
|
||||||
(unsigned long long)mgr.count);
|
(unsigned long long)mgr.count);
|
||||||
for (u64 i = 0; i < n; i++) {
|
for (u64 i = 0; i < n; i++) {
|
||||||
|
PrNodeId id = prNodeManagerGetNode(&mgr, sorted[i]);
|
||||||
printf(" [%llu] idx=%llu gen=%llu\n",
|
printf(" [%llu] idx=%llu gen=%llu\n",
|
||||||
(unsigned long long)i,
|
(unsigned long long)i,
|
||||||
(unsigned long long)sorted[i].index,
|
(unsigned long long)sorted[i],
|
||||||
(unsigned long long)sorted[i].generation);
|
(unsigned long long)id.generation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user