/src/netcdf-c/libdispatch/dinstance_intern.c
Line | Count | Source |
1 | | /* |
2 | | Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata |
3 | | See COPYRIGHT for license information. |
4 | | */ |
5 | | |
6 | | /** \internal |
7 | | This file contains various instance operations that operate |
8 | | on a deep level rather than the shallow level of e.g. nc_free_vlen_t. |
9 | | Currently two operations are defined: |
10 | | 1. reclaim a vector of instances |
11 | | 2. copy a vector of instances |
12 | | */ |
13 | | |
14 | | #include "config.h" |
15 | | #include <stdlib.h> |
16 | | #include <string.h> |
17 | | #include <assert.h> |
18 | | #include "netcdf.h" |
19 | | #include "nc4internal.h" |
20 | | #include "nc4dispatch.h" |
21 | | #include "ncoffsets.h" |
22 | | #include "ncbytes.h" |
23 | | |
24 | | #undef REPORT |
25 | | #undef DEBUG |
26 | | |
27 | | /* It is helpful to have a structure that identifies a pointer into the overall memory */ |
28 | | typedef struct Position{char* memory;} Position; |
29 | | |
30 | | static int type_alignment_initialized = 0; |
31 | | |
32 | | /* Forward */ |
33 | | #ifdef USE_NETCDF4 |
34 | | static int reclaim_datar(NC_FILE_INFO_T* file, NC_TYPE_INFO_T* utype, Position instance); |
35 | | static int copy_datar(NC_FILE_INFO_T* file, NC_TYPE_INFO_T* utype, Position src, Position dst); |
36 | | #endif |
37 | | |
38 | | int NC_print_data(NC_FILE_INFO_T* file, nc_type xtype, const void* memory, size_t count); |
39 | | |
40 | | /** |
41 | | Reclaim a vector of instances of a type. This recursively walks the |
42 | | top-level instances to reclaim any nested data such as vlen or strings |
43 | | or such. |
44 | | |
45 | | Assumes it is passed a pointer to count instances of xtype. |
46 | | Reclaims any nested data. |
47 | | |
48 | | These are the internal equivalents of nc_reclaim_data[_all] and |
49 | | nc_copy_data[_all] and as such operate using internal data structures. |
50 | | |
51 | | WARNING: DOES NOT RECLAIM THE TOP-LEVEL MEMORY. |
52 | | The reason is that we do not know how it was allocated (e.g. static vs |
53 | | dynamic); only the caller can know that. But note that it assumes all |
54 | | memory blocks other than the top were dynamically allocated, so they |
55 | | will be free'd. |
56 | | |
57 | | Should work for any netcdf type. |
58 | | |
59 | | Note that this has been optimized significantly, largely |
60 | | by unwinding various reclaim cliche procedures. |
61 | | |
62 | | @param nc NC* structure |
63 | | @param xtype type id |
64 | | @param memory ptr to top-level memory to reclaim |
65 | | @param count number of instances of the type in memory block |
66 | | @return error code |
67 | | */ |
68 | | |
69 | | int |
70 | | NC_reclaim_data(NC* nc, nc_type xtype, void* memory, size_t count) |
71 | 0 | { |
72 | 0 | int stat = NC_NOERR; |
73 | 0 | size_t i; |
74 | 0 | Position instance; |
75 | 0 | NC_FILE_INFO_T* file = NULL; |
76 | 0 | NC_TYPE_INFO_T* utype = NULL; |
77 | |
|
78 | 0 | assert(nc != NULL); |
79 | 0 | assert((memory == NULL && count == 0) || (memory != NULL || count > 0)); |
80 | | |
81 | | /* Process atomic types */ |
82 | | |
83 | | /* Optimize: Vector of fixed size atomic types (always the case for netcdf-3)*/ |
84 | 0 | if(xtype < NC_STRING) goto done; |
85 | | |
86 | 0 | #ifdef USE_NETCDF4 |
87 | | /* Optimize: Vector of strings */ |
88 | 0 | if(xtype == NC_STRING) { |
89 | 0 | char** ss = (char**)memory; |
90 | 0 | for(i=0;i<count;i++) { |
91 | 0 | nullfree(ss[i]); |
92 | 0 | } |
93 | 0 | goto done; |
94 | 0 | } |
95 | | |
96 | | /* Process User types */ |
97 | 0 | assert(USEFILEINFO(nc) != 0); |
98 | 0 | file = (NC_FILE_INFO_T*)(nc)->dispatchdata; |
99 | 0 | if((stat = nc4_find_type(file,xtype,&utype))) goto done; |
100 | | |
101 | | /* Optimize: vector of fixed sized compound type instances */ |
102 | 0 | if(!utype->varsized) goto done; /* no need to reclaim anything */ |
103 | | |
104 | | /* Remaining cases: vector of VLEN and vector of (transitive) variable sized compound types. |
105 | | These all require potential recursion. |
106 | | */ |
107 | | |
108 | | /* Build a memory walker object */ |
109 | 0 | instance.memory = (char*)memory; /* use char* so we can do pointer arithmetic */ |
110 | | /* Walk each vector instance */ |
111 | | /* Note that we avoid reclaiming the top level memory */ |
112 | 0 | for(i=0;i<count;i++) { |
113 | 0 | if((stat=reclaim_datar(file,utype,instance))) goto done; |
114 | 0 | instance.memory += utype->size; /* move to next entry */ |
115 | 0 | } |
116 | | #else |
117 | | stat = NC_EBADTYPE; |
118 | | #endif |
119 | | |
120 | 0 | done: |
121 | 0 | return stat; |
122 | 0 | } |
123 | | |
124 | | #ifdef USE_NETCDF4 |
125 | | /* Recursive type walker: reclaim a single instance of a variable-sized user-defined type; |
126 | | specifically a vlen or a variable-sized compound type instance |
127 | | */ |
128 | | static int |
129 | | reclaim_datar(NC_FILE_INFO_T* file, NC_TYPE_INFO_T* utype, Position instance) |
130 | 0 | { |
131 | 0 | int i,stat = NC_NOERR; |
132 | 0 | nc_type basetypeid; |
133 | 0 | NC_TYPE_INFO_T* basetype = NULL; |
134 | 0 | size_t nfields; |
135 | 0 | nc_vlen_t* vlen; |
136 | 0 | size_t fid; |
137 | 0 | int ndims; |
138 | 0 | int dimsizes[NC_MAX_VAR_DIMS]; |
139 | 0 | size_t alignment = 0; |
140 | 0 | Position vinstance; /* walk the vlen instance memory */ |
141 | |
|
142 | 0 | assert(utype->varsized); /* All fixed size cases are optimized out */ |
143 | | |
144 | | /* Leaving VLEN or Compound */ |
145 | |
|
146 | 0 | if(utype->nc_type_class == NC_VLEN) { |
147 | 0 | basetypeid = utype->u.v.base_nc_typeid; /* Get basetype */ |
148 | 0 | vlen = (nc_vlen_t*)instance.memory;/* memory as vector of nc_vlen_t instances */ |
149 | | /* Optimize: basetype is atomic fixed size */ |
150 | 0 | if(basetypeid < NC_STRING) { |
151 | 0 | goto out; |
152 | 0 | } |
153 | | /* Optimize: basetype is string */ |
154 | 0 | if(basetypeid == NC_STRING) { |
155 | 0 | if(vlen->len > 0 && vlen->p != NULL) { |
156 | 0 | char** slist = (char**)vlen->p; /* vlen instance is a vector of string pointers */ |
157 | 0 | for(i=0;i<vlen->len;i++) {if(slist[i] != NULL) free(slist[i]);} |
158 | 0 | } |
159 | 0 | goto out; |
160 | 0 | } |
161 | | /* Optimize: vlen basetype is a fixed-size user-type */ |
162 | 0 | if((stat = nc4_find_type(file,basetypeid,&basetype))) goto done; |
163 | 0 | if(!basetype->varsized) { |
164 | 0 | goto out; |
165 | 0 | } |
166 | | /* Remaining case: basetype is itself variable size => recurse */ |
167 | 0 | if((stat = NC_type_alignment_internal(file,basetypeid,basetype,&alignment))) goto done;; |
168 | 0 | vinstance.memory = (char*)vlen->p; /* use char* so we can do pointer arithmetic */ |
169 | 0 | vinstance.memory = (void*)NC_read_align((uintptr_t)vinstance.memory,alignment); |
170 | 0 | for(i=0;i<vlen->len;i++) { |
171 | 0 | if((stat=reclaim_datar(file,basetype,vinstance))) goto done; /* reclaim one basetype instance */ |
172 | 0 | vinstance.memory += basetype->size; /* move to next base instance */ |
173 | 0 | } |
174 | 0 | out: |
175 | 0 | if(vlen->len > 0 && vlen->p != NULL) {free(vlen->p);} |
176 | 0 | goto done; |
177 | 0 | } else if(utype->nc_type_class == NC_COMPOUND) { |
178 | 0 | Position finstance; /* mark the fields's instance */ |
179 | 0 | nfields = nclistlength(utype->u.c.field); |
180 | | /* Get info about each field in turn and reclaim it */ |
181 | 0 | for(fid=0;fid<nfields;fid++) { |
182 | 0 | NC_FIELD_INFO_T* field = NULL; |
183 | | |
184 | | /* Get field's dimension sizes */ |
185 | 0 | field = (NC_FIELD_INFO_T*)nclistget(utype->u.c.field,fid); |
186 | 0 | ndims = field->ndims; |
187 | 0 | int arraycount = 1; |
188 | 0 | for(i=0;i<ndims;i++) {dimsizes[i] = field->dim_size[i]; arraycount *= dimsizes[i];} |
189 | 0 | if(field->ndims == 0) {ndims=1; dimsizes[0]=1;} /* fake the scalar case */ |
190 | | |
191 | | /* "Move" to start of this field's instance */ |
192 | 0 | finstance.memory = instance.memory + field->offset; /* includes proper alignment */ |
193 | | |
194 | | /* optimize: fixed length atomic type */ |
195 | 0 | if(field->nc_typeid < NC_STRING) continue; |
196 | | |
197 | | /* optimize: string field type */ |
198 | 0 | if(field->nc_typeid == NC_STRING) { |
199 | 0 | char** strvec = (char**)finstance.memory; |
200 | 0 | for(i=0;i<arraycount;i++) { |
201 | 0 | if(strvec[i] != NULL) free(strvec[i]); |
202 | 0 | } |
203 | 0 | continue; /* do next field */ |
204 | 0 | } |
205 | | |
206 | | /* optimize: fixed length compound base type */ |
207 | 0 | if((stat = nc4_find_type(file,field->nc_typeid,&basetype))) goto done; |
208 | 0 | if(!basetype->varsized) continue; |
209 | | |
210 | | /* Field is itself variable length (possibly transitively) */ |
211 | 0 | for(i=0;i<arraycount;i++) { |
212 | 0 | if((stat = reclaim_datar(file, basetype, finstance))) goto done; |
213 | 0 | finstance.memory += basetype->size; |
214 | 0 | } |
215 | 0 | } |
216 | 0 | goto done; |
217 | 0 | } else {stat = NC_EBADTYPE; goto done;} |
218 | | |
219 | 0 | done: |
220 | 0 | return stat; |
221 | 0 | } |
222 | | #endif |
223 | | |
224 | | /**************************************************/ |
225 | | |
226 | | /** |
227 | | Copy a vector of instances of a type. This recursively walks |
228 | | the top-level instances to copy any nested data such as vlen or |
229 | | strings or such. |
230 | | |
231 | | Assumes it is passed a pointer to count instances of xtype and a |
232 | | space into which to copy the instance. Copys any nested data |
233 | | by calling malloc(). |
234 | | |
235 | | WARNING: DOES NOT ALLOCATE THE TOP-LEVEL MEMORY (see the |
236 | | nc_copy_data_all function). Note that all memory blocks other |
237 | | than the top are dynamically allocated. |
238 | | |
239 | | Should work for any netcdf type. |
240 | | |
241 | | @param file NC_FILE_INFO_T* structure |
242 | | @param xtype type id |
243 | | @param memory ptr to top-level memory to reclaim |
244 | | @param count number of instances of the type in memory block |
245 | | @param copy top-level space into which to copy the instance |
246 | | @return error code |
247 | | */ |
248 | | |
249 | | int |
250 | | NC_copy_data(NC* nc, nc_type xtype, const void* memory, size_t count, void* copy) |
251 | 0 | { |
252 | 0 | int stat = NC_NOERR; |
253 | 0 | size_t i; |
254 | 0 | Position src; |
255 | 0 | Position dst; |
256 | 0 | NC_FILE_INFO_T* file = NULL; |
257 | 0 | NC_TYPE_INFO_T* utype = NULL; |
258 | 0 | size_t typesize = 0; |
259 | |
|
260 | 0 | if(memory == NULL || count == 0) |
261 | 0 | goto done; /* ok, do nothing */ |
262 | | |
263 | 0 | assert(nc != NULL); |
264 | 0 | assert(memory != NULL || count > 0); |
265 | 0 | assert(copy != NULL || count == 0); |
266 | | |
267 | | /* Process atomic types */ |
268 | | |
269 | | /* Optimize: Vector of fixed size atomic types */ |
270 | 0 | if(xtype < NC_STRING) { |
271 | 0 | typesize = NC_atomictypelen(xtype); |
272 | 0 | memcpy(copy,memory,count*typesize); |
273 | 0 | goto done; |
274 | 0 | } |
275 | | |
276 | 0 | #ifdef USE_NETCDF4 |
277 | | /* Optimize: Vector of strings */ |
278 | 0 | if(xtype == NC_STRING) { |
279 | 0 | char** svec = (char**)memory; |
280 | 0 | char** dvec = (char**)copy; |
281 | 0 | size_t len; |
282 | 0 | for(i=0;i<count;i++) { |
283 | 0 | const char* ssrc = svec[i]; |
284 | 0 | char* sdst; |
285 | 0 | if(ssrc == NULL) |
286 | 0 | sdst = NULL; |
287 | 0 | else { |
288 | 0 | len = nulllen(ssrc); |
289 | 0 | if((sdst = (char*)malloc(len+1))==NULL) {stat = NC_ENOMEM; goto done;} |
290 | 0 | memcpy(sdst,ssrc,len+1); /* +1 for trailing nul */ |
291 | 0 | } |
292 | 0 | dvec[i] = sdst; |
293 | 0 | } |
294 | 0 | goto done; |
295 | 0 | } |
296 | | |
297 | 0 | assert(USEFILEINFO(nc) != 0); |
298 | 0 | file = (NC_FILE_INFO_T*)(nc)->dispatchdata; |
299 | | |
300 | | /* Process User types */ |
301 | 0 | if((stat = nc4_find_type(file,xtype,&utype))) goto done; |
302 | | |
303 | | /* Optimize: vector of fixed sized compound type instances */ |
304 | 0 | if(!utype->varsized) { |
305 | 0 | memcpy(copy,memory,count*utype->size); |
306 | 0 | goto done; |
307 | 0 | } |
308 | | |
309 | | /* Remaining cases: vector of VLEN and vector of variable sized compound types. |
310 | | These all require potential recursion. |
311 | | */ |
312 | | |
313 | 0 | src.memory = (char*)memory; /* use char* so we can do pointer arithmetic */ |
314 | 0 | dst.memory = (char*)copy; /* use char* so we can do pointer arithmetic */ |
315 | | /* Walk each vector instance */ |
316 | 0 | for(i=0;i<count;i++) { |
317 | 0 | if((stat=copy_datar(file,utype,src,dst))) goto done; |
318 | 0 | src.memory += utype->size; |
319 | 0 | dst.memory += utype->size; |
320 | 0 | } |
321 | | #else |
322 | | stat = NC_EBADTYPE; |
323 | | #endif |
324 | | |
325 | 0 | done: |
326 | 0 | return stat; |
327 | 0 | } |
328 | | |
329 | | #ifdef USE_NETCDF4 |
330 | | /* Recursive type walker: reclaim an instance of variable-sized user-defined types; |
331 | | specifically a vlen or a variable-sized compound type instance |
332 | | */ |
333 | | static int |
334 | | copy_datar(NC_FILE_INFO_T* file, NC_TYPE_INFO_T* utype, Position src, Position dst) |
335 | 0 | { |
336 | 0 | int i, stat = NC_NOERR; |
337 | 0 | nc_type basetypeid; |
338 | 0 | NC_TYPE_INFO_T* basetype = NULL; |
339 | 0 | size_t nfields; |
340 | 0 | nc_vlen_t* srcvlens = NULL; |
341 | 0 | nc_vlen_t* dstvlens = NULL; |
342 | 0 | size_t fid, arraycount; |
343 | 0 | int ndims; |
344 | 0 | int dimsizes[NC_MAX_VAR_DIMS]; |
345 | 0 | Position vsrc, vdst; |
346 | 0 | size_t alignment = 0; |
347 | |
|
348 | 0 | assert(utype->varsized); /* All fixed size cases are optimized out */ |
349 | | |
350 | | /* Leaving VLEN or Compound */ |
351 | |
|
352 | 0 | if(utype->nc_type_class == NC_VLEN) { |
353 | 0 | size_t basetypesize = 0; |
354 | 0 | size_t copycount = 0; |
355 | |
|
356 | 0 | basetypeid = utype->u.v.base_nc_typeid; /* Get basetype */ |
357 | 0 | srcvlens = (nc_vlen_t*)src.memory; |
358 | 0 | dstvlens = (nc_vlen_t*)dst.memory; |
359 | 0 | dstvlens->len = srcvlens->len; /* always */ |
360 | |
|
361 | 0 | if(srcvlens->len == 0) { |
362 | 0 | dstvlens->p = NULL; |
363 | 0 | goto done; |
364 | 0 | } |
365 | | |
366 | 0 | if(basetypeid <= NC_MAX_ATOMIC_TYPE) |
367 | 0 | basetypesize = NC_atomictypelen(basetypeid); |
368 | 0 | copycount = srcvlens->len*basetypesize; |
369 | | |
370 | | /* Optimize: basetype is atomic fixed size */ |
371 | 0 | if(basetypeid < NC_STRING) { |
372 | 0 | if((dstvlens->p = (void*)malloc(copycount))==NULL) {stat = NC_ENOMEM; goto done;} |
373 | 0 | memcpy(dstvlens->p,srcvlens->p,copycount); |
374 | 0 | goto done; |
375 | 0 | } |
376 | | |
377 | | /* Optimize: basetype is string */ |
378 | 0 | if(basetypeid == NC_STRING) { |
379 | 0 | char** srcstrvec = (char**)srcvlens->p; |
380 | 0 | char** dststrvec = NULL; |
381 | 0 | if((dststrvec = (void*)malloc(copycount))==NULL) {stat = NC_ENOMEM; goto done;} |
382 | 0 | dstvlens->p = (void*)dststrvec; |
383 | 0 | for(i=0;i<srcvlens->len;i++) { |
384 | 0 | if((dststrvec[i] = strdup(srcstrvec[i]))==NULL) {stat = NC_ENOMEM; goto done;} |
385 | 0 | } |
386 | 0 | goto done; |
387 | 0 | } |
388 | | |
389 | | /* User-defined type */ |
390 | | /* Recompute base type size */ |
391 | 0 | if((stat = nc4_find_type(file,basetypeid,&basetype))) goto done; |
392 | 0 | basetypesize = basetype->size; |
393 | 0 | copycount = srcvlens->len*basetypesize; |
394 | | |
395 | | /* Optimize: basetype is user-type fixed size */ |
396 | 0 | if(!basetype->varsized) { |
397 | 0 | if((dstvlens->p = (void*)malloc(copycount))==NULL) {stat = NC_ENOMEM; goto done;} |
398 | 0 | memcpy(dstvlens->p,srcvlens->p,copycount); |
399 | 0 | goto done; |
400 | 0 | } |
401 | | |
402 | | /* Remaining case: basetype is itself variable size => recurse */ |
403 | 0 | if((stat = NC_type_alignment_internal(file,basetypeid,basetype,&alignment))) goto done;; |
404 | 0 | vsrc.memory = (char*)srcvlens->p; /* use char* so we can do pointer arithmetic */ |
405 | 0 | if((vdst.memory = (char*)malloc(copycount))==NULL) {stat = NC_ENOMEM; goto done;} |
406 | 0 | dstvlens->p = vdst.memory; /* don't lose it */ |
407 | 0 | vsrc.memory = (void*)NC_read_align((uintptr_t)vsrc.memory,alignment); |
408 | 0 | vdst.memory = (void*)NC_read_align((uintptr_t)vdst.memory,alignment); |
409 | 0 | for(i=0;i<srcvlens->len;i++) { |
410 | 0 | if((stat=copy_datar(file,basetype,vsrc,vdst))) goto done; |
411 | 0 | vsrc.memory += basetype->size; |
412 | 0 | vdst.memory += basetype->size; |
413 | 0 | } |
414 | 0 | goto done; |
415 | 0 | } else if(utype->nc_type_class == NC_COMPOUND) { |
416 | 0 | Position fsrc; /* mark the src fields's instance */ |
417 | 0 | Position fdst; /* mark the dst fields's instance */ |
418 | 0 | nfields = nclistlength(utype->u.c.field); |
419 | | /* Get info about each field in turn and copy it */ |
420 | 0 | for(fid=0;fid<nfields;fid++) { |
421 | 0 | NC_FIELD_INFO_T* field = NULL; |
422 | | |
423 | 0 | field = (NC_FIELD_INFO_T*)nclistget(utype->u.c.field,fid); |
424 | 0 | ndims = field->ndims; |
425 | 0 | arraycount = 1; |
426 | 0 | for(i=0;i<ndims;i++) {dimsizes[i] = field->dim_size[i]; arraycount *= (size_t)dimsizes[i];} |
427 | 0 | if(field->ndims == 0) {ndims=1; dimsizes[0]=1;} /* fake the scalar case */ |
428 | | |
429 | | /* "move" to this field */ |
430 | 0 | fsrc.memory = src.memory + field->offset; |
431 | 0 | fdst.memory = dst.memory + field->offset; |
432 | | |
433 | | /* optimize: fixed length atomic type */ |
434 | 0 | if(field->nc_typeid < NC_STRING) { |
435 | 0 | size_t typesize = NC_atomictypelen(field->nc_typeid); |
436 | 0 | memcpy(fdst.memory,fsrc.memory,arraycount*typesize); |
437 | 0 | continue; /* move to next field */ |
438 | 0 | } |
439 | | |
440 | | /* optimize: string field type */ |
441 | 0 | if(field->nc_typeid == NC_STRING) { |
442 | 0 | char** srcstrvec = (char**)fsrc.memory; |
443 | 0 | char** dststrvec = (char**)fdst.memory; |
444 | 0 | for(i=0;i<arraycount;i++) |
445 | 0 | {if(srcstrvec[i] != NULL) {dststrvec[i] = strdup(srcstrvec[i]);} else {dststrvec[i] = NULL;}} |
446 | 0 | continue; /* move to next field */ |
447 | 0 | } |
448 | | |
449 | | /* optimize: fixed length compound base type */ |
450 | 0 | if((stat = nc4_find_type(file,field->nc_typeid,&basetype))) goto done; |
451 | 0 | if(!basetype->varsized) { |
452 | 0 | memcpy(fdst.memory,fsrc.memory,arraycount*basetype->size); |
453 | 0 | continue; /* move to next field */ |
454 | 0 | } |
455 | | |
456 | | /* Remaining case; field type is variable type */ |
457 | 0 | for(i=0;i<arraycount;i++) { |
458 | 0 | if((stat = copy_datar(file, basetype, fsrc, fdst))) goto done; |
459 | 0 | fsrc.memory += basetype->size; |
460 | 0 | fdst.memory += basetype->size; |
461 | 0 | } |
462 | 0 | } |
463 | 0 | goto done; |
464 | |
|
465 | 0 | } else {stat = NC_EBADTYPE; goto done;} |
466 | | |
467 | 0 | done: |
468 | 0 | return stat; |
469 | 0 | } |
470 | | #endif |
471 | | |
472 | | /**************************************************/ |
473 | | /* Alignment functions */ |
474 | | |
475 | | #ifdef USE_NETCDF4 |
476 | | uintptr_t |
477 | | NC_read_align(uintptr_t addr, size_t alignment) |
478 | 0 | { |
479 | 0 | size_t loc_align = (alignment == 0 ? 1 : alignment); |
480 | 0 | size_t delta = (addr % loc_align); |
481 | 0 | if(delta == 0) return addr; |
482 | 0 | return (addr + (alignment - delta)); |
483 | 0 | } |
484 | | |
485 | | |
486 | | /** |
487 | | * Compute proper data alignment for a type |
488 | | * @param file - only needed for a compound type |
489 | | * @param xtype - type for which alignment is requested |
490 | | * @param utype - if known |
491 | | * @return 0 if not found |
492 | | */ |
493 | | int |
494 | | NC_type_alignment_internal(NC_FILE_INFO_T* file, nc_type xtype, NC_TYPE_INFO_T* utype, size_t* alignp) |
495 | 0 | { |
496 | 0 | int stat = NC_NOERR; |
497 | 0 | size_t align = 0; |
498 | 0 | int klass; |
499 | |
|
500 | 0 | if(!type_alignment_initialized) { |
501 | 0 | NC_compute_alignments(); |
502 | 0 | type_alignment_initialized = 1; |
503 | 0 | } |
504 | 0 | if(xtype <= NC_MAX_ATOMIC_TYPE) |
505 | 0 | {stat = NC_class_alignment(xtype,&align); goto done;} |
506 | 0 | else {/* Presumably a user type */ |
507 | 0 | if(utype == NULL) { |
508 | 0 | if((stat = nc4_find_type(file,xtype,&utype))) goto done; |
509 | 0 | } |
510 | 0 | klass = utype->nc_type_class; |
511 | 0 | switch(klass) { |
512 | 0 | case NC_VLEN: stat = NC_class_alignment(klass,&align); break; |
513 | 0 | case NC_OPAQUE: stat = NC_class_alignment(klass,&align); break; |
514 | 0 | case NC_COMPOUND: {/* get alignment of the first field of the compound */ |
515 | 0 | NC_FIELD_INFO_T* field = NULL; |
516 | 0 | NC_TYPE_INFO_T* basetype = NULL; |
517 | 0 | if(nclistlength(utype->u.c.field) == 0) {stat = NC_EINVAL; goto done;} |
518 | 0 | field = (NC_FIELD_INFO_T*)nclistget(utype->u.c.field,0); |
519 | 0 | if(field->nc_typeid <= NC_MAX_ATOMIC_TYPE) { |
520 | 0 | if((stat = nc4_find_type(file,field->nc_typeid,&basetype))) goto done; |
521 | 0 | } |
522 | 0 | stat = NC_type_alignment_internal(file,field->nc_typeid,basetype,&align); /* may recurse repeatedly */ |
523 | 0 | } break; |
524 | 0 | default: break; |
525 | 0 | } |
526 | 0 | } |
527 | 0 | if(alignp) *alignp = align; |
528 | |
|
529 | 0 | done: |
530 | | #if 0 |
531 | | Why was this here? |
532 | | if(stat == NC_NOERR && align == 0) stat = NC_EINVAL; |
533 | | #endif |
534 | 0 | return stat; |
535 | 0 | } |
536 | | #endif |
537 | | |
538 | | /**************************************************/ |
539 | | |
540 | | /* Internal versions of the XX_all functions */ |
541 | | |
542 | | /* Alternate entry point: includes recovering the top-level memory */ |
543 | | int |
544 | | NC_reclaim_data_all(NC* nc, nc_type xtypeid, void* memory, size_t count) |
545 | 0 | { |
546 | 0 | int stat = NC_NOERR; |
547 | |
|
548 | 0 | assert(nc != NULL); |
549 | |
|
550 | 0 | stat = NC_reclaim_data(nc,xtypeid,memory,count); |
551 | 0 | if(stat == NC_NOERR && memory != NULL) |
552 | 0 | free(memory); |
553 | 0 | return stat; |
554 | 0 | } |
555 | | |
556 | | /* Alternate entry point: includes recovering the top-level memory */ |
557 | | int |
558 | | NC_copy_data_all(NC* nc, nc_type xtype, const void* memory, size_t count, void** copyp) |
559 | 0 | { |
560 | 0 | int stat = NC_NOERR; |
561 | 0 | size_t xsize = 0; |
562 | 0 | void* copy = NULL; |
563 | 0 | NC_FILE_INFO_T* file = NULL; |
564 | 0 | NC_TYPE_INFO_T* utype = NULL; |
565 | |
|
566 | 0 | assert(nc != NULL); |
567 | |
|
568 | 0 | if(xtype <= NC_STRING && count > 0) { |
569 | 0 | xsize = NC_atomictypelen(xtype); |
570 | 0 | if((copy = calloc(count,xsize))==NULL) {stat = NC_ENOMEM; goto done;} |
571 | 0 | if(xtype < NC_STRING) /* fixed-size atomic type */ |
572 | 0 | memcpy(copy,memory,xsize*count); |
573 | 0 | else { /* string type */ |
574 | 0 | size_t i; |
575 | 0 | char** strvec = (char**)memory; |
576 | 0 | char** scopyvec = (char**)copy; |
577 | 0 | for(i=0;i<count;i++) { |
578 | 0 | char* s = strvec[i]; |
579 | 0 | char* sdup = NULL; |
580 | 0 | if(s != NULL) sdup = strdup(s); |
581 | 0 | scopyvec[i] = sdup; |
582 | 0 | } |
583 | 0 | } |
584 | 0 | } |
585 | 0 | #ifdef USE_NETCDF4 |
586 | 0 | else { |
587 | 0 | file = (NC_FILE_INFO_T*)(nc)->dispatchdata; |
588 | 0 | if((stat = nc4_find_type(file,xtype,&utype))) goto done; |
589 | 0 | xsize = utype->size; |
590 | | /* allocate the top-level */ |
591 | 0 | if(count > 0) { |
592 | 0 | if((copy = calloc(count,xsize))==NULL) {stat = NC_ENOMEM; goto done;} |
593 | 0 | } |
594 | 0 | if((stat = NC_copy_data(nc,xtype,memory,count,copy))) |
595 | 0 | (void)NC_reclaim_data_all(nc,xtype,copy,count); |
596 | 0 | } |
597 | 0 | #endif |
598 | 0 | if(copyp) {*copyp = copy; copy = NULL;} |
599 | 0 | done: |
600 | 0 | return stat; |
601 | 0 | } |
602 | | |
603 | | /* Alternate entry point: includes recovering the top-level memory */ |
604 | | int |
605 | | NC_print_data(NC_FILE_INFO_T* file, nc_type xtype, const void* memory, size_t count) |
606 | 0 | { |
607 | 0 | EXTERNL int nc_print_data(int ncid, nc_type xtype, const void* memory, size_t count); |
608 | 0 | return nc_print_data(file->controller->ext_ncid,xtype,memory,count); |
609 | 0 | } |
610 | | |