source: XIOS/dev/dev_olga/extern/src_netcdf4/ncaux.c @ 1620

Last change on this file since 1620 was 409, checked in by ymipsl, 11 years ago

Add improved nectdf internal library src

YM

  • Property svn:eol-style set to native
File size: 11.5 KB
Line 
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group.                                               *
3 * Copyright by the Board of Trustees of the University of Illinois.         *
4 * All rights reserved.                                                      *
5 *                                                                           *
6 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7 * terms governing use, modification, and redistribution, is contained in    *
8 * the files COPYING and Copyright.html.  COPYING can be found at the root   *
9 * of the source code distribution tree; Copyright.html can be found at the  *
10 * root level of an installed copy of the electronic HDF5 document set and   *
11 * is linked from the top-level documents page.  It can also be found at     *
12 * http://hdfgroup.org/HDF5/doc/Copyright.html.  If you do not have          *
13 * access to either file, you may request a copy from help@hdfgroup.org.     *
14 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16/*
17This code is a variant of the H5detect.c code from HDF5.
18Author: D. Heimbigner 10/7/2008
19*/
20
21#include <stdlib.h>
22#include <string.h>
23#include <assert.h>
24#include <netcdf.h>
25
26#include "ncaux.h"
27
28struct NCAUX_FIELD {
29    char* name;
30    nc_type fieldtype;
31    int ndims;
32    int dimsizes[NC_MAX_VAR_DIMS];   
33    size_t size;
34    size_t offset;
35    size_t alignment;
36};
37
38struct NCAUX_CMPD {
39    int ncid;
40    int mode;
41    char* name;
42    int nfields;
43    struct NCAUX_FIELD* fields;
44    size_t size;
45    size_t offset; /* cumulative as fields are added */
46    size_t alignment;
47};
48
49static int ncaux_initialized = 0;
50
51static void compute_alignments(void);
52static int computefieldinfo(struct NCAUX_CMPD* cmpd);
53
54int
55ncaux_begin_compound(int ncid, const char *name, int alignmode, void** tagp)
56{
57    int status = NC_NOERR;
58    struct NCAUX_CMPD* cmpd = NULL;
59
60    if(!ncaux_initialized) {
61        compute_alignments();
62        ncaux_initialized = 1;
63    }
64
65    if(tagp) *tagp = NULL;
66       
67    cmpd = (struct NCAUX_CMPD*)calloc(1,sizeof(struct NCAUX_CMPD));
68    if(cmpd == NULL) {status = NC_ENOMEM; goto fail;}
69    cmpd->ncid = ncid;
70    cmpd->mode = alignmode;
71    cmpd->nfields = 0;
72    cmpd->name = strdup(name);   
73    if(cmpd->name == NULL) {status = NC_ENOMEM; goto fail;}
74
75    if(tagp) *tagp = (void*)cmpd;
76
77    return status;
78
79fail:
80    ncaux_abort_compound((void*)cmpd);
81    return status;
82}
83
84int
85ncaux_abort_compound(void* tag)
86{
87    int i;
88    struct NCAUX_CMPD* cmpd = (struct NCAUX_CMPD*)tag;
89    if(cmpd == NULL) goto done;
90    if(cmpd->name) free(cmpd->name);
91    for(i=0;i<cmpd->nfields;i++) {
92        struct NCAUX_FIELD* field = &cmpd->fields[i];
93        if(field->name) free(field->name);
94    }
95    if(cmpd->fields) free(cmpd->fields);
96    free(cmpd);
97
98done:
99    return NC_NOERR;
100}
101
102int
103ncaux_add_field(void* tag,  const char *name, nc_type field_type,
104                           int ndims, const int* dimsizes)
105{
106    int i;
107    int status = NC_NOERR;
108    struct NCAUX_CMPD* cmpd = (struct NCAUX_CMPD*)tag;
109    struct NCAUX_FIELD* newfields = NULL;
110    struct NCAUX_FIELD* field = NULL;
111
112    if(cmpd == NULL) goto done;
113    if(ndims < 0) {status = NC_EINVAL; goto done;}
114    for(i=0;i<ndims;i++) {
115        if(dimsizes[i] <= 0) {status = NC_EINVAL; goto done;}
116    }
117    if(cmpd->fields == NULL) {
118        newfields = (struct NCAUX_FIELD*)calloc(1,sizeof(struct NCAUX_FIELD));
119    } else {
120        newfields = (struct NCAUX_FIELD*)realloc(cmpd->fields,cmpd->nfields+1*sizeof(struct NCAUX_FIELD));
121    }
122    if(cmpd->fields == NULL) {status = NC_ENOMEM; goto done;}
123    cmpd->fields = newfields;
124    field = &cmpd->fields[cmpd->nfields+1];
125    field->name = strdup(name);
126    field->fieldtype = field_type;
127    if(field->name == NULL) {status = NC_ENOMEM; goto done;}   
128    field->ndims = ndims;
129    memcpy(field->dimsizes,dimsizes,sizeof(int)*ndims);
130    cmpd->nfields++;
131
132done:
133    return status;
134}
135
136static size_t
137dimproduct(int ndims, int* dimsizes)
138{
139    int i;
140    size_t product = 1;
141    for(i=0;i<ndims;i++) product *= dimsizes[i];
142    return product;
143}
144
145int
146ncaux_end_compound(void* tag, nc_type* idp)
147{
148    int i;
149    int status = NC_NOERR;
150    struct NCAUX_CMPD* cmpd = (struct NCAUX_CMPD*)tag;
151
152    if(cmpd == NULL) {status = NC_EINVAL; goto done;}
153
154    /* Compute field and compound info */
155    status = computefieldinfo(cmpd);
156    if(status != NC_NOERR) goto done;
157
158    status = nc_def_compound(cmpd->ncid, cmpd->size, cmpd->name, idp);
159    if(status != NC_NOERR) goto done;
160
161    for(i=0;i<cmpd->nfields;i++) {
162        struct NCAUX_FIELD* field = &cmpd->fields[i];
163        if(field->ndims > 0) {
164            status = nc_insert_compound(cmpd->ncid, *idp, field->name,
165                                        field->offset, field->fieldtype);
166        } else {
167            status = nc_insert_array_compound(cmpd->ncid, *idp, field->name,
168                                        field->offset, field->fieldtype,
169                                        field->ndims,field->dimsizes);
170        }
171        if(status != NC_NOERR) goto done;
172    }
173
174done:
175    return status;
176}
177
178/**************************************************/
179
180/*
181The heart of this is the following macro,
182which computes the offset of a field x
183when preceded by a char field.
184The assumptions appear to be as follows:
1851. the offset produced in this situation indicates
186   the alignment for x relative in such a way that it
187   depends only on the types that precede it in the struct.
1882. the compiler does not reorder fields.
1893. arrays are tightly packed.
1904. nested structs are alignd according to their first member
191   (this actually follows from C language requirement that
192    a struct can legally be cast to an instance of its first member).
193Given the alignments for the various common primitive types,
194it is assumed that one can use them anywhere to construct
195the layout of a struct of such types.
196It seems to work for HDF5 for a wide variety of machines.
197*/
198
199#define COMP_ALIGNMENT(DST,TYPE)  {\
200    struct {char f1; TYPE x;} tmp; \
201    DST.typename = #TYPE ;        \
202    DST.alignment = (size_t)((char*)(&(tmp.x)) - (char*)(&tmp));}
203
204/* Define indices for every primitive C type */
205/* NAT => NOT-A-TYPE*/
206#define NATINDEX       0
207#define CHARINDEX      1
208#define UCHARINDEX     2
209#define SHORTINDEX     3
210#define USHORTINDEX    4
211#define INTINDEX       5
212#define UINTINDEX      6
213#define LONGINDEX      7
214#define ULONGINDEX     8
215#define LONGLONGINDEX  9
216#define ULONGLONGINDEX 10
217#define FLOATINDEX     11
218#define DOUBLEINDEX    12
219#define PTRINDEX       13
220#define NCVLENINDEX    14
221
222#define NCTYPES        15
223
224typedef struct Alignment {
225    char* typename;
226    int alignment;
227} Alignment;
228
229typedef Alignment Typealignvec;
230
231/* Capture in struct and in a vector*/
232typedef struct Typealignset {
233    Alignment charalign;        /* char*/
234    Alignment ucharalign;       /* unsigned char*/
235    Alignment shortalign;       /* short*/
236    Alignment ushortalign;      /* unsigned short*/
237    Alignment intalign;         /* int*/
238    Alignment uintalign;        /* unsigned int*/
239    Alignment longalign;        /* long*/
240    Alignment ulongalign;       /* unsigned long*/
241    Alignment longlongalign;    /* long long*/
242    Alignment ulonglongalign;   /* unsigned long long*/
243    Alignment floatalign;       /* float*/
244    Alignment doublealign;      /* double*/
245    Alignment ptralign;         /* void**/
246    Alignment ncvlenalign;      /* nc_vlen_t*/
247} Typealignset;
248
249static Typealignvec vec[NCTYPES];
250static Typealignset set;
251
252static void
253compute_alignments(void)
254{
255    /* Compute the alignments for all the common C data types*/
256    /* First for the struct*/
257    /* initialize*/
258    memset((void*)&set,0,sizeof(set));
259    memset((void*)vec,0,sizeof(vec));
260
261    COMP_ALIGNMENT(set.charalign,char);
262    COMP_ALIGNMENT(set.ucharalign,unsigned char);
263    COMP_ALIGNMENT(set.shortalign,short);
264    COMP_ALIGNMENT(set.ushortalign,unsigned short);
265    COMP_ALIGNMENT(set.intalign,int);
266    COMP_ALIGNMENT(set.uintalign,unsigned int);
267    COMP_ALIGNMENT(set.longalign,long);
268    COMP_ALIGNMENT(set.ulongalign,unsigned long);
269    COMP_ALIGNMENT(set.longlongalign,long long);
270    COMP_ALIGNMENT(set.ulonglongalign,unsigned long long);
271    COMP_ALIGNMENT(set.floatalign,float);
272    COMP_ALIGNMENT(set.doublealign,double);
273    COMP_ALIGNMENT(set.ptralign,void*);
274    COMP_ALIGNMENT(set.ncvlenalign,nc_vlen_t);
275
276    /* Then the vector*/
277    COMP_ALIGNMENT(vec[CHARINDEX],char);
278    COMP_ALIGNMENT(vec[UCHARINDEX],unsigned char); 
279    COMP_ALIGNMENT(vec[SHORTINDEX],short);
280    COMP_ALIGNMENT(vec[USHORTINDEX],unsigned short);
281    COMP_ALIGNMENT(vec[INTINDEX],int);
282    COMP_ALIGNMENT(vec[UINTINDEX],unsigned int);
283    COMP_ALIGNMENT(vec[LONGINDEX],long);
284    COMP_ALIGNMENT(vec[ULONGINDEX],unsigned long);
285    COMP_ALIGNMENT(vec[LONGLONGINDEX],long long);
286    COMP_ALIGNMENT(vec[ULONGLONGINDEX],unsigned long long);
287    COMP_ALIGNMENT(vec[FLOATINDEX],float);
288    COMP_ALIGNMENT(vec[DOUBLEINDEX],double);
289    COMP_ALIGNMENT(vec[PTRINDEX],void*);
290    COMP_ALIGNMENT(vec[NCVLENINDEX],nc_vlen_t);
291}
292
293static size_t
294nctypealignment(nc_type nctype)
295{
296    Alignment* align = NULL;
297    int index = 0;
298    switch (nctype) {
299      case NC_BYTE: index = UCHARINDEX; break;
300      case NC_CHAR: index = CHARINDEX; break;
301      case NC_SHORT: index = SHORTINDEX; break;
302      case NC_INT: index = INTINDEX; break;
303      case NC_FLOAT: index = FLOATINDEX; break;
304      case NC_DOUBLE: index = DOUBLEINDEX; break;
305      case NC_UBYTE: index = UCHARINDEX; break;
306      case NC_USHORT: index = USHORTINDEX; break;
307      case NC_UINT: index = UINTINDEX; break;
308      case NC_INT64: index = LONGLONGINDEX; break;
309      case NC_UINT64: index = ULONGLONGINDEX; break;
310      case NC_STRING: index = PTRINDEX; break;
311      case NC_VLEN: index = NCVLENINDEX; break;
312      case NC_OPAQUE: index = UCHARINDEX; break;
313      default: assert(0);
314    }
315    align = &vec[index];
316    return align->alignment;
317}
318
319static int
320getpadding(int offset, int alignment)
321{
322    int rem = (alignment==0?0:(offset % alignment));
323    int pad = (rem==0?0:(alignment - rem));
324    return pad;
325}
326
327/* Find first primitive field of a possibly nested sequence of compounds */
328static nc_type
329findfirstfield(int ncid, nc_type xtype)
330{
331    int status = NC_NOERR;
332    nc_type fieldtype = xtype;
333    if(xtype <= NC_MAX_ATOMIC_TYPE) goto done;
334       
335    status = nc_inq_compound_fieldtype(ncid, xtype, 0, &fieldtype);
336    if(status != NC_NOERR) goto done;
337    fieldtype = findfirstfield(ncid,fieldtype);
338
339done:
340    return (status == NC_NOERR?fieldtype:NC_NAT);
341}
342
343static int
344computefieldinfo(struct NCAUX_CMPD* cmpd)
345{
346    int i;
347    int status = NC_NOERR;
348    size_t offset = 0;
349    size_t totaldimsize;
350
351    /* Assign the sizes for the fields */
352    for(i=0;i<cmpd->nfields;i++) {
353        struct NCAUX_FIELD* field = &cmpd->fields[i];   
354        status = nc_inq_type(cmpd->ncid,field->fieldtype,NULL,&field->size);
355        if(status != NC_NOERR) goto done;
356        totaldimsize = dimproduct(field->ndims,field->dimsizes);
357        field->size *= totaldimsize;
358    }
359
360    for(offset=0,i=0;i<cmpd->nfields;i++) {
361        struct NCAUX_FIELD* field = &cmpd->fields[i];
362        int alignment = 0;
363        nc_type firsttype = findfirstfield(cmpd->ncid,field->fieldtype);
364
365        /* only support 'c' alignment for now*/
366        switch (field->fieldtype) {
367        case NC_OPAQUE:
368            field->alignment = 1;
369            break;
370        case NC_ENUM:
371            field->alignment = nctypealignment(firsttype);
372            break;     
373        case NC_VLEN: /*fall thru*/
374        case NC_COMPOUND:
375            field->alignment = nctypealignment(firsttype);
376            break;
377        default:
378            field->alignment = nctypealignment(field->fieldtype);
379            break;
380        }
381        offset += getpadding(offset,alignment);
382        field->offset = offset;
383        offset += field->size;
384    }
385    cmpd->size = offset;
386    cmpd->alignment = cmpd->fields[0].alignment;
387
388done:
389    return status;
390}
Note: See TracBrowser for help on using the repository browser.