1 /*********************************************************************
2  *   Copyright 1993, UCAR/Unidata
3  *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4  *   $Header: /upc/share/CVS/netcdf-3/ncgen/offsets.c,v 1.1 2009/09/25 18:22:40 dmh Exp $
5  *********************************************************************/
6 
7 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8  * Copyright by The HDF Group.                                               *
9  * Copyright by the Board of Trustees of the University of Illinois.         *
10  * All rights reserved.                                                      *
11  *                                                                           *
12  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
13  * terms governing use, modification, and redistribution, is contained in    *
14  * the files COPYING and Copyright.html.  COPYING can be found at the root   *
15  * of the source code distribution tree; Copyright.html can be found at the  *
16  * root level of an installed copy of the electronic HDF5 document set and   *
17  * is linked from the top-level documents page.  It can also be found at     *
18  * http://hdfgroup.org/HDF5/doc/Copyright.html.  If you do not have          *
19  * access to either file, you may request a copy from help@hdfgroup.org.     *
20  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21 
22 /*
23 This code is a variantion of the H5detect.c code from HDF5.
24 Author: D. Heimbigner 10/7/2008
25 */
26 
27 #include "config.h"
28 #include        <stdlib.h>
29 #include        <stdio.h>
30 #include        <string.h>
31 #include        <assert.h>
32 #include        "nclog.h"
33 
34 #ifdef OFFSETTEST
35 
36 static void* emalloc(size_t);
37 
38 typedef int nc_type;
39 typedef struct nc_vlen_t {
40     size_t len;
41     void* p;
42 } nc_vlen_t;
43 
44 #define	NC_NAT 	        0	/* NAT = 'Not A Type' (c.f. NaN) */
45 #define	NC_BYTE         1	/* signed 1 byte integer */
46 #define	NC_CHAR 	2	/* ISO/ASCII character */
47 #define	NC_SHORT 	3	/* signed 2 byte integer */
48 #define	NC_INT 	        4	/* signed 4 byte integer */
49 #define	NC_FLOAT 	5	/* single precision floating point number */
50 #define	NC_DOUBLE 	6	/* double precision floating point number */
51 #define	NC_UBYTE 	7	/* unsigned 1 byte int */
52 #define	NC_USHORT 	8	/* unsigned 2-byte int */
53 #define	NC_UINT 	9	/* unsigned 4-byte int */
54 #define	NC_INT64 	10	/* signed 8-byte int */
55 #define	NC_UINT64 	11	/* unsigned 8-byte int */
56 #define	NC_STRING 	12	/* string */
57 #define	NC_STRING 	12	/* string */
58 #define	NC_VLEN 	13
59 #define	NC_OPAQUE 	14
60 #define	NC_ENUM 	15
61 #define	NC_COMPOUND 	16
62 #endif
63 
64 #include        "netcdf.h"
65 #include        "ncoffsets.h"
66 
67 
68 /*
69 The heart of this is the following macro,
70 which computes the offset of a field x
71 when preceded by a char field.
72 The assumptions appear to be as follows:
73 1. the offset produced in this situation indicates
74    the alignment for x relative in such a way that it
75    depends only on the types that precede it in the struct.
76 2. the compiler does not reorder fields.
77 3. arrays are tightly packed.
78 4. nested structs are alignd according to their first member
79    (this actually follows from C language requirement that
80     a struct can legally be cast to an instance of its first member).
81 Given the alignments for the various common primitive types,
82 it is assumed that one can use them anywhere to construct
83 the layout of a struct of such types.
84 It seems to work for HDF5 for a wide variety of machines.
85 Note that technically, this is compiler dependent, but in practice
86 all compilers seem to mimic the gcc rules.
87 */
88 
89 #define COMP_ALIGNMENT(DST,TYPE)  {\
90     struct {char f1; TYPE x;} tmp; \
91     DST.type_name = #TYPE ;        \
92     DST.alignment = (size_t)((char*)(&(tmp.x)) - (char*)(&tmp));}
93 
94 #if 0
95 char* ctypenames[NCTYPES] = {
96 (char*)NULL,
97 "char","unsigned char",
98 "short","unsigned short",
99 "int","unsigned int",
100 "long long","unsigned long long",
101 "float","double",
102 "void*","nc_vlen_t"
103 };
104 #endif
105 
106 static NCtypealignvec vec[NC_NCTYPES];
107 static NCtypealignset set;
108 int NC_alignments_computed = 0;
109 
110 /* Argument is a netcdf type class, except compound|ENUM  */
111 size_t
NC_class_alignment(int ncclass)112 NC_class_alignment(int ncclass)
113 {
114     NCalignment* align = NULL;
115     int index = 0;
116     if(!NC_alignments_computed) {
117 	NC_compute_alignments();
118 	NC_alignments_computed = 1;
119     }
120     switch (ncclass) {
121       case NC_BYTE: index = NC_UCHARINDEX; break;
122       case NC_CHAR: index = NC_CHARINDEX; break;
123       case NC_SHORT: index = NC_SHORTINDEX; break;
124       case NC_INT: index = NC_INTINDEX; break;
125       case NC_FLOAT: index = NC_FLOATINDEX; break;
126       case NC_DOUBLE: index = NC_DOUBLEINDEX; break;
127       case NC_UBYTE: index = NC_UCHARINDEX; break;
128       case NC_USHORT: index = NC_USHORTINDEX; break;
129       case NC_UINT: index = NC_UINTINDEX; break;
130       case NC_INT64: index = NC_LONGLONGINDEX; break;
131       case NC_UINT64: index = NC_ULONGLONGINDEX; break;
132       case NC_STRING: index = NC_PTRINDEX; break;
133       /* Here class matters */
134       case NC_VLEN: index = NC_NCVLENINDEX; break;
135       case NC_OPAQUE: index = NC_UCHARINDEX; break;
136       case NC_ENUM: /* fall thru */
137       case NC_COMPOUND: /* fall thru */
138       default:
139 	nclog(NCLOGERR,"nc_class_alignment: class code %d cannot be aligned",ncclass);
140 	return 0;
141     }
142     align = &vec[index];
143     return align->alignment;
144 }
145 
146 
147 void
NC_compute_alignments(void)148 NC_compute_alignments(void)
149 {
150     if(NC_alignments_computed) return;
151     /* Compute the alignments for all the common C data types*/
152     /* First for the struct*/
153     /* initialize*/
154     memset((void*)&set,0,sizeof(set));
155     memset((void*)vec,0,sizeof(vec));
156 
157     COMP_ALIGNMENT(set.charalign,char);
158     COMP_ALIGNMENT(set.ucharalign,unsigned char);
159     COMP_ALIGNMENT(set.shortalign,short);
160     COMP_ALIGNMENT(set.ushortalign,unsigned short);
161     COMP_ALIGNMENT(set.intalign,int);
162     COMP_ALIGNMENT(set.uintalign,unsigned int);
163     COMP_ALIGNMENT(set.longlongalign,long long);
164     COMP_ALIGNMENT(set.ulonglongalign,unsigned long long);
165     COMP_ALIGNMENT(set.floatalign,float);
166     COMP_ALIGNMENT(set.doublealign,double);
167     COMP_ALIGNMENT(set.ptralign,void*);
168     COMP_ALIGNMENT(set.ncvlenalign,nc_vlen_t);
169 
170     /* Then the vector*/
171     COMP_ALIGNMENT(vec[NC_CHARINDEX],char);
172     COMP_ALIGNMENT(vec[NC_UCHARINDEX],unsigned char);
173     COMP_ALIGNMENT(vec[NC_SHORTINDEX],short);
174     COMP_ALIGNMENT(vec[NC_USHORTINDEX],unsigned short);
175     COMP_ALIGNMENT(vec[NC_INTINDEX],int);
176     COMP_ALIGNMENT(vec[NC_UINTINDEX],unsigned int);
177     COMP_ALIGNMENT(vec[NC_LONGLONGINDEX],long long);
178     COMP_ALIGNMENT(vec[NC_ULONGLONGINDEX],unsigned long long);
179     COMP_ALIGNMENT(vec[NC_FLOATINDEX],float);
180     COMP_ALIGNMENT(vec[NC_DOUBLEINDEX],double);
181     COMP_ALIGNMENT(vec[NC_PTRINDEX],void*);
182     COMP_ALIGNMENT(vec[NC_NCVLENINDEX],nc_vlen_t);
183     NC_alignments_computed = 1;
184 }
185 
186 #ifdef OFFSETTEST
187 
188 /* Compute the alignment of TYPE when it is preceded
189    by a field of type TYPE1
190 */
191 #define COMP_ALIGNMENT1(DST,TYPE1,TYPE)  {\
192     struct {TYPE1 f1; TYPE x;} tmp; \
193     DST.type_name = #TYPE ;        \
194     DST.alignment = (size_t)((char*)(&(tmp.x)) - (char*)(&tmp));}
195 
196 /* Compute the alignment of TYPE when it is preceded
197    by a field of type TYPE1 and a field of type TYPE2
198 */
199 #define COMP_ALIGNMENT2(DST,TYPE1,TYPE2,TYPE)  {\
200     struct {TYPE1 f1, TYPE2 f2; TYPE x;} tmp;   \
201     DST.type_name = #TYPE ;                      \
202     DST.alignment = (size_t)((char*)(&(tmp.x)) - (char*)(&tmp));}
203 
204 /* Compute the alignment of TYPE when it is preceded
205    by a field of type TYPE1 and a field of type TYPE2
206 */
207 #define COMP_SIZE0(DST,TYPE1,TYPE2)  {\
208     struct {TYPE1 c; TYPE2 x;} tmp; \
209     DST = sizeof(tmp); }
210 
211 static char*
padname(char * name)212 padname(char* name)
213 {
214 #define MAX 20
215     if(name == NULL) name = "null";
216     int len = strlen(name);
217     if(len > MAX) len = MAX;
218     char* s = (char*)emalloc(MAX+1);
219     memset(s,' ',MAX);
220     s[MAX+1] = '\0';
221     strncpy(s,name,len);
222     return s;
223 }
224 
225 static void
verify(NCtypealignvec * vec)226 verify(NCtypealignvec* vec)
227 {
228     int i,j;
229     NCtypealignvec* vec16;
230     NCtypealignvec* vec32;
231     int* sizes8;
232     int* sizes16;
233     int* sizes32;
234 
235     vec16 = (NCtypealignvec*)emalloc(sizeof(NCtypealignvec)*NCTYPES);
236     vec32 = (NCtypealignvec*)emalloc(sizeof(NCtypealignvec)*NCTYPES);
237     sizes8 = (int*)emalloc(sizeof(int)*NCTYPES);
238     sizes16 = (int*)emalloc(sizeof(int)*NCTYPES);
239     sizes32 = (int*)emalloc(sizeof(int)*NCTYPES);
240 
241     COMP_SIZE0(sizes8[1],char,char);
242     COMP_SIZE0(sizes8[2],unsigned char,char);
243     COMP_SIZE0(sizes8[3],short,char);
244     COMP_SIZE0(sizes8[4],unsigned short,char);
245     COMP_SIZE0(sizes8[5],int,char);
246     COMP_SIZE0(sizes8[6],unsigned int,char);
247     COMP_SIZE0(sizes8[7],long long,char);
248     COMP_SIZE0(sizes8[8],unsigned long long,char);
249     COMP_SIZE0(sizes8[9],float,char);
250     COMP_SIZE0(sizes8[10],double,char) ;
251     COMP_SIZE0(sizes8[11],void*,char);
252     COMP_SIZE0(sizes8[12],nc_vlen_t,char);
253 
254     COMP_SIZE0(sizes16[1],char,short);
255     COMP_SIZE0(sizes16[2],unsigned char,short);
256     COMP_SIZE0(sizes16[3],short,short);
257     COMP_SIZE0(sizes16[4],unsigned short,short);
258     COMP_SIZE0(sizes16[5],int,short);
259     COMP_SIZE0(sizes16[6],unsigned int,short);
260     COMP_SIZE0(sizes16[7],long long,short);
261     COMP_SIZE0(sizes16[8],unsigned long long,short);
262     COMP_SIZE0(sizes16[9],float,short);
263     COMP_SIZE0(sizes16[10],double,short) ;
264     COMP_SIZE0(sizes16[11],void*,short);
265     COMP_SIZE0(sizes16[12],nc_vlen_t*,short);
266 
267     COMP_SIZE0(sizes32[1],char,int);
268     COMP_SIZE0(sizes32[2],unsigned char,int);
269     COMP_SIZE0(sizes32[3],short,int);
270     COMP_SIZE0(sizes32[4],unsigned short,int);
271     COMP_SIZE0(sizes32[5],int,int);
272     COMP_SIZE0(sizes32[6],unsigned int,int);
273     COMP_SIZE0(sizes32[7],long long,int);
274     COMP_SIZE0(sizes32[8],unsigned long long,int);
275     COMP_SIZE0(sizes32[9],float,int);
276     COMP_SIZE0(sizes32[10],double,int) ;
277     COMP_SIZE0(sizes32[11],void*,int);
278     COMP_SIZE0(sizes32[12],nc_vlen_t*,int);
279 
280     COMP_ALIGNMENT1(vec16[1],char,short);
281     COMP_ALIGNMENT1(vec16[2],unsigned char,short);
282     COMP_ALIGNMENT1(vec16[3],short,short);
283     COMP_ALIGNMENT1(vec16[4],unsigned short,short);
284     COMP_ALIGNMENT1(vec16[5],int,short);
285     COMP_ALIGNMENT1(vec16[6],unsigned int,short);
286     COMP_ALIGNMENT1(vec32[7],long long,short);
287     COMP_ALIGNMENT1(vec32[8],unsigned long long,short);
288     COMP_ALIGNMENT1(vec16[9],float,short);
289     COMP_ALIGNMENT1(vec16[10],double,short);
290     COMP_ALIGNMENT1(vec16[11],void*,short);
291     COMP_ALIGNMENT1(vec16[12],nc_vlen_t*,short);
292 
293     COMP_ALIGNMENT1(vec32[1],char,short);
294     COMP_ALIGNMENT1(vec32[2],unsigned char,short);
295     COMP_ALIGNMENT1(vec32[3],char,short);
296     COMP_ALIGNMENT1(vec32[4],unsigned short,short);
297     COMP_ALIGNMENT1(vec32[5],int,int);
298     COMP_ALIGNMENT1(vec32[6],unsigned int,int);
299     COMP_ALIGNMENT1(vec32[7],long long,int);
300     COMP_ALIGNMENT1(vec32[8],unsigned long long,int);
301     COMP_ALIGNMENT1(vec32[9],float,int);
302     COMP_ALIGNMENT1(vec32[10],double,int);
303     COMP_ALIGNMENT1(vec32[11],void*,int);
304     COMP_ALIGNMENT1(vec32[12],nc_vlen_t*,int);
305 
306     for(i=0;i<NCTYPES;i++) {
307 	printf("%s: size=%2d  alignment=%2d\n",
308 		padname(vec[i].type_name),sizes8[i],vec[i].alignment);
309     }
310     for(i=0;i<NCTYPES;i++) {
311 	printf("short vs %s: size=%2d  alignment=%2d\n",
312 		padname(vec[i].type_name),sizes16[i],vec16[i].alignment);
313     }
314     for(i=0;i<NCTYPES;i++) {
315 	printf("int vs %s: size=%2d  alignment=%2d\n",
316 		padname(vec[i].type_name),sizes32[i],vec32[i].alignment);
317     }
318 
319 }
320 
321 void *
emalloc(size_t bytes)322 emalloc(size_t bytes) {
323     size_t *memory;
324     memory = malloc(bytes);
325     if(memory == 0) {
326 	printf("malloc failed\n");
327 	exit(2);
328     }
329     return memory;
330 }
331 
332 int
main(int argc,char ** argv)333 main(int argc, char** argv)
334 {
335     int i;
336 
337     compute_alignments();
338 
339     verify(vec);
340 
341 /*
342     for(i=0;i<NCTYPES;i++) {
343 	printf("%s:\talignment=%d\n",vec[i].type_name,vec[i].alignment);
344     }
345 */
346     exit(0);
347 }
348 #endif /*OFFSETTEST*/
349