#include c_err_t c_TransitiveClosure_Init(c_TransitiveClosure_t* self, c_Digraph_t* graph, c_Allocator_t* allocator) { if (!self || !graph) return C_ERR_PARAM; self->allocator = allocator ? *allocator : c_DefaultAllocator; self->V = graph->V; self->dfs_matrix = NULL; if (self->V == 0) return C_SUCCESS; /* 1. Allocate an array of non-recursive DFS structures */ self->dfs_matrix = (c_NonrecursiveDirectedDFS_t*)c_Allocator_Calloc( &self->allocator, self->V, sizeof(c_NonrecursiveDirectedDFS_t) ); if (!self->dfs_matrix) return C_ERR_NOMEM; /* 2. Run a non-recursive DFS starting from each individual vertex */ for (c_size_t v = 0; v < self->V; ++v) { c_err_t err = c_NonrecursiveDirectedDFS_Init(&self->dfs_matrix[v], graph, v, allocator); if (err != C_SUCCESS) { /* Clean up previously initialized instances to avoid memory leaks if OOM occurs mid-way */ for (c_size_t i = 0; i < v; ++i) { c_NonrecursiveDirectedDFS_Destroy(&self->dfs_matrix[i]); } c_Allocator_Free(&self->allocator, self->dfs_matrix); self->dfs_matrix = NULL; self->V = 0; return err; } } return C_SUCCESS; } void c_TransitiveClosure_Destroy(c_TransitiveClosure_t* self) { if (!self) return; if (self->dfs_matrix) { /* Deallocate every independent tracking instance matrix block */ for (c_size_t i = 0; i < self->V; ++i) { c_NonrecursiveDirectedDFS_Destroy(&self->dfs_matrix[i]); } c_Allocator_Free(&self->allocator, self->dfs_matrix); self->dfs_matrix = NULL; } self->V = 0; }