1 /*
2 * $Id: binobj.c,v 1.1 2005-09-18 22:03:50 dhmunro Exp $
3 * Implement functions for generic blocks of data.
4 */
5 /* Copyright (c) 2005, The Regents of the University of California.
6 * All rights reserved.
7 * This file is part of yorick (http://yorick.sourceforge.net).
8 * Read the accompanying LICENSE file for details.
9 */
10
11 #include "bcast.h"
12 #include "defmem.h"
13 #include "pstdlib.h"
14 #include <string.h>
15
16 extern void FreeMemberList(Member *member, long n);
17
18 /*--------------------------------------------------------------------------*/
19
20 /* Set up a block allocator which grabs space for 64 scalar array objects
21 at a time. Since Array contains an ops pointer, the alignment
22 of an Array must be at least as strict as a void*. */
23 static MemryBlock arrayBlock= {0, 0, sizeof(Array),
24 64*sizeof(Array)};
25
NewArray(StructDef * base,Dimension * dims)26 Array *NewArray(StructDef *base, Dimension *dims)
27 {
28 long number= TotalNumber(dims);
29 long size= base->size;
30 Array *array= (number*size>2*sizeof(double))?
31 p_malloc(sizeof(Array)+number*size) : NextUnit(&arrayBlock);
32 array->references= 0;
33 array->ops= base->dataOps;
34 array->type.base= Ref(base);
35 array->type.dims= Ref(dims);
36 array->type.number= number;
37 /* Dangerous to try to initialize things with copy -- could leave
38 junk in padding between struct members, which prevents comparison
39 operations from working properly. On the other hand, an array
40 will normally be filled when it is initialized, so setting
41 everything to 0 first may be a substantial performance penalty... */
42 /* base->Copy(base, array->value.c, array->value.c, number);
43 is NOT legal, since this is used by FreeArray to deallocate
44 valid strings or pointers
45 On the other hand,
46 memset(array->value.c, 0, size*number);
47 is gratuitous in the case of non-pointer objects */
48 if (base->Copy!=&CopyX) memset(array->value.c, 0, size*number);
49 return array;
50 }
51
FreeArray(void * v)52 void FreeArray(void *v) /* ******* Use Unref(array) ******* */
53 {
54 Array *array= v;
55 long number;
56 long size;
57 StructDef *base;
58 if (!array) return;
59 base= array->type.base;
60 number= TotalNumber(array->type.dims);
61 size= base->size;
62 base->Copy(base, array->value.c, array->value.c, number);
63 Unref(base);
64 FreeDimension(array->type.dims);
65 if (number*size>2*sizeof(double)) p_free(array);
66 else FreeUnit(&arrayBlock, array);
67 }
68
69 /* Set up a block allocator which grabs space for 16 StructDefs
70 at a time. Since StructDef contains an ops pointer, the alignment
71 of a StructDef must be at least as strict as a void*. */
72 static MemryBlock sdefBlock= {0, 0, sizeof(StructDef),
73 16*sizeof(StructDef)};
74
NewStructDef(IOStream * file,long index)75 StructDef *NewStructDef(IOStream *file, long index)
76 {
77 StructDef *base= NextUnit(&sdefBlock);
78 base->references= 0;
79 base->ops= yOpsStructDef;
80 base->dataOps= 0; /* set by InstallStruct to validate */
81
82 base->size= 0;
83 base->alignment= 0;
84
85 base->table.nItems= 0;
86 base->table.maxItems= 0;
87 base->table.names= 0;
88 base->table.nSlots= 0;
89 base->table.items= 0;
90
91 base->members= 0;
92 base->offsets= 0;
93
94 base->Copy= &CopyX;
95
96 base->file= file; /* NOT Ref(file), since file owns base->reference */
97 base->index= index;
98 base->addressType= 0;
99 base->model= 0;
100 base->Convert= 0;
101 base->order= 0;
102 base->fpLayout= 0;
103 return base;
104 }
105
FreeStructDef(void * v)106 void FreeStructDef(void *v) /* *** Use Unref(base) *** */
107 {
108 StructDef *base= v;
109 if (!base->table.nItems && !base->file && base->index<=8) {
110 base->references= 0;
111 YError("(BUG?) attempt to free StructDef of basic data type");
112 }
113 FreeMemberList(base->members, base->table.nItems);
114 HashClear(&base->table);
115 p_free(base->members);
116 p_free(base->offsets);
117 Unref(base->model);
118 /* NO Unref(base->file), see NewStructDef above */
119 FreeFPLayout(base->fpLayout);
120 FreeUnit(&sdefBlock, base);
121 }
122
FreeMemberList(Member * member,long n)123 void FreeMemberList(Member *member, long n)
124 {
125 while (n > 0) {
126 Unref(member->base);
127 FreeDimension(member->dims);
128 member++;
129 n--;
130 }
131 }
132
133 /* Set up a block allocator which grabs space for 256 shape objects
134 at a time. */
135 union FourLongs {
136 /* Since each of these structs contain a pointer, the
137 alignment of a FourLongs must be at least as strict as a void*. */
138 Dimension d;
139 Strider q;
140 };
141 static MemryBlock fourBlock= {0, 0, sizeof(union FourLongs),
142 256*sizeof(union FourLongs)};
143
144 int yForceOrigin= 1;
145
NewDimension(long number,long origin,Dimension * next)146 Dimension *NewDimension(long number, long origin, Dimension *next)
147 {
148 Dimension *dims= NextUnit(&fourBlock);
149 dims->next= next; /* THINK CAREFULLY -- usually don't want Ref(next) */
150 dims->number= number;
151 dims->origin= origin;
152 dims->references= 0;
153 return dims;
154 }
155
156 Dimension *
ynew_dim(long n,Dimension * next)157 ynew_dim(long n, Dimension *next)
158 {
159 Dimension *dims = tmpDims;
160 tmpDims = 0;
161 if (dims) FreeDimension(dims);
162 return tmpDims = NewDimension(n, 1L, next);
163 }
164
FreeDimension(Dimension * dims)165 void FreeDimension(Dimension *dims)
166 {
167 if (dims && --dims->references<0) {
168 FreeDimension(dims->next);
169 FreeUnit(&fourBlock, dims);
170 }
171 }
172
NewStrider(long stride,long number)173 Strider *NewStrider(long stride, long number)
174 {
175 Strider *strider= NextUnit(&fourBlock);
176 strider->next= 0;
177 strider->stride= stride;
178 strider->number= number;
179 strider->indexList= 0;
180 return strider;
181 }
182
FreeStrider(Strider * strider)183 void FreeStrider(Strider *strider)
184 {
185 if (strider) {
186 FreeStrider(strider->next);
187 Unref(strider->indexList);
188 FreeUnit(&fourBlock, strider);
189 }
190 }
191
192 /*--------------------------------------------------------------------------*/
193
194 Dimension *tmpDims= 0;
195
TotalNumber(const Dimension * dims)196 long TotalNumber(const Dimension *dims)
197 {
198 long number= 1;
199 while (dims) {
200 number*= dims->number;
201 dims= dims->next;
202 }
203 return number;
204 }
205
CountDims(const Dimension * dims)206 int CountDims(const Dimension *dims)
207 {
208 int count;
209 for (count=0 ; dims ; dims= dims->next) count++;
210 return count;
211 }
212
213 /* Note-- like NewDimension, CopyDims does NOT do Ref(next) */
CopyDims(Dimension * dims,Dimension * next,int copyOrigin)214 Dimension *CopyDims(Dimension *dims, Dimension *next, int copyOrigin)
215 {
216 if (dims)
217 return NewDimension(dims->number, copyOrigin? dims->origin : 1L,
218 CopyDims(dims->next, next, copyOrigin));
219 else
220 return next;
221 }
222
CopyStrider(Strider * strider,Strider * next)223 Strider *CopyStrider(Strider *strider, Strider *next)
224 {
225 Strider *s;
226 if (!strider) return next;
227 s= NewStrider(strider->stride, strider->number);
228 s->next= CopyStrider(strider->next, next);
229 s->indexList= Ref(strider->indexList);
230 return s;
231 }
232
233 /*--------------------------------------------------------------------------*/
234
235 /* The offsetof macro may be defined in <stddef.h> (it is ANSI standard). */
236 /* #define offsetof(structure, member) ((long)&(((structure*)0)->member))
237 (does not work on Crays) */
238 #ifndef offsetof
239 #define offsetof(structure, member) \
240 ((long)((char *)&(((structure*)0)->member) - (char *)0))
241 #endif
242
Pointee(void * pointer)243 void *Pointee(void *pointer)
244 {
245 if (pointer) return (char *)pointer - offsetof(Array, value);
246 else return &nilDB;
247 }
248
249 /*--------------------------------------------------------------------------*/
250 /* Here are the four possibilities for the StructDef->Copy function.
251 Note that they function properly when s==t on input-- namely,
252 Copy(base, address, address, n) will properly initialize all pointers
253 to 0 without any other initialization. */
254
CopyX(StructDef * base,void * s,const void * t,long n)255 void CopyX(StructDef *base, void *s, const void *t, long n)
256 {
257 /* memcpy is a serious performance bottleneck for basic data types
258 -- this is a kludge to work around the fact that I misused
259 &CopyX as a flag in a couple of places in the code
260 many C compilers need hand unrolled loops */
261 if (s!=t) {
262 if (base==&doubleStruct) {
263 double *ss= s;
264 const double *tt= t;
265 long i;
266 for (i=0 ; i<(n&7) ; i++) ss[i]= tt[i];
267 for ( ; i<n ; i+=8) {
268 ss[i ]= tt[i];
269 ss[i+1]= tt[i+1];
270 ss[i+2]= tt[i+2];
271 ss[i+3]= tt[i+3];
272 ss[i+4]= tt[i+4];
273 ss[i+5]= tt[i+5];
274 ss[i+6]= tt[i+6];
275 ss[i+7]= tt[i+7];
276 }
277 } else if (base==&longStruct) {
278 long *ss= s;
279 const long *tt= t;
280 long i;
281 for (i=0 ; i<(n&7) ; i++) ss[i]= tt[i];
282 for ( ; i<n ; i+=8) {
283 ss[i ]= tt[i];
284 ss[i+1]= tt[i+1];
285 ss[i+2]= tt[i+2];
286 ss[i+3]= tt[i+3];
287 ss[i+4]= tt[i+4];
288 ss[i+5]= tt[i+5];
289 ss[i+6]= tt[i+6];
290 ss[i+7]= tt[i+7];
291 }
292 } else if (base==&intStruct) {
293 int *ss= s;
294 const int *tt= t;
295 long i;
296 for (i=0 ; i<(n&7) ; i++) ss[i]= tt[i];
297 for ( ; i<n ; i+=8) {
298 ss[i ]= tt[i];
299 ss[i+1]= tt[i+1];
300 ss[i+2]= tt[i+2];
301 ss[i+3]= tt[i+3];
302 ss[i+4]= tt[i+4];
303 ss[i+5]= tt[i+5];
304 ss[i+6]= tt[i+6];
305 ss[i+7]= tt[i+7];
306 }
307 } else if (base==&floatStruct) {
308 float *ss= s;
309 const float *tt= t;
310 long i;
311 for (i=0 ; i<(n&7) ; i++) ss[i]= tt[i];
312 for ( ; i<n ; i+=8) {
313 ss[i ]= tt[i];
314 ss[i+1]= tt[i+1];
315 ss[i+2]= tt[i+2];
316 ss[i+3]= tt[i+3];
317 ss[i+4]= tt[i+4];
318 ss[i+5]= tt[i+5];
319 ss[i+6]= tt[i+6];
320 ss[i+7]= tt[i+7];
321 }
322 } else {
323 memcpy(s, t, n*base->size);
324 }
325 }
326 }
327
328 typedef char *charPtr;
329
330 /* ARGSUSED */
CopyQ(StructDef * base,void * s,const void * t,long n)331 void CopyQ(StructDef *base, void *s, const void *t, long n)
332 {
333 char **dst= s;
334 const charPtr *src= (const charPtr *)t;
335 while (n--) {
336 p_free(*dst);
337 *dst= 0;
338 *dst++= p_strcpy(*src++);
339 }
340 }
341
342 typedef void *voidPtr;
343
344 /* ARGSUSED */
CopyP(StructDef * base,void * s,const void * t,long n)345 void CopyP(StructDef *base, void *s, const void *t, long n)
346 {
347 void **dst= s;
348 const voidPtr *src= (const voidPtr *)t;
349 void *oldArray;
350 while (n--) {
351 if ((oldArray= *dst)) {
352 *dst= 0; /* Unref might take some time, delete reference first */
353 oldArray= Pointee(oldArray);
354 Unref((Array *)oldArray);
355 }
356 if (*src) { /* Can't take this branch if dst==src. */
357 oldArray= Pointee(*dst++= *src++);
358 ((Array *)oldArray)->references++;
359 } else {
360 *dst++= 0;
361 src++;
362 }
363 }
364 }
365
CopyS(StructDef * base,void * s,const void * t,long n)366 void CopyS(StructDef *base, void *s, const void *t, long n)
367 {
368 long size= base->size;
369 long nItems= base->table.nItems;
370 long off, *offsets= base->offsets;
371 Member *members= base->members;
372
373 char *dst= s;
374 const char *src= t;
375 int initializing= (s==t);
376
377 StructDef *subBase;
378 long m, subTotal, subSize;
379 Copier *SubCopy;
380
381 /* outer loop is on number of items */
382 while (n--) {
383
384 /* inner loop is on base structure members */
385 for (m=0 ; m<nItems ; /* m++ in loop body */) {
386 subBase= members[m].base;
387 SubCopy= subBase->Copy;
388 /* skip initialization of direct data */
389 if (initializing && SubCopy==CopyX) { m++; continue; }
390
391 subTotal= members[m].number;
392 off= offsets[m++];
393 /* include contiguous members of the same type to avoid multiple
394 calls to SubCopy */
395 subSize= subBase->size;
396 while (m<nItems && members[m].base==subBase &&
397 offsets[m]==off+subSize*subTotal) {
398 subTotal+= members[m].number;
399 m++;
400 }
401 /* copy member or contiguous members (possibly recursive) */
402 SubCopy(subBase, dst+off, src+off, subTotal);
403 }
404
405 /* end of loop on structure members */
406 dst+= size;
407 src+= size;
408 } /* end of loop on number of items */
409 }
410
411 /*--------------------------------------------------------------------------*/
412