Graphviz 12.0.1~dev.20240715.2254
Loading...
Searching...
No Matches
rec.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 <cgraph/cghdr.h>
17#include <cgraph/streq.h>
18#include <cgraph/unreachable.h>
19#include <stdbool.h>
20#include <stddef.h>
21
22/*
23 * run time records
24 */
25
26static void set_data(Agobj_t * obj, Agrec_t * data, bool mtflock)
27{
28 Agedge_t *e;
29
30 obj->data = data;
31 obj->tag.mtflock = mtflock;
32 if (AGTYPE(obj) == AGINEDGE || AGTYPE(obj) == AGOUTEDGE) {
33 e = agopp((Agedge_t *) obj);
34 AGDATA(e) = data;
35 e->base.tag.mtflock = mtflock;
36 }
37}
38
39/* find record in circular list and do optional move-to-front */
40Agrec_t *aggetrec(void *obj, const char *name, int mtf)
41{
42 Agobj_t *hdr;
43 Agrec_t *d, *first;
44
45 hdr = obj;
46 first = d = hdr->data;
47 while (d && !streq(name, d->name)) {
48 d = d->next;
49 if (d == first)
50 return NULL;
51 }
52 if (!d)
53 return NULL;
54
55 if (hdr->tag.mtflock) {
56 if (mtf && hdr->data != d)
57 agerrorf("move to front lock inconsistency");
58 } else if (d != first || mtf != 0) {
59 set_data(hdr, d, mtf != 0); /* Always optimize */
60 }
61 return d;
62}
63
64/* insert the record in data list of this object (only) */
65static void objputrec(Agobj_t * obj, void *arg)
66{
67 Agrec_t *firstrec, *newrec;
68
69 newrec = arg;
70 firstrec = obj->data;
71 if (firstrec == NULL)
72 newrec->next = newrec; /* 0 elts */
73 else {
74 if (firstrec->next == firstrec) {
75 firstrec->next = newrec; /* 1 elt */
76 newrec->next = firstrec;
77 } else {
78 newrec->next = firstrec->next;
79 firstrec->next = newrec;
80 }
81 }
82 if (!obj->tag.mtflock)
83 set_data(obj, newrec, false);
84}
85
86/* attach a new record of the given size to the object.
87 */
88void *agbindrec(void *arg_obj, const char *recname, unsigned int recsize,
89 int move_to_front)
90{
91 Agraph_t *g;
92 Agobj_t *obj;
93
94 obj = arg_obj;
95 g = agraphof(obj);
96 Agrec_t *rec = aggetrec(obj, recname, 0);
97 if (rec == NULL && recsize > 0) {
98 rec = agalloc(g, recsize);
99 rec->name = agstrdup(g, recname);
100 objputrec(obj, rec);
101 }
102 if (move_to_front)
103 aggetrec(arg_obj, recname, 1);
104 return rec;
105}
106
107
108/* if obj points to rec, move its data pointer. break any mtf lock(?) */
109static void objdelrec(Agraph_t * g, Agobj_t * obj, void *arg_rec)
110{
111 (void)g;
112 Agrec_t *rec = arg_rec, *newrec;
113 if (obj->data == rec) {
114 if (rec->next == rec)
115 newrec = NULL;
116 else
117 newrec = rec->next;
118 set_data(obj, newrec, false);
119 }
120}
121
122/* delete a record from a circular data list */
123static void listdelrec(Agobj_t * obj, Agrec_t * rec)
124{
125 Agrec_t *prev;
126
127 prev = obj->data;
128 while (prev->next != rec) {
129 prev = prev->next;
130 assert(prev != obj->data);
131 }
132 /* following is a harmless no-op if the list is trivial */
133 prev->next = rec->next;
134}
135
136int agdelrec(void *arg_obj, const char *name)
137{
138 Agobj_t *obj = arg_obj;
139 Agraph_t *g = agraphof(obj);
140 Agrec_t *rec = aggetrec(obj, name, 0);
141 if (!rec)
142 return FAILURE;
143
144 listdelrec(obj, rec); /* zap it from the circular list */
145 switch (obj->tag.objtype) { /* refresh any stale pointers */
146 case AGRAPH:
147 objdelrec(g, obj, rec);
148 break;
149 case AGNODE:
150 case AGINEDGE:
151 case AGOUTEDGE:
152 agapply(agroot(g), obj, objdelrec, rec, false);
153 break;
154 default:
155 UNREACHABLE();
156 }
157 agstrfree(g, rec->name);
158 agfree(g, rec);
159
160 return SUCCESS;
161}
162
163static void simple_delrec(Agraph_t * g, Agobj_t * obj, void *rec_name)
164{
165 (void)g;
166 agdelrec(obj, rec_name);
167}
168
169void aginit(Agraph_t * g, int kind, const char *rec_name, int arg_rec_size,
170 int mtf) {
171 Agnode_t *n;
172 Agedge_t *e;
173 Agraph_t *s;
174 unsigned int rec_size;
175 bool recur = arg_rec_size < 0; /* if recursive on subgraphs */
176
177 rec_size = (unsigned int) abs(arg_rec_size);
178 switch (kind) {
179 case AGRAPH:
180 agbindrec(g, rec_name, rec_size, mtf);
181 if (recur)
182 for (s = agfstsubg(g); s; s = agnxtsubg(s))
183 aginit(s,kind,rec_name,arg_rec_size,mtf);
184 break;
185 case AGNODE:
186 case AGOUTEDGE:
187 case AGINEDGE:
188 for (n = agfstnode(g); n; n = agnxtnode(g, n))
189 if (kind == AGNODE)
190 agbindrec(n, rec_name, rec_size, mtf);
191 else {
192 for (e = agfstout(g, n); e; e = agnxtout(g, e))
193 agbindrec(e, rec_name, rec_size, mtf);
194 }
195 break;
196 default:
197 break;
198 }
199}
200
201void agclean(Agraph_t * g, int kind, char *rec_name)
202{
203 Agnode_t *n;
204 Agedge_t *e;
205
206 switch (kind) {
207 case AGRAPH:
208 agapply(g, (Agobj_t *)g, simple_delrec, rec_name, true);
209 break;
210 case AGNODE:
211 case AGOUTEDGE:
212 case AGINEDGE:
213 for (n = agfstnode(g); n; n = agnxtnode(g, n))
214 if (kind == AGNODE)
215 agdelrec(n, rec_name);
216 else {
217 for (e = agfstout(g, n); e; e = agnxtout(g, e))
218 agdelrec(e, rec_name);
219 }
220 break;
221 default:
222 break;
223 }
224}
225
227{
228 Agraph_t *g;
229 Agrec_t *rec, *nrec;
230
231 g = agraphof(obj);
232 if ((rec = obj->data)) {
233 do {
234 nrec = rec->next;
235 agstrfree(g, rec->name);
236 agfree(g, rec);
237 rec = nrec;
238 } while (rec != obj->data);
239 }
240 obj->data = NULL;
241}
int agapply(Agraph_t *g, Agobj_t *obj, agobjfn_t fn, void *arg, int preorder)
Definition apply.c:60
cgraph.h additions
#define FAILURE
Definition cghdr.h:44
#define SUCCESS
Definition cghdr.h:43
node NULL
Definition grammar.y:149
void * agalloc(Agraph_t *g, size_t size)
Definition mem.c:19
void agfree(Agraph_t *g, void *ptr)
Definition mem.c:49
#define agopp(e)
opposite edge: flip Agedgepair_s.out ⇄ Agedgepair_s.in/*#end#*‍/
Definition cgraph.h:891
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:23
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:38
void agerrorf(const char *fmt,...)
Definition agerror.c:165
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
Agraph_t * agraphof(void *obj)
Definition obj.c:184
#define AGDATA(obj)
returns Agrec_t
Definition cgraph.h:227
#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:167
@ AGOUTEDGE
Definition cgraph.h:207
@ AGNODE
Definition cgraph.h:207
@ AGINEDGE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
Agrec_t * aggetrec(void *obj, const char *name, int mtf)
find record in circular list and do optional move-to-front and lock
Definition rec.c:40
void aginit(Agraph_t *g, int kind, const char *rec_name, int arg_rec_size, int mtf)
attach new records to objects of specified kind
Definition rec.c:169
void * agbindrec(void *arg_obj, const char *recname, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
Definition rec.c:88
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:201
int agdelrec(void *arg_obj, const char *name)
deletes a named record from one object
Definition rec.c:136
int agstrfree(Agraph_t *, const char *)
Definition refstr.c:138
char * agstrdup(Agraph_t *, const char *)
returns a pointer to a reference-counted copy of the argument string, creating one if necessary
Definition refstr.c:130
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:77
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:82
static Agdesc_t kind
Definition gvpack.cpp:88
$2 u p prev
Definition htmlparse.y:495
void agrecclose(Agobj_t *obj)
Definition rec.c:226
static void objdelrec(Agraph_t *g, Agobj_t *obj, void *arg_rec)
Definition rec.c:109
static void listdelrec(Agobj_t *obj, Agrec_t *rec)
Definition rec.c:123
static void simple_delrec(Agraph_t *g, Agobj_t *obj, void *rec_name)
Definition rec.c:163
static void objputrec(Agobj_t *obj, void *arg)
Definition rec.c:65
static void set_data(Agobj_t *obj, Agrec_t *data, bool mtflock)
Definition rec.c:26
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
Agobj_t base
Definition cgraph.h:269
a generic header of Agraph_s, Agnode_s and Agedge_s
Definition cgraph.h:210
Agrec_t * data
stores programmer-defined data, access with AGDATA
Definition cgraph.h:212
Agtag_t tag
access with AGTAG
Definition cgraph.h:211
graph or subgraph
Definition cgraph.h:425
implementation of Agrec_t
Definition cgraph.h:172
Agrec_t * next
circular linked list of records
Definition cgraph.h:174
char * name
Definition cgraph.h:173
unsigned objtype
access with AGTYPE
Definition cgraph.h:199
unsigned mtflock
move-to-front lock, guards Agobj_s::data
Definition cgraph.h:200
Definition legal.c:50
Definition grammar.c:93
#define UNREACHABLE()
Definition unreachable.h:30