isl_test_cpp17-generic.cc: work around std::optional::value issue in older macOS
[isl.git] / isl_tarjan.c
bloba958c016e0be52825b51b47dff9c383f47787790
1 /*
2 * Copyright 2010-2011 INRIA Saclay
3 * Copyright 2012 Ecole Normale Superieure
5 * Use of this software is governed by the MIT license
7 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
8 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
9 * 91893 Orsay, France
10 * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
13 #include <stdlib.h>
14 #include <isl/ctx.h>
15 #include <isl_tarjan.h>
17 struct isl_tarjan_graph *isl_tarjan_graph_free(struct isl_tarjan_graph *g)
19 if (!g)
20 return NULL;
21 free(g->node);
22 free(g->stack);
23 free(g->order);
24 free(g);
25 return NULL;
28 static struct isl_tarjan_graph *isl_tarjan_graph_alloc(isl_ctx *ctx, int len)
30 struct isl_tarjan_graph *g;
31 int i;
33 g = isl_calloc_type(ctx, struct isl_tarjan_graph);
34 if (!g)
35 return NULL;
36 g->len = len;
37 g->node = isl_alloc_array(ctx, struct isl_tarjan_node, len);
38 if (len && !g->node)
39 goto error;
40 for (i = 0; i < len; ++i)
41 g->node[i].index = -1;
42 g->stack = isl_alloc_array(ctx, int, len);
43 if (len && !g->stack)
44 goto error;
45 g->order = isl_alloc_array(ctx, int, 2 * len);
46 if (len && !g->order)
47 goto error;
49 g->sp = 0;
50 g->index = 0;
51 g->op = 0;
53 return g;
54 error:
55 isl_tarjan_graph_free(g);
56 return NULL;
59 /* Perform Tarjan's algorithm for computing the strongly connected components
60 * in the graph with g->len nodes and with edges defined by "follows".
62 static isl_stat isl_tarjan_components(struct isl_tarjan_graph *g, int i,
63 isl_bool (*follows)(int i, int j, void *user), void *user)
65 int j;
67 g->node[i].index = g->index;
68 g->node[i].min_index = g->index;
69 g->node[i].on_stack = 1;
70 g->index++;
71 g->stack[g->sp++] = i;
73 for (j = g->len - 1; j >= 0; --j) {
74 isl_bool f;
76 if (j == i)
77 continue;
78 if (g->node[j].index >= 0 &&
79 (!g->node[j].on_stack ||
80 g->node[j].index > g->node[i].min_index))
81 continue;
83 f = follows(i, j, user);
84 if (f < 0)
85 return isl_stat_error;
86 if (!f)
87 continue;
89 if (g->node[j].index < 0) {
90 isl_tarjan_components(g, j, follows, user);
91 if (g->node[j].min_index < g->node[i].min_index)
92 g->node[i].min_index = g->node[j].min_index;
93 } else if (g->node[j].index < g->node[i].min_index)
94 g->node[i].min_index = g->node[j].index;
97 if (g->node[i].index != g->node[i].min_index)
98 return isl_stat_ok;
100 do {
101 j = g->stack[--g->sp];
102 g->node[j].on_stack = 0;
103 g->order[g->op++] = j;
104 } while (j != i);
105 g->order[g->op++] = -1;
107 return isl_stat_ok;
110 /* Decompose the graph with "len" nodes and edges defined by "follows"
111 * into strongly connected components (SCCs).
112 * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise.
113 * It should return -1 on error.
115 * If SCC a contains a node i that follows a node j in another SCC b
116 * (i.e., follows(i, j, user) returns 1), then SCC a will appear after SCC b
117 * in the result.
119 struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len,
120 isl_bool (*follows)(int i, int j, void *user), void *user)
122 int i;
123 struct isl_tarjan_graph *g = NULL;
125 g = isl_tarjan_graph_alloc(ctx, len);
126 if (!g)
127 return NULL;
128 for (i = len - 1; i >= 0; --i) {
129 if (g->node[i].index >= 0)
130 continue;
131 if (isl_tarjan_components(g, i, follows, user) < 0)
132 return isl_tarjan_graph_free(g);
135 return g;
138 /* Decompose the graph with "len" nodes and edges defined by "follows"
139 * into the strongly connected component (SCC) that contains "node"
140 * as well as all SCCs that are followed by this SCC.
141 * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise.
142 * It should return -1 on error.
144 * The SCC containing "node" will appear as the last component
145 * in g->order.
147 struct isl_tarjan_graph *isl_tarjan_graph_component(isl_ctx *ctx, int len,
148 int node, isl_bool (*follows)(int i, int j, void *user), void *user)
150 struct isl_tarjan_graph *g;
152 g = isl_tarjan_graph_alloc(ctx, len);
153 if (!g)
154 return NULL;
155 if (isl_tarjan_components(g, node, follows, user) < 0)
156 return isl_tarjan_graph_free(g);
158 return g;