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