Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
graph.c
Go to the documentation of this file.
1
6/*************************************************************************
7 * Copyright (c) 2011 AT&T Intellectual Property
8 * All rights reserved. This program and the accompanying materials
9 * are made available under the terms of the Eclipse Public License v1.0
10 * which accompanies this distribution, and is available at
11 * https://www.eclipse.org/legal/epl-v10.html
12 *
13 * Contributors: Details at https://graphviz.org
14 *************************************************************************/
15
16#include <assert.h>
17#include <cgraph/cghdr.h>
18#include <cgraph/node_set.h>
19#include <limits.h>
20#include <stdbool.h>
21#include <stdlib.h>
22#include <util/alloc.h>
23
25
26/*
27 * this code sets up the resource management discipline
28 * and returns a new main graph struct.
29 */
30static Agclos_t *agclos(Agdisc_t * proto)
31{
32 Agclos_t *rv;
33
34 /* establish an allocation arena */
35 rv = gv_calloc(1, sizeof(Agclos_t));
36 rv->disc.id = ((proto && proto->id) ? proto->id : &AgIdDisc);
37 rv->disc.io = ((proto && proto->io) ? proto->io : &AgIoDisc);
38 return rv;
39}
40
41/*
42 * Open a new main graph with the given descriptor (directed, strict, etc.)
43 */
44Agraph_t *agopen(char *name, Agdesc_t desc, Agdisc_t * arg_disc)
45{
46 Agraph_t *g;
47 Agclos_t *clos;
48 IDTYPE gid;
49
50 clos = agclos(arg_disc);
51 g = gv_calloc(1, sizeof(Agraph_t));
52 AGTYPE(g) = AGRAPH;
53 g->clos = clos;
54 g->desc = desc;
55 g->desc.maingraph = true;
56 g->root = g;
57 g->clos->state.id = g->clos->disc.id->open(g, arg_disc);
58 if (agmapnametoid(g, AGRAPH, name, &gid, true))
59 AGID(g) = gid;
60 g = agopen1(g);
61 agregister(g, AGRAPH, g);
62 return g;
63}
64
65/*
66 * initialize dictionaries, set seq, invoke init method of new graph
67 */
69{
70 Agraph_t *par;
71
73 g->n_id = node_set_new();
77
78 // `agdtopen` has allocated a `Dt_t`, which we now expand to host a
79 // `g_seq_t`. See `g_seq_t` for why we do this odd thing.
80 g->g_seq = gv_realloc(g->g_seq, sizeof(Dt_t), sizeof(g_seq_t));
81
83
84 par = agparent(g);
85 if (par) {
86 uint64_t seq = agnextseq(par, AGRAPH);
87 assert((seq & SEQ_MASK) == seq && "sequence ID overflow");
88 AGSEQ(g) = seq & SEQ_MASK;
89 dtinsert(par->g_seq, g);
90 Agraphs_append(g_seq2(par), g);
91 dtinsert(par->g_id, g);
92 }
93 if (!par || par->desc.has_attrs)
95 agmethod_init(g, g);
96 return g;
97}
98
99/*
100 * Close a graph or subgraph, freeing its storage.
101 */
103{
104 Agraph_t *subg, *next_subg, *par;
105 Agnode_t *n, *next_n;
106
107 par = agparent(g);
108
109 for (subg = agfstsubg(g); subg; subg = next_subg) {
110 next_subg = agnxtsubg(subg);
111 agclose(subg);
112 }
113
114 for (n = agfstnode(g); n; n = next_n) {
115 next_n = agnxtnode(g, n);
116 agdelnode(g, n);
117 }
118
120 agmethod_delete(g, g);
121
122 assert(node_set_is_empty(g->n_id));
123 node_set_free(&g->n_id);
124 assert(dtsize(g->n_seq) == 0);
125 if (agdtclose(g, g->n_seq)) return FAILURE;
126
127 assert(dtsize(g->e_id) == 0);
128 if (agdtclose(g, g->e_id)) return FAILURE;
129 assert(dtsize(g->e_seq) == 0);
130 if (agdtclose(g, g->e_seq)) return FAILURE;
131
132 // needs to be done before closing `g_seq` because `agdtclose(g, g->g_seq)`
133 // deallocates the memory this is hosted in
134 assert(Agraphs_is_empty(g_seq2(g)));
135 Agraphs_free(g_seq2(g));
136
137 assert(dtsize(g->g_seq) == 0);
138 if (agdtclose(g, g->g_seq)) return FAILURE;
139
140 assert(dtsize(g->g_id) == 0);
141 if (agdtclose(g, g->g_id)) return FAILURE;
142
143 if (g->desc.has_attrs)
144 if (agraphattr_delete(g)) return FAILURE;
145 agrecclose((Agobj_t *) g);
146 agfreeid(g, AGRAPH, AGID(g));
147
148 if (par) {
149 agdelsubg(par, g);
150 free(g);
151 } else {
152 void *clos;
153 while (g->clos->cb)
154 agpopdisc(g, g->clos->cb->f);
155 AGDISC(g, id)->close(AGCLOS(g, id));
156 if (agstrclose(g)) return FAILURE;
157 clos = g->clos;
158 free(g);
159 free(clos);
160 }
161 return SUCCESS;
162}
163
164uint64_t agnextseq(Agraph_t * g, int objtype)
165{
166 return ++(g->clos->seq[objtype]);
167}
168
170{
171 assert(node_set_size(g->n_id) <= INT_MAX);
172 return (int)node_set_size(g->n_id);
173}
174
176{
177 Agnode_t *n;
178 int rv = 0;
179
180 for (n = agfstnode(g); n; n = agnxtnode(g, n))
181 rv += agdegree(g, n, 0, 1); /* must use OUT to get self-arcs */
182 return rv;
183}
184
186{
187 return dtsize(g->g_seq);
188}
189
191{
192 return g->desc.directed;
193}
194
196{
197 return !agisdirected(g);
198}
199
201{
202 return g->desc.strict;
203}
204
206{
207 return (g->desc.strict && g->desc.no_loop);
208}
209
210static int cnt(Dict_t * d, Dtlink_t ** set)
211{
212 int rv;
213 dtrestore(d, *set);
214 rv = dtsize(d);
215 *set = dtextract(d);
216 return rv;
217}
218
219int agcountuniqedges(Agraph_t * g, Agnode_t * n, int want_in, int want_out)
220{
221 Agedge_t *e;
222 Agsubnode_t *sn;
223 int rv = 0;
224
225 sn = agsubrep(g, n);
226 if (want_out) rv = cnt(g->e_seq,&(sn->out_seq));
227 if (want_in) {
228 if (!want_out) rv += cnt(g->e_seq,&(sn->in_seq)); /* cheap */
229 else { /* less cheap */
230 for (e = agfstin(g, n); e; e = agnxtin(g, e))
231 if (e->node != n) rv++; /* don't double count loops */
232 }
233 }
234 return rv;
235}
236
237int agdegree(Agraph_t * g, Agnode_t * n, int want_in, int want_out)
238{
239 Agsubnode_t *sn;
240 int rv = 0;
241
242 sn = agsubrep(g, n);
243 if (sn) {
244 if (want_out) rv += cnt(g->e_seq,&(sn->out_seq));
245 if (want_in) rv += cnt(g->e_seq,&(sn->in_seq));
246 }
247 return rv;
248}
249
250static int agraphseqcmpf(void *arg0, void *arg1) {
251 Agraph_t *sg0 = arg0;
252 Agraph_t *sg1 = arg1;
253 if (AGSEQ(sg0) < AGSEQ(sg1)) {
254 return -1;
255 }
256 if (AGSEQ(sg0) > AGSEQ(sg1)) {
257 return 1;
258 }
259 return 0;
260}
261
262static int agraphidcmpf(void *arg0, void *arg1) {
263 Agraph_t *sg0 = arg0;
264 Agraph_t *sg1 = arg1;
265 if (AGID(sg0) < AGID(sg1)) {
266 return -1;
267 }
268 if (AGID(sg0) > AGID(sg1)) {
269 return 1;
270 }
271 return 0;
272}
273
275 .link = offsetof(Agraph_t, seq_link), // link offset
276 .comparf = agraphseqcmpf,
277};
278
280 .link = offsetof(Agraph_t, id_link), // link offset
281 .comparf = agraphidcmpf,
282};
283
284Agdesc_t Agdirected = {.directed = true, .maingraph = true};
285Agdesc_t Agstrictdirected = {.directed = true, .strict = true, .maingraph = true};
287Agdesc_t Agstrictundirected = {.strict = true, .maingraph = true};
288
290
Memory allocation wrappers that exit on failure.
static void * gv_realloc(void *ptr, size_t old_size, size_t new_size)
Definition alloc.h:49
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
CDT_API Dtlink_t * dtextract(Dt_t *)
Definition dtextract.c:9
CDT_API int dtsize(Dt_t *)
Definition dtsize.c:12
#define dtinsert(d, o)
Definition cdt.h:185
CDT_API Dtmethod_t * Dttree
Definition dttree.c:308
CDT_API int dtrestore(Dt_t *, Dtlink_t *)
Definition dtrestore.c:11
cgraph.h additions
void agfreeid(Agraph_t *g, int objtype, IDTYPE id)
Definition id.c:146
int agstrclose(Agraph_t *g)
Definition refstr.c:64
void aginternalmapclose(Agraph_t *g)
Definition imap.c:196
void agrecclose(Agobj_t *obj)
Definition rec.c:227
Dtdisc_t Ag_subnode_seq_disc
Definition node.c:311
int agmapnametoid(Agraph_t *g, int objtype, char *str, IDTYPE *result, bool createflag)
Definition id.c:112
Dict_t * agdtopen(Agraph_t *g, Dtdisc_t *disc, Dtmethod_t *method)
Definition utils.c:21
static Agraphs_t * g_seq2(Agraph_t *g)
Definition cghdr.h:188
Dtdisc_t Ag_subedge_seq_disc
Definition edge.c:415
#define FAILURE
Definition cghdr.h:45
#define AGDISC(g, d)
Definition cghdr.h:48
Dtdisc_t Ag_mainedge_seq_disc
Definition edge.c:410
void agregister(Agraph_t *g, int objtype, void *obj)
Definition id.c:185
#define SUCCESS
Definition cghdr.h:44
#define AGCLOS(g, d)
Definition cghdr.h:49
Dtdisc_t Ag_subedge_id_disc
Definition edge.c:426
Dtdisc_t Ag_mainedge_id_disc
Definition edge.c:421
@ SEQ_MASK
Definition cghdr.h:77
int agdtclose(Agraph_t *g, Dict_t *dict)
Definition utils.c:32
void node_set_free(node_set_t **self)
Definition node.c:557
size_t node_set_size(const node_set_t *self)
Definition node.c:552
node_set_t * node_set_new(void)
Definition node.c:413
void free(void *)
static int agraphidcmpf(void *arg0, void *arg1)
Definition graph.c:262
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:210
static Agclos_t * agclos(Agdisc_t *proto)
Definition graph.c:30
Agraph_t * agopen1(Agraph_t *g)
Definition graph.c:68
Agraph_t * Ag_G_global
Definition graph.c:24
uint64_t agnextseq(Agraph_t *g, int objtype)
Definition graph.c:164
static int agraphseqcmpf(void *arg0, void *arg1)
Definition graph.c:250
Dtdisc_t Ag_subgraph_seq_disc
Definition graph.c:274
Dtdisc_t Ag_subgraph_id_disc
Definition graph.c:279
int agnsubg(Agraph_t *g)
Definition graph.c:185
int agcountuniqedges(Agraph_t *g, Agnode_t *n, int want_in, int want_out)
Definition graph.c:219
int agnedges(Agraph_t *g)
Definition graph.c:175
int agdegree(Agraph_t *g, Agnode_t *n, int want_in, int want_out)
Definition graph.c:237
int agnnodes(Agraph_t *g)
Definition graph.c:169
void agraphattr_init(Agraph_t *g)
Definition attr.c:370
int agraphattr_delete(Agraph_t *g)
Definition attr.c:381
int agpopdisc(Agraph_t *g, Agcbdisc_t *disc)
Definition obj.c:211
void agmethod_delete(Agraph_t *g, void *obj)
Definition obj.c:138
void agmethod_init(Agraph_t *g, void *obj)
Definition obj.c:78
Agdisc_t AgDefaultDisc
Definition graph.c:289
Agiddisc_t AgIdDisc
Definition id.c:100
Agiodisc_t AgIoDisc
Definition io.c:39
Agedge_t * agnxtin(Agraph_t *g, Agedge_t *e)
Definition edge.c:69
Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
Definition edge.c:55
Agdesc_t Agundirected
undirected
Definition graph.c:286
int agisdirected(Agraph_t *g)
Definition graph.c:190
Agdesc_t Agstrictundirected
strict undirected
Definition graph.c:287
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:102
int agisstrict(Agraph_t *g)
Definition graph.c:200
int agissimple(Agraph_t *g)
Definition graph.c:205
Agdesc_t Agstrictdirected
strict directed. A strict graph cannot have multi-edges or self-arcs.
Definition graph.c:285
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *arg_disc)
creates a new graph with the given name and kind
Definition graph.c:44
int agisundirected(Agraph_t *g)
Definition graph.c:195
Agdesc_t Agdirected
directed
Definition graph.c:284
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
int agdelnode(Agraph_t *g, Agnode_t *arg_n)
removes a node from a graph or subgraph.
Definition node.c:195
Agsubnode_t * agsubrep(Agraph_t *g, Agnode_t *n)
Definition edge.c:145
#define AGID(obj)
returns the unique integer ID associated with the object
Definition cgraph.h:221
uint64_t IDTYPE
unique per main graph ID
Definition cgraph.h:73
#define AGTYPE(obj)
returns AGRAPH, AGNODE, or AGEDGE depending on the type of the object
Definition cgraph.h:216
Agraph_t * agroot(void *obj)
Definition obj.c:168
#define AGSEQ(obj)
Definition cgraph.h:225
@ AGRAPH
Definition cgraph.h:207
Agraph_t * agparent(Agraph_t *g)
Definition subg.c:91
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:78
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:83
int agdelsubg(Agraph_t *g, Agraph_t *sub)
Definition subg.c:99
unordered set of Agsubnode_t *
static bool node_set_is_empty(const node_set_t *self)
Definition node_set.h:55
Agcbdisc_t * f
Definition cgraph.h:400
shared resources for Agraph_s
Definition cgraph.h:411
Agdisc_t disc
Definition cgraph.h:412
Agdstate_t state
Definition cgraph.h:413
Agcbstack_t * cb
Definition cgraph.h:416
uint64_t seq[3]
Definition cgraph.h:415
graph descriptor
Definition cgraph.h:284
unsigned has_attrs
Definition cgraph.h:290
unsigned maingraph
Definition cgraph.h:288
unsigned no_loop
Definition cgraph.h:287
unsigned strict
Definition cgraph.h:286
unsigned directed
Definition cgraph.h:285
user's discipline
Definition cgraph.h:337
Agiddisc_t * id
Definition cgraph.h:338
Agiodisc_t * io
Definition cgraph.h:339
void * id
Definition cgraph.h:364
Agnode_t * node
Definition cgraph.h:272
void *(* open)(Agraph_t *g, Agdisc_t *)
Definition cgraph.h:317
a generic header of Agraph_s, Agnode_s and Agedge_s
Definition cgraph.h:210
graph or subgraph
Definition cgraph.h:425
struct graphviz_node_set * n_id
the node set indexed by ID
Definition cgraph.h:431
Dict_t * g_seq
Definition cgraph.h:433
Agraph_t * root
subgraphs - ancestors
Definition cgraph.h:434
Dict_t * g_id
subgraphs - descendants
Definition cgraph.h:433
Dict_t * e_seq
Definition cgraph.h:432
Dict_t * n_seq
the node set in sequence
Definition cgraph.h:430
Agclos_t * clos
shared resources
Definition cgraph.h:435
Agdesc_t desc
Definition cgraph.h:427
Dict_t * e_id
holders for edge sets
Definition cgraph.h:432
This is the node struct allocated per graph (or subgraph).
Definition cgraph.h:251
Dtlink_t * out_seq
Definition cgraph.h:256
Dtlink_t * in_seq
Definition cgraph.h:256
Definition cdt.h:100
int link
Definition cdt.h:87