Graphviz 14.1.0
Loading...
Searching...
No Matches
ccomps.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include <cgraph/cgraph.h>
12#include <common/render.h>
13#include <common/utils.h>
14#include <limits.h>
15#include <pack/pack.h>
16#include <stdbool.h>
17#include <stdlib.h>
18#include <util/agxbuf.h>
19#include <util/alloc.h>
20#include <util/gv_ctype.h>
21#include <util/list.h>
22#include <util/prisize_t.h>
23
24typedef LIST(Agnode_t *) node_stack_t;
25
26typedef struct {
27 node_stack_t data;
28 void (*actionfn)(Agnode_t *, void *);
29 bool (*markfn)(Agnode_t *, int);
31
33static bool marked(const stk_t *stk, Agnode_t *n) { return stk->markfn(n, -1); }
34
36static void mark(const stk_t *stk, Agnode_t *n) { stk->markfn(n, 1); }
37
39static void unmark(const stk_t *stk, Agnode_t *n) { stk->markfn(n, 0); }
40
41static stk_t initStk(void (*actionfn)(Agnode_t *, void *),
42 bool (*markfn)(Agnode_t *, int)) {
43 return (stk_t){.actionfn = actionfn, .markfn = markfn};
44}
45
46static void freeStk(stk_t *sp) { LIST_FREE(&sp->data); }
47
48static void push(stk_t *sp, Agnode_t *np) {
49 mark(sp, np);
50 LIST_PUSH_BACK(&sp->data, np);
51}
52
53static Agnode_t *pop(stk_t *sp) {
54 if (LIST_IS_EMPTY(&sp->data)) {
55 return NULL;
56 }
57
58 return LIST_POP_BACK(&sp->data);
59}
60
61static size_t dfs(Agraph_t *g, Agnode_t *n, void *state, stk_t *stk) {
62 Agedge_t *e;
63 Agnode_t *other;
64 size_t cnt = 0;
65
66 push(stk, n);
67 while ((n = pop(stk))) {
68 cnt++;
69 if (stk->actionfn)
70 stk->actionfn(n, state);
71 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
72 if ((other = agtail(e)) == n)
73 other = aghead(e);
74 if (!marked(stk, other))
75 push(stk, other);
76 }
77 }
78 return cnt;
79}
80
81static bool isLegal(const char *p) {
82 char c;
83
84 while ((c = *p++)) {
85 if (c != '_' && !gv_isalnum(c))
86 return false;
87 }
88
89 return true;
90}
91
92static void insertFn(Agnode_t *n, void *state) { agsubnode(state, n, 1); }
93
94static bool markFn(Agnode_t *n, int v) {
95 if (v < 0)
96 return ND_mark(n) != 0;
97 const size_t ret = ND_mark(n);
98 ND_mark(n) = v != 0;
99 return ret != 0;
100}
101
102static void setPrefix(agxbuf *xb, const char *pfx) {
103 if (!pfx || !isLegal(pfx)) {
104 pfx = "_cc_";
105 }
106 agxbput(xb, pfx);
107}
108
109/* pccomps:
110 * Return an array of subgraphs consisting of the connected
111 * components of graph g. The number of components is returned in ncc.
112 * All pinned nodes are in one component.
113 * If pfx is non-null and a legal graph name, we use it as the prefix
114 * for the name of the subgraphs created. If not, a simple default is used.
115 * If pinned is non-null, *pinned set to 1 if pinned nodes found
116 * and the first component is the one containing the pinned nodes.
117 * Note that the component subgraphs do not contain any edges. These must
118 * be obtained from the root graph.
119 * Return NULL if graph is empty.
120 */
121Agraph_t **pccomps(Agraph_t *g, size_t *ncc, char *pfx, bool *pinned) {
122 agxbuf name = {0};
123 Agraph_t *out = NULL;
124 Agnode_t *n;
125 bool pin = false;
126
127 if (agnnodes(g) == 0) {
128 *ncc = 0;
129 return NULL;
130 }
131
132 LIST(Agraph_t *) ccs = {0};
133
135 for (n = agfstnode(g); n; n = agnxtnode(g, n))
136 unmark(&stk, n);
137
138 /* Component with pinned nodes */
139 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
140 if (marked(&stk, n) || !isPinned(n))
141 continue;
142 if (!out) {
143 setPrefix(&name, pfx);
144 agxbprint(&name, "%" PRISIZE_T, LIST_SIZE(&ccs));
145 out = agsubg(g, agxbuse(&name), 1);
146 agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t),
147 true); // node custom data
148 LIST_APPEND(&ccs, out);
149 pin = true;
150 }
151 dfs(g, n, out, &stk);
152 }
153
154 /* Remaining nodes */
155 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
156 if (marked(&stk, n))
157 continue;
158 setPrefix(&name, pfx);
159 agxbprint(&name, "%" PRISIZE_T, LIST_SIZE(&ccs));
160 out = agsubg(g, agxbuse(&name), 1);
161 agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t),
162 true); // node custom data
163 dfs(g, n, out, &stk);
164 LIST_APPEND(&ccs, out);
165 }
166 freeStk(&stk);
167 agxbfree(&name);
168 *pinned = pin;
169 Agraph_t **ret;
170 LIST_DETACH(&ccs, &ret, ncc);
171 return ret;
172}
173
174/* ccomps:
175 * Return an array of subgraphs consisting of the connected
176 * components of graph g. The number of components is returned in ncc.
177 * If pfx is non-null and a legal graph name, we use it as the prefix
178 * for the name of the subgraphs created. If not, a simple default is used.
179 * Note that the component subgraphs do not contain any edges. These must
180 * be obtained from the root graph.
181 * Returns NULL on error or if graph is empty.
182 */
183Agraph_t **ccomps(Agraph_t *g, size_t *ncc, char *pfx) {
184 agxbuf name = {0};
185 Agraph_t *out;
186 Agnode_t *n;
187
188 if (agnnodes(g) == 0) {
189 *ncc = 0;
190 return NULL;
191 }
192
193 LIST(Agraph_t *) ccs = {0};
195 for (n = agfstnode(g); n; n = agnxtnode(g, n))
196 unmark(&stk, n);
197
198 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
199 if (marked(&stk, n))
200 continue;
201 setPrefix(&name, pfx);
202 agxbprint(&name, "%" PRISIZE_T, LIST_SIZE(&ccs));
203 out = agsubg(g, agxbuse(&name), 1);
204 agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t),
205 true); // node custom data
206 dfs(g, n, out, &stk);
207 LIST_APPEND(&ccs, out);
208 }
209 freeStk(&stk);
210 agxbfree(&name);
211 Agraph_t **ret;
212 LIST_DETACH(&ccs, &ret, ncc);
213 return ret;
214}
215
216typedef struct {
218 char cc_subg; /* true iff subgraph corresponds to a component */
220
221typedef struct {
223 char mark;
224 union {
227 void *v;
228 } ptr;
230
231#define GRECNAME "ccgraphinfo"
232#define NRECNAME "ccgnodeinfo"
233#define GD_cc_subg(g) (((ccgraphinfo_t *)aggetrec(g, GRECNAME, 0))->cc_subg)
234#ifdef DEBUG
237 if (ip)
238 return ip->ptr.n;
239 fprintf(stderr, "nodeinfo undefined\n");
240 return NULL;
241}
242void dnodeSet(Agnode_t *v, Agnode_t *n) {
243 ((ccgnodeinfo_t *)aggetrec(v, NRECNAME, 0))->ptr.n = n;
244}
245#else
246#define dnodeOf(v) (((ccgnodeinfo_t *)aggetrec(v, NRECNAME, 0))->ptr.n)
247#define dnodeSet(v, w) (((ccgnodeinfo_t *)aggetrec(v, NRECNAME, 0))->ptr.n = w)
248#endif
249
250#define ptrOf(np) (((ccgnodeinfo_t *)((np)->base.data))->ptr.v)
251#define nodeOf(np) (((ccgnodeinfo_t *)((np)->base.data))->ptr.n)
252#define clustOf(np) (((ccgnodeinfo_t *)((np)->base.data))->ptr.g)
253#define clMark(n) (((ccgnodeinfo_t *)(n->base.data))->mark)
254
255/* deriveClusters:
256 * Construct nodes in derived graph corresponding top-level clusters.
257 * Since a cluster might be wrapped in a subgraph, we need to traverse
258 * down into the tree of subgraphs
259 */
260static void deriveClusters(Agraph_t *dg, Agraph_t *g) {
261 Agraph_t *subg;
262 Agnode_t *dn;
263 Agnode_t *n;
264
265 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
266 if (is_a_cluster(subg)) {
267 dn = agnode(dg, agnameof(subg), 1);
268 agbindrec(dn, NRECNAME, sizeof(ccgnodeinfo_t), true);
269 clustOf(dn) = subg;
270 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
271 if (dnodeOf(n)) {
272 fprintf(stderr,
273 "Error: node \"%s\" belongs to two non-nested clusters "
274 "\"%s\" and \"%s\"\n",
275 agnameof(n), agnameof(subg), agnameof(dnodeOf(n)));
276 }
277 dnodeSet(n, dn);
278 }
279 } else {
280 deriveClusters(dg, subg);
281 }
282 }
283}
284
285/* deriveGraph:
286 * Create derived graph dg of g where nodes correspond to top-level nodes
287 * or clusters, and there is an edge in dg if there is an edge in g
288 * between any nodes in the respective clusters.
289 */
291 Agraph_t *dg;
292 Agnode_t *dn;
293 Agnode_t *n;
294
295 dg = agopen("dg", Agstrictundirected, NULL);
296
297 deriveClusters(dg, g);
298
299 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
300 if (dnodeOf(n))
301 continue;
302 dn = agnode(dg, agnameof(n), 1);
303 agbindrec(dn, NRECNAME, sizeof(ccgnodeinfo_t), true);
304 nodeOf(dn) = n;
305 dnodeSet(n, dn);
306 }
307
308 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
309 Agedge_t *e;
310 Agnode_t *hd;
311 Agnode_t *tl = dnodeOf(n);
312 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
313 hd = aghead(e);
314 hd = dnodeOf(hd);
315 if (hd == tl)
316 continue;
317 if (hd > tl)
318 agedge(dg, tl, hd, NULL, 1);
319 else
320 agedge(dg, hd, tl, NULL, 1);
321 }
322 }
323
324 return dg;
325}
326
327/* unionNodes:
328 * Add all nodes in cluster nodes of dg to g
329 */
330static void unionNodes(Agraph_t *dg, Agraph_t *g) {
331 Agnode_t *n;
332 Agnode_t *dn;
333 Agraph_t *clust;
334
335 for (dn = agfstnode(dg); dn; dn = agnxtnode(dg, dn)) {
336 if (AGTYPE(ptrOf(dn)) == AGNODE) {
337 agsubnode(g, nodeOf(dn), 1);
338 } else {
339 clust = clustOf(dn);
340 for (n = agfstnode(clust); n; n = agnxtnode(clust, n))
341 agsubnode(g, n, 1);
342 }
343 }
344}
345
346static bool clMarkFn(Agnode_t *n, int v) {
347 int ret;
348 if (v < 0)
349 return clMark(n) != 0;
350 ret = clMark(n);
351 clMark(n) = (char)v;
352 return ret != 0;
353}
354
355typedef struct {
358} orig_t;
359
360#define ORIG_REC "orig"
361
363 orig_t *op = (orig_t *)aggetrec(cl, ORIG_REC, 0);
364 assert(op);
365 return op->orig;
366}
367
368/* projectG:
369 * If any nodes of subg are in g, create a subgraph of g
370 * and fill it with all nodes of subg in g and their induced
371 * edges in subg. Copy the attributes of subg to g. Return the subgraph.
372 * If not, return null.
373 * If subg is a cluster, the new subgraph will contain a pointer to it
374 * in the record "orig".
375 */
376static Agraph_t *projectG(Agraph_t *subg, Agraph_t *g, int inCluster) {
377 Agraph_t *proj = NULL;
378 Agnode_t *n;
379 Agnode_t *m;
380 orig_t *op;
381
382 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
383 if ((m = agfindnode(g, agnameof(n)))) {
384 if (proj == NULL) {
385 proj = agsubg(g, agnameof(subg), 1);
386 }
387 agsubnode(proj, m, 1);
388 }
389 }
390 if (!proj && inCluster) {
391 proj = agsubg(g, agnameof(subg), 1);
392 }
393 if (proj) {
394 (void)graphviz_node_induce(proj, subg);
395 agcopyattr(subg, proj);
396 if (is_a_cluster(proj)) {
397 op = agbindrec(proj, ORIG_REC, sizeof(orig_t), false);
398 op->orig = subg;
399 }
400 }
401
402 return proj;
403}
404
405/* subgInduce:
406 * Project subgraphs of root graph on subgraph.
407 * If non-empty, add to subgraph.
408 */
409static void subgInduce(Agraph_t *root, Agraph_t *g, int inCluster) {
410 Agraph_t *subg;
411 Agraph_t *proj;
412 int in_cluster;
413
414 for (subg = agfstsubg(root); subg; subg = agnxtsubg(subg)) {
415 if (GD_cc_subg(subg))
416 continue;
417 if ((proj = projectG(subg, g, inCluster))) {
418 in_cluster = (inCluster || is_a_cluster(subg));
419 subgInduce(subg, proj, in_cluster);
420 }
421 }
422}
423
424static void subGInduce(Agraph_t *g, Agraph_t *out) { subgInduce(g, out, 0); }
425
426/* cccomps:
427 * Decompose g into "connected" components, where nodes are connected
428 * either by an edge or by being in the same cluster. The components
429 * are returned in an array of subgraphs. ncc indicates how many components
430 * there are. The subgraphs use the prefix pfx in their names, if non-NULL.
431 * Note that cluster subgraph of the main graph, corresponding to a component,
432 * is cloned within the subgraph. Each cloned cluster contains a record pointing
433 * to the real cluster.
434 */
435Agraph_t **cccomps(Agraph_t *g, size_t *ncc, char *pfx) {
436 Agraph_t *dg;
437 size_t n_cnt, e_cnt;
438 agxbuf name = {0};
439 Agraph_t *out;
440 Agraph_t *dout;
441 Agnode_t *dn;
442 int sz = (int)sizeof(ccgraphinfo_t);
443
444 if (agnnodes(g) == 0) {
445 *ncc = 0;
446 return NULL;
447 }
448
449 /* Bind ccgraphinfo to graph and all subgraphs */
450 aginit(g, AGRAPH, GRECNAME, -sz, false);
451
452 /* Bind ccgraphinfo to graph and all subgraphs */
453 aginit(g, AGNODE, NRECNAME, sizeof(ccgnodeinfo_t), false);
454
455 dg = deriveGraph(g);
456
457 size_t ccs_length = (size_t)agnnodes(dg);
458 LIST(Agraph_t *) ccs = {0};
459 LIST_RESERVE(&ccs, ccs_length);
461
462 for (dn = agfstnode(dg); dn; dn = agnxtnode(dg, dn)) {
463 if (marked(&stk, dn))
464 continue;
465 setPrefix(&name, pfx);
466 agxbprint(&name, "%" PRISIZE_T, LIST_SIZE(&ccs));
467 char *name_str = agxbuse(&name);
468 dout = agsubg(dg, name_str, 1);
469 out = agsubg(g, name_str, 1);
470 agbindrec(out, GRECNAME, sizeof(ccgraphinfo_t), false);
471 GD_cc_subg(out) = 1;
472 n_cnt = dfs(dg, dn, dout, &stk);
473 unionNodes(dout, out);
474 e_cnt = graphviz_node_induce(out, NULL);
475 subGInduce(g, out);
476 LIST_APPEND(&ccs, out);
477 agdelete(dg, dout);
478 if (Verbose)
479 fprintf(stderr,
480 "(%4" PRISIZE_T ") %7" PRISIZE_T " nodes %7" PRISIZE_T " edges\n",
481 LIST_SIZE(&ccs) - 1, n_cnt, e_cnt);
482 }
483
484 if (Verbose)
485 fprintf(stderr,
486 " %7d nodes %7d edges %7" PRISIZE_T " components %s\n",
487 agnnodes(g), agnedges(g), LIST_SIZE(&ccs), agnameof(g));
488
489 agclose(dg);
492 freeStk(&stk);
493 agxbfree(&name);
494 Agraph_t **ret;
495 LIST_DETACH(&ccs, &ret, ncc);
496 return ret;
497}
498
499/* isConnected:
500 * Returns 1 if the graph is connected.
501 * Returns 0 if the graph is not connected.
502 * Returns -1 if the graph is error.
503 */
505 if (agnnodes(g) == 0)
506 return 1;
507
508 stk_t stk = initStk(NULL, markFn);
509 for (Agnode_t *n = agfstnode(g); n; n = agnxtnode(g, n))
510 unmark(&stk, n);
511
512 const size_t cnt = dfs(g, agfstnode(g), NULL, &stk);
513 freeStk(&stk);
514 if (cnt != (size_t)agnnodes(g))
515 return 0;
516 return 1;
517}
static void out(agerrlevel_t level, const char *fmt, va_list args)
Report messages using a user-supplied or default write function.
Definition agerror.c:84
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:97
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:252
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:325
Memory allocation wrappers that exit on failure.
abstract graph C library, Cgraph API
static Agnode_t * pop(void)
Definition ccomps.c:220
static void deriveClusters(Agraph_t *dg, Agraph_t *g)
Definition ccomps.c:335
static Agraph_t * deriveGraph(Agraph_t *g)
Definition ccomps.c:360
static void unionNodes(Agraph_t *dg, Agraph_t *g)
add all nodes in cluster nodes of dg to g
Definition ccomps.c:391
static Agraph_t * projectG(Agraph_t *subg, Agraph_t *g, int inCluster)
Definition ccomps.c:286
static void subGInduce(Agraph_t *g, Agraph_t *out)
Definition ccomps.c:326
static void subgInduce(Agraph_t *root, Agraph_t *g, int inCluster)
Definition ccomps.c:313
static int dfs(Agraph_t *g, Agnode_t *n, Agraph_t *out)
Definition ccomps.c:227
#define GD_cc_subg(g)
Definition ccomps.c:51
bool is_a_cluster(Agraph_t *g)
Definition utils.c:693
static bool Verbose
Definition gml2gv.c:24
static gstack_t * push(gstack_t *s, Agraph_t *subg)
Definition grammar.c:1655
node NULL
Definition grammar.y:181
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:196
int agnedges(Agraph_t *g)
Definition graph.c:161
int agnnodes(Agraph_t *g)
Definition graph.c:155
size_t graphviz_node_induce(Agraph_t *g, Agraph_t *edgeset)
Definition node_induce.c:9
int agcopyattr(void *oldobj, void *newobj)
copies all of the attributes from one object to another
Definition attr.c:633
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition edge.c:253
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:26
#define agtail(e)
Definition cgraph.h:977
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:96
#define aghead(e)
Definition cgraph.h:978
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:41
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:87
Agdesc_t Agstrictundirected
strict undirected
Definition graph.c:273
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:95
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
creates a new graph with the given name and kind
Definition graph.c:42
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:141
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:48
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:41
Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
Definition node.c:252
#define agfindnode(g, n)
Definition types.h:611
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:143
#define AGTYPE(obj)
returns AGRAPH, AGNODE, or AGEDGE depending on the type of the object
Definition cgraph.h:216
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
Definition obj.c:20
@ AGNODE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
Agrec_t * aggetrec(void *obj, const char *name, int move_to_front)
find record in circular list and do optional move-to-front and lock
Definition rec.c:41
void aginit(Agraph_t *g, int kind, const char *rec_name, int rec_size, int move_to_front)
attach new records to objects of specified kind
Definition rec.c:170
void * agbindrec(void *obj, const char *name, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
Definition rec.c:89
void agclean(Agraph_t *g, int kind, char *rec_name)
calls agdelrec for all objects of the same class in an entire graph
Definition rec.c:202
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:73
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:78
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:53
replacements for ctype.h functions
static bool gv_isalnum(int c)
Definition gv_ctype.h:43
agxbput(xb, staging)
#define ND_mark(n)
Definition acyclic.c:28
static void unmark(const stk_t *stk, Agnode_t *n)
unset a mark on n
Definition ccomps.c:39
static bool marked(const stk_t *stk, Agnode_t *n)
does n have a mark set?
Definition ccomps.c:33
#define clMark(n)
Definition ccomps.c:253
static void freeStk(stk_t *sp)
Definition ccomps.c:46
Agraph_t ** pccomps(Agraph_t *g, size_t *ncc, char *pfx, bool *pinned)
Definition ccomps.c:121
static void setPrefix(agxbuf *xb, const char *pfx)
Definition ccomps.c:102
#define dnodeOf(v)
Definition ccomps.c:246
static void mark(const stk_t *stk, Agnode_t *n)
set a mark on n
Definition ccomps.c:36
static void insertFn(Agnode_t *n, void *state)
Definition ccomps.c:92
static bool markFn(Agnode_t *n, int v)
Definition ccomps.c:94
#define GRECNAME
Definition ccomps.c:231
#define nodeOf(np)
Definition ccomps.c:251
#define ORIG_REC
Definition ccomps.c:360
Agraph_t ** ccomps(Agraph_t *g, size_t *ncc, char *pfx)
Definition ccomps.c:183
static stk_t initStk(void(*actionfn)(Agnode_t *, void *), bool(*markfn)(Agnode_t *, int))
Definition ccomps.c:41
int isConnected(Agraph_t *g)
Definition ccomps.c:504
Agraph_t ** cccomps(Agraph_t *g, size_t *ncc, char *pfx)
Definition ccomps.c:435
#define clustOf(np)
Definition ccomps.c:252
stk_t
Definition ccomps.c:30
static bool clMarkFn(Agnode_t *n, int v)
Definition ccomps.c:346
static bool isLegal(const char *p)
Definition ccomps.c:81
#define dnodeSet(v, w)
Definition ccomps.c:247
#define NRECNAME
Definition ccomps.c:232
#define ptrOf(np)
Definition ccomps.c:250
Agraph_t * mapClust(Agraph_t *cl)
Definition ccomps.c:362
type-generic dynamically expanding list
#define LIST_DETACH(list, datap, sizep)
Definition list.h:443
#define LIST(type)
Definition list.h:55
#define LIST_SIZE(list)
Definition list.h:80
#define LIST_APPEND(list, item)
Definition list.h:120
#define LIST_FREE(list)
Definition list.h:370
#define LIST_RESERVE(list, capacity)
Definition list.h:257
#define LIST_POP_BACK(list)
Definition list.h:407
#define LIST_IS_EMPTY(list)
Definition list.h:90
#define LIST_PUSH_BACK(list, item)
Definition list.h:384
#define isPinned(n)
Definition macros.h:17
support for connected components
#define PRISIZE_T
Definition prisize_t.h:25
graph or subgraph
Definition cgraph.h:424
implementation of Agrec_t
Definition cgraph.h:172
Agrec_t h
Definition ccomps.c:222
union ccgnodeinfo_t::@77 ptr
Agraph_t * g
Definition ccomps.c:225
void * v
Definition ccomps.c:227
Agnode_t * n
Definition ccomps.c:226
char cc_subg
Definition ccomps.c:218
Agrec_t h
Definition ccomps.c:217
Agrec_t h
Definition ccomps.c:356
Agraph_t * orig
Definition ccomps.c:357