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