ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/modobject.c
Revision: 2.25
Committed: Sat Jun 21 17:42:17 2025 UTC (4 weeks, 1 day ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.24: +21 -9 lines
Log Message:
perf: Optimized objndx() call with hashed cache table

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: modobject.c,v 2.24 2025/06/21 00:15:30 greg Exp $";
3 #endif
4 /*
5 * Routines for tracking object modifiers
6 *
7 * External symbols declared in object.h
8 */
9
10 #include "copyright.h"
11
12 #include "standard.h"
13 #include "object.h"
14 #include "otypes.h"
15
16
17 static struct ohtab {
18 int hsiz; /* current table size */
19 OBJECT *htab; /* table, if allocated */
20 } modtab = {100, NULL}, objtab = {1000, NULL}; /* modifiers and objects */
21
22 static int otndx(char *, struct ohtab *);
23
24
25 OBJECT
26 objndx( /* get object number from pointer */
27 OBJREC *op
28 )
29 {
30 #ifndef ONCACHESIZ
31 #define ONCACHESIZ 907 /* keep a cache of previous searches */
32 #endif
33 static OBJECT oncache[ONCACHESIZ];
34 const int ent = (size_t)op % ONCACHESIZ;
35 int i;
36 /* clear cache on first call */
37 for (i = ONCACHESIZ*(!oncache[0] & !oncache[1]); i--; )
38 oncache[i] = OVOID;
39 /* is this pointer in cache? */
40 if ((oncache[ent] != OVOID) & (oncache[ent] < nobjects) &&
41 objptr(oncache[ent]) == op)
42 return(oncache[ent]); /* matches previous search */
43 /* else look for allocated block */
44 for (i = (nobjects-1)>>OBJBLKSHFT; i >= 0; i--)
45 if ((objblock[i] <= op) & (op < objblock[i]+OBJBLKSIZ)) {
46 /* found it -- save index to cache */
47 oncache[ent] = ((OBJECT)i << OBJBLKSHFT) +
48 (op - objblock[i]);
49 return(oncache[ent]);
50 }
51 return(OVOID); /* not in our array -- may still be valid */
52 }
53
54
55 OBJECT
56 lastmod( /* find modifier definition before obj */
57 OBJECT obj,
58 char *mname
59 )
60 {
61 OBJREC *op;
62 OBJECT i;
63
64 i = modifier(mname); /* try hash table first */
65 if ((obj == OVOID) | (i < obj))
66 return(i);
67 for (i = obj; i-- > 0; ) { /* need to search */
68 op = objptr(i);
69 if ((ismodifier(op->otype) != 0) & (op->oname[0] == mname[0])
70 && !strcmp(op->oname, mname))
71 return(i);
72 }
73 return(OVOID);
74 }
75
76
77 OBJECT
78 modifier( /* get a modifier number from its name */
79 char *mname
80 )
81 {
82 int ndx;
83
84 ndx = otndx(mname, &modtab);
85 return(modtab.htab[ndx]);
86 }
87
88
89 #ifdef GETOBJ
90 OBJECT
91 object( /* get an object number from its name */
92 char *oname
93 )
94 {
95 int ndx;
96
97 ndx = otndx(oname, &objtab);
98 return(objtab.htab[ndx]);
99 }
100 #endif
101
102
103 int
104 eqreal( /* are two real values close enough to equal? */
105 double d1,
106 double d2
107 )
108 {
109 if (d2 != 0.0)
110 d1 = d1/d2 - 1.0;
111 return((-FTINY <= d1) & (d1 <= FTINY));
112 }
113
114
115 int
116 eqobjects( /* check if two objects are equal */
117 OBJECT obj1,
118 OBJECT obj2
119 )
120 {
121 OBJREC *op1, *op2;
122 int i, n;
123
124 while (obj1 != obj2) {
125 if (obj1 == OVOID)
126 return(0);
127 if (obj2 == OVOID)
128 return(0);
129 op1 = objptr(obj1);
130 op2 = objptr(obj2);
131 if (op1->otype != op2->otype)
132 return(0);
133 if (op1->oargs.nsargs != op2->oargs.nsargs)
134 return(0);
135 if (op1->oargs.nfargs != op2->oargs.nfargs)
136 return(0);
137 #ifdef IARGS
138 if (op1->oargs.niargs != op2->oargs.niargs)
139 return(0);
140 for (i = op1->oargs.niargs; i-- > 0; )
141 if (op1->oargs.iarg[i] != op2->oargs.iarg[i])
142 return(0);
143 #endif
144 for (i = op1->oargs.nfargs; i-- > 0; )
145 if (!eqreal(op1->oargs.farg[i], op2->oargs.farg[i]))
146 return(0);
147 n = 0;
148 switch (op1->otype) { /* special cases (KEEP CONSISTENT!) */
149 case MOD_ALIAS:
150 case MAT_ILLUM:
151 case MAT_MIRROR:
152 n = (op1->oargs.nsargs > 0);
153 break;
154 case MIX_FUNC:
155 case MIX_DATA:
156 case MIX_TEXT:
157 case MIX_PICT:
158 n = 2*(op1->oargs.nsargs >= 2);
159 break;
160 case MAT_CLIP:
161 n = op1->oargs.nsargs;
162 break;
163 }
164 /* check other string arguments */
165 for (i = op1->oargs.nsargs; i-- > n; )
166 if (strcmp(op1->oargs.sarg[i], op2->oargs.sarg[i]))
167 return(0);
168 while (n-- > 0) /* check modifier references */
169 if (!eqobjects( lastmod(obj1, op1->oargs.sarg[n]),
170 lastmod(obj2, op2->oargs.sarg[n]) ))
171 return(0);
172 obj1 = op1->omod;
173 obj2 = op2->omod;
174 }
175 return(1);
176 }
177
178
179 void
180 insertobject( /* insert new object into our list */
181 OBJECT obj
182 )
183 {
184 int i;
185
186 if (ismodifier(objptr(obj)->otype)) {
187 i = otndx(objptr(obj)->oname, &modtab);
188 if (eqobjects(obj, modtab.htab[i]))
189 return; /* don't index if same as earlier def. */
190 modtab.htab[i] = obj;
191 }
192 #ifdef GETOBJ
193 else {
194 i = otndx(objptr(obj)->oname, &objtab);
195 objtab.htab[i] = obj;
196 }
197 #endif
198 for (i = 0; addobjnotify[i] != NULL; i++)
199 (*addobjnotify[i])(obj);
200 }
201
202
203 void
204 truncobjndx(void) /* remove bogus table entries past end */
205 {
206 int ndx;
207
208 if (nobjects <= 0) {
209 if (modtab.htab != NULL) {
210 free(modtab.htab);
211 modtab.htab = NULL;
212 modtab.hsiz = 100;
213 }
214 if (objtab.htab != NULL) {
215 free(objtab.htab);
216 objtab.htab = NULL;
217 objtab.hsiz = 100;
218 }
219 return;
220 }
221 for (ndx = modtab.hsiz*(modtab.htab != NULL); ndx--; )
222 if (modtab.htab[ndx] >= nobjects)
223 modtab.htab[ndx] = OVOID;
224
225 for (ndx = objtab.hsiz*(objtab.htab != NULL); ndx--; )
226 if (objtab.htab[ndx] >= nobjects)
227 objtab.htab[ndx] = OVOID;
228 }
229
230
231 static int
232 nexthsiz( /* return next hash table size */
233 int oldsiz
234 )
235 {
236 static int hsiztab[] = {
237 251, 509, 1021, 2039, 4093, 8191, 16381,
238 32749, 65521, 131071, 262139, 0
239 };
240 int *hsp;
241
242 for (hsp = hsiztab; *hsp; hsp++)
243 if (*hsp > oldsiz)
244 return(*hsp);
245 return(oldsiz*2 + 1); /* not always prime */
246 }
247
248
249 static int
250 otndx( /* get object table index for name */
251 char *name,
252 struct ohtab *tab
253 )
254 {
255 char *onm;
256 OBJECT *oldhtab;
257 int hval, i;
258 int ndx;
259
260 if (tab->htab == NULL) { /* new table */
261 tab->hsiz = nexthsiz(tab->hsiz);
262 tab->htab = (OBJECT *)malloc(tab->hsiz*sizeof(OBJECT));
263 if (tab->htab == NULL)
264 error(SYSTEM, "out of memory in otndx");
265 ndx = tab->hsiz;
266 while (ndx--) /* empty it */
267 tab->htab[ndx] = OVOID;
268 }
269 /* look up object */
270 hval = shash(name);
271 tryagain:
272 for (i = 0; i < tab->hsiz; i++) {
273 ndx = (hval + (unsigned long)i*i) % tab->hsiz;
274 if (tab->htab[ndx] == OVOID)
275 return(ndx);
276 onm = objptr(tab->htab[ndx])->oname;
277 if (onm != NULL && !strcmp(onm, name))
278 return(ndx);
279 }
280 /* table is full, reallocate */
281 oldhtab = tab->htab;
282 ndx = tab->hsiz;
283 tab->htab = NULL;
284 while (ndx--)
285 if (oldhtab[ndx] != OVOID) {
286 onm = objptr(oldhtab[ndx])->oname;
287 if (onm == NULL)
288 continue;
289 i = otndx(onm, tab);
290 tab->htab[i] = oldhtab[ndx];
291 }
292 free(oldhtab);
293 goto tryagain; /* should happen only once! */
294 }