/src/hdf5/src/H5Tcompound.c
Line | Count | Source |
1 | | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | | * Copyright by The HDF Group. * |
3 | | * All rights reserved. * |
4 | | * * |
5 | | * This file is part of HDF5. The full HDF5 copyright notice, including * |
6 | | * terms governing use, modification, and redistribution, is contained in * |
7 | | * the LICENSE file, which can be found at the root of the source code * |
8 | | * distribution tree, or in https://www.hdfgroup.org/licenses. * |
9 | | * If you do not have access to either file, you may request a copy from * |
10 | | * help@hdfgroup.org. * |
11 | | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
12 | | |
13 | | /* |
14 | | * Module Info: This module contains the functionality for compound datatypes |
15 | | * in the H5T interface. |
16 | | */ |
17 | | |
18 | | /****************/ |
19 | | /* Module Setup */ |
20 | | /****************/ |
21 | | |
22 | | #include "H5Tmodule.h" /* This source code file is part of the H5T module */ |
23 | | |
24 | | /***********/ |
25 | | /* Headers */ |
26 | | /***********/ |
27 | | #include "H5private.h" /*generic functions */ |
28 | | #include "H5Eprivate.h" /*error handling */ |
29 | | #include "H5Iprivate.h" /*ID functions */ |
30 | | #include "H5MMprivate.h" /*memory management */ |
31 | | #include "H5Tpkg.h" /*data-type functions */ |
32 | | |
33 | | /****************/ |
34 | | /* Local Macros */ |
35 | | /****************/ |
36 | | |
37 | | /******************/ |
38 | | /* Local Typedefs */ |
39 | | /******************/ |
40 | | |
41 | | /********************/ |
42 | | /* Package Typedefs */ |
43 | | /********************/ |
44 | | |
45 | | /********************/ |
46 | | /* Local Prototypes */ |
47 | | /********************/ |
48 | | static herr_t H5T__pack(const H5T_t *dt); |
49 | | static htri_t H5T__is_packed(const H5T_t *dt); |
50 | | static H5T_t *H5T__reopen_member_type(const H5T_t *dt, unsigned membno); |
51 | | |
52 | | /*********************/ |
53 | | /* Public Variables */ |
54 | | /*********************/ |
55 | | |
56 | | /*********************/ |
57 | | /* Package Variables */ |
58 | | /*********************/ |
59 | | |
60 | | /*****************************/ |
61 | | /* Library Private Variables */ |
62 | | /*****************************/ |
63 | | |
64 | | /*******************/ |
65 | | /* Local Variables */ |
66 | | /*******************/ |
67 | | |
68 | | /*------------------------------------------------------------------------- |
69 | | * Function: H5Tget_member_offset |
70 | | * |
71 | | * Purpose: Returns the byte offset of the beginning of a member with |
72 | | * respect to the beginning of the compound datatype datum. |
73 | | * |
74 | | * Return: Success: Byte offset. |
75 | | * |
76 | | * Failure: Zero. Zero is a valid offset, but this |
77 | | * function will fail only if a call to |
78 | | * H5Tget_member_dims() fails with the same |
79 | | * arguments. |
80 | | * |
81 | | *------------------------------------------------------------------------- |
82 | | */ |
83 | | size_t |
84 | | H5Tget_member_offset(hid_t type_id, unsigned membno) |
85 | 0 | { |
86 | 0 | H5T_t *dt; /* Datatype to query */ |
87 | 0 | size_t ret_value; /* Return value */ |
88 | |
|
89 | 0 | FUNC_ENTER_API(0) |
90 | | |
91 | | /* Check args */ |
92 | 0 | if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)) || H5T_COMPOUND != dt->shared->type) |
93 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, 0, "not a compound datatype"); |
94 | 0 | if (membno >= dt->shared->u.compnd.nmembs) |
95 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, 0, "invalid member number"); |
96 | | |
97 | | /* Value */ |
98 | 0 | ret_value = H5T_GET_MEMBER_OFFSET(dt->shared, membno); |
99 | |
|
100 | 0 | done: |
101 | 0 | FUNC_LEAVE_API(ret_value) |
102 | 0 | } /* end H5Tget_member_offset() */ |
103 | | |
104 | | /*------------------------------------------------------------------------- |
105 | | * Function: H5T_get_member_offset |
106 | | * |
107 | | * Purpose: Private function for H5Tget_member_offset. Returns the byte |
108 | | * offset of the beginning of a member with respect to the |
109 | | * beginning of the compound datatype datum. |
110 | | * |
111 | | * Return: Success: Byte offset. |
112 | | * |
113 | | * Failure: Zero. Zero is a valid offset, but this |
114 | | * function will fail only if a call to |
115 | | * H5Tget_member_dims() fails with the same |
116 | | * arguments. |
117 | | * |
118 | | *------------------------------------------------------------------------- |
119 | | */ |
120 | | size_t |
121 | | H5T_get_member_offset(const H5T_t *dt, unsigned membno) |
122 | 0 | { |
123 | 0 | FUNC_ENTER_NOAPI_NOINIT_NOERR |
124 | |
|
125 | 0 | assert(dt); |
126 | 0 | assert(membno < dt->shared->u.compnd.nmembs); |
127 | |
|
128 | 0 | FUNC_LEAVE_NOAPI(dt->shared->u.compnd.memb[membno].offset) |
129 | 0 | } /* end H5T_get_member_offset() */ |
130 | | |
131 | | /*------------------------------------------------------------------------- |
132 | | * Function: H5Tget_member_class |
133 | | * |
134 | | * Purpose: Returns the datatype class of a member of a compound datatype. |
135 | | * |
136 | | * Return: Success: Non-negative |
137 | | * |
138 | | * Failure: H5T_NO_CLASS |
139 | | * |
140 | | *------------------------------------------------------------------------- |
141 | | */ |
142 | | H5T_class_t |
143 | | H5Tget_member_class(hid_t type_id, unsigned membno) |
144 | 0 | { |
145 | 0 | H5T_t *dt; /* Datatype to query */ |
146 | 0 | H5T_class_t ret_value; /* Return value */ |
147 | |
|
148 | 0 | FUNC_ENTER_API(H5T_NO_CLASS) |
149 | | |
150 | | /* Check args */ |
151 | 0 | if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)) || H5T_COMPOUND != dt->shared->type) |
152 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5T_NO_CLASS, "not a compound datatype"); |
153 | 0 | if (membno >= dt->shared->u.compnd.nmembs) |
154 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5T_NO_CLASS, "invalid member number"); |
155 | | |
156 | | /* Get the type's class. We have to use this function to get type class |
157 | | * because of the concern of variable-length string. |
158 | | */ |
159 | 0 | ret_value = H5T_GET_CLASS(dt->shared->u.compnd.memb[membno].type->shared, false); |
160 | |
|
161 | 0 | done: |
162 | 0 | FUNC_LEAVE_API(ret_value) |
163 | 0 | } /* end H5Tget_member_class() */ |
164 | | |
165 | | /*------------------------------------------------------------------------- |
166 | | * Function: H5Tget_member_type |
167 | | * |
168 | | * Purpose: Returns the datatype of the specified member. The caller |
169 | | * should invoke H5Tclose() to release resources associated with |
170 | | * the type. |
171 | | * |
172 | | * Return: Success: An OID of a copy of the member datatype; |
173 | | * modifying the returned datatype does not |
174 | | * modify the member type. |
175 | | * |
176 | | * Failure: H5I_INVALID_HID |
177 | | * |
178 | | *------------------------------------------------------------------------- |
179 | | */ |
180 | | hid_t |
181 | | H5Tget_member_type(hid_t type_id, unsigned membno) |
182 | 0 | { |
183 | 0 | H5T_t *dt; /* Datatype to query */ |
184 | 0 | H5T_t *memb_dt = NULL; /* Member datatype */ |
185 | 0 | hid_t ret_value; /* Return value */ |
186 | |
|
187 | 0 | FUNC_ENTER_API(H5I_INVALID_HID) |
188 | | |
189 | | /* Check args */ |
190 | 0 | if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)) || H5T_COMPOUND != dt->shared->type) |
191 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a compound datatype"); |
192 | 0 | if (membno >= dt->shared->u.compnd.nmembs) |
193 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "invalid member number"); |
194 | | |
195 | | /* Retrieve the datatype for the member */ |
196 | 0 | if (NULL == (memb_dt = H5T__reopen_member_type(dt, membno))) |
197 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, H5I_INVALID_HID, "unable to retrieve member type"); |
198 | | |
199 | | /* Get an ID for the datatype */ |
200 | 0 | if ((ret_value = H5I_register(H5I_DATATYPE, memb_dt, true)) < 0) |
201 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTREGISTER, H5I_INVALID_HID, "unable register datatype ID"); |
202 | | |
203 | 0 | done: |
204 | 0 | if (ret_value < 0) |
205 | 0 | if (memb_dt && H5T_close(memb_dt) < 0) |
206 | 0 | HDONE_ERROR(H5E_DATATYPE, H5E_CANTCLOSEOBJ, H5I_INVALID_HID, "can't close datatype"); |
207 | |
|
208 | 0 | FUNC_LEAVE_API(ret_value) |
209 | 0 | } /* end H5Tget_member_type() */ |
210 | | |
211 | | /*------------------------------------------------------------------------- |
212 | | * Function: H5T_get_member_type |
213 | | * |
214 | | * Purpose: Returns a copy of the data type of the specified member. |
215 | | * |
216 | | * Return: Success: A copy of the member datatype; |
217 | | * modifying the returned datatype does not |
218 | | * modify the member type. |
219 | | * |
220 | | * Failure: NULL |
221 | | * |
222 | | *------------------------------------------------------------------------- |
223 | | */ |
224 | | H5T_t * |
225 | | H5T_get_member_type(const H5T_t *dt, unsigned membno) |
226 | 0 | { |
227 | 0 | H5T_t *ret_value = NULL; /* Return value */ |
228 | |
|
229 | 0 | FUNC_ENTER_NOAPI(NULL) |
230 | | |
231 | | /* Sanity checks */ |
232 | 0 | assert(dt); |
233 | 0 | assert(membno < dt->shared->u.compnd.nmembs); |
234 | | |
235 | | /* Copy datatype */ |
236 | 0 | if (NULL == (ret_value = H5T_copy(dt->shared->u.compnd.memb[membno].type, H5T_COPY_TRANSIENT))) |
237 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "unable to copy member datatype"); |
238 | | |
239 | 0 | done: |
240 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
241 | 0 | } /* end H5T_get_member_type() */ |
242 | | |
243 | | /*------------------------------------------------------------------------- |
244 | | * Function: H5T__reopen_member_type |
245 | | * |
246 | | * Purpose: Private function for H5Tget_member_type. Returns a re-opened |
247 | | * copy of the data type of the specified member. |
248 | | * |
249 | | * Return: Success: A copy of the member datatype; |
250 | | * modifying the returned datatype does not |
251 | | * modify the member type. |
252 | | * |
253 | | * Failure: NULL |
254 | | * |
255 | | *------------------------------------------------------------------------- |
256 | | */ |
257 | | static H5T_t * |
258 | | H5T__reopen_member_type(const H5T_t *dt, unsigned membno) |
259 | 0 | { |
260 | 0 | H5T_t *ret_value = NULL; /* Return value */ |
261 | |
|
262 | 0 | FUNC_ENTER_PACKAGE |
263 | | |
264 | | /* Sanity checks */ |
265 | 0 | assert(dt); |
266 | 0 | assert(membno < dt->shared->u.compnd.nmembs); |
267 | | |
268 | | /* Copy datatype, possibly re-opening it */ |
269 | 0 | if (NULL == (ret_value = H5T_copy_reopen(dt->shared->u.compnd.memb[membno].type))) |
270 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, NULL, "unable to reopen member datatype"); |
271 | | |
272 | 0 | done: |
273 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
274 | 0 | } /* end H5T__reopen_member_type() */ |
275 | | |
276 | | /*------------------------------------------------------------------------- |
277 | | * Function: H5T__get_member_size |
278 | | * |
279 | | * Purpose: Returns the size of the specified member. |
280 | | * |
281 | | * Return: Success: The size in bytes of the member's datatype. |
282 | | * Failure: 0 |
283 | | * |
284 | | *------------------------------------------------------------------------- |
285 | | */ |
286 | | size_t |
287 | | H5T__get_member_size(const H5T_t *dt, unsigned membno) |
288 | 0 | { |
289 | 0 | FUNC_ENTER_PACKAGE_NOERR |
290 | |
|
291 | 0 | assert(dt); |
292 | 0 | assert(membno < dt->shared->u.compnd.nmembs); |
293 | |
|
294 | 0 | FUNC_LEAVE_NOAPI(dt->shared->u.compnd.memb[membno].type->shared->size) |
295 | 0 | } /* end H5T__get_member_size() */ |
296 | | |
297 | | /*------------------------------------------------------------------------- |
298 | | * Function: H5Tinsert |
299 | | * |
300 | | * Purpose: Adds another member to the compound datatype PARENT_ID. The |
301 | | * new member has a NAME which must be unique within the |
302 | | * compound datatype. The OFFSET argument defines the start of |
303 | | * the member in an instance of the compound datatype, and |
304 | | * MEMBER_ID is the type of the new member. |
305 | | * |
306 | | * Return: Success: Non-negative, the PARENT_ID compound data |
307 | | * type is modified to include a copy of the |
308 | | * member type MEMBER_ID. |
309 | | * |
310 | | * Failure: Negative |
311 | | * |
312 | | * Errors: |
313 | | * |
314 | | *------------------------------------------------------------------------- |
315 | | */ |
316 | | herr_t |
317 | | H5Tinsert(hid_t parent_id, const char *name, size_t offset, hid_t member_id) |
318 | 0 | { |
319 | 0 | H5T_t *parent; /* The compound parent datatype */ |
320 | 0 | H5T_t *member; /* The member datatype */ |
321 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
322 | |
|
323 | 0 | FUNC_ENTER_API(FAIL) |
324 | | |
325 | | /* Check args */ |
326 | 0 | if (parent_id == member_id) |
327 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "can't insert compound datatype within itself"); |
328 | 0 | if (NULL == (parent = (H5T_t *)H5I_object_verify(parent_id, H5I_DATATYPE)) || |
329 | 0 | H5T_COMPOUND != parent->shared->type) |
330 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a compound datatype"); |
331 | 0 | if (H5T_STATE_TRANSIENT != parent->shared->state) |
332 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "parent type read-only"); |
333 | 0 | if (!name || !*name) |
334 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no member name"); |
335 | 0 | if (NULL == (member = (H5T_t *)H5I_object_verify(member_id, H5I_DATATYPE))) |
336 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype"); |
337 | | |
338 | | /* Insert */ |
339 | 0 | if (H5T__insert(parent, name, offset, member) < 0) |
340 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINSERT, FAIL, "unable to insert member"); |
341 | | |
342 | 0 | done: |
343 | 0 | FUNC_LEAVE_API(ret_value) |
344 | 0 | } /* end H5Tinsert() */ |
345 | | |
346 | | /*------------------------------------------------------------------------- |
347 | | * Function: H5Tpack |
348 | | * |
349 | | * Purpose: Recursively removes padding from within a compound datatype |
350 | | * to make it more efficient (space-wise) to store that data. |
351 | | * |
352 | | * Return: Non-negative on success/Negative on failure |
353 | | * |
354 | | *------------------------------------------------------------------------- |
355 | | */ |
356 | | herr_t |
357 | | H5Tpack(hid_t type_id) |
358 | 0 | { |
359 | 0 | H5T_t *dt; /* Datatype to modify */ |
360 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
361 | |
|
362 | 0 | FUNC_ENTER_API(FAIL) |
363 | | |
364 | | /* Check args */ |
365 | 0 | if (NULL == (dt = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)) || |
366 | 0 | H5T_detect_class(dt, H5T_COMPOUND, true) <= 0) |
367 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a compound datatype"); |
368 | | |
369 | | /* Pack */ |
370 | 0 | if (H5T__pack(dt) < 0) |
371 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to pack compound datatype"); |
372 | | |
373 | 0 | done: |
374 | 0 | FUNC_LEAVE_API(ret_value) |
375 | 0 | } /* end H5Tpack() */ |
376 | | |
377 | | /*------------------------------------------------------------------------- |
378 | | * Function: H5T__insert |
379 | | * |
380 | | * Purpose: Adds a new MEMBER to the compound datatype PARENT. The new |
381 | | * member will have a NAME that is unique within PARENT and an |
382 | | * instance of PARENT will have the member begin at byte offset |
383 | | * OFFSET from the beginning. |
384 | | * |
385 | | * Return: Non-negative on success/Negative on failure |
386 | | * |
387 | | *------------------------------------------------------------------------- |
388 | | */ |
389 | | herr_t |
390 | | H5T__insert(H5T_t *parent, const char *name, size_t offset, const H5T_t *member) |
391 | 0 | { |
392 | 0 | unsigned idx; /* Index of member to insert */ |
393 | 0 | size_t total_size; |
394 | 0 | unsigned i; /* Local index variable */ |
395 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
396 | |
|
397 | 0 | FUNC_ENTER_PACKAGE |
398 | | |
399 | | /* check args */ |
400 | 0 | assert(parent && H5T_COMPOUND == parent->shared->type); |
401 | 0 | assert(H5T_STATE_TRANSIENT == parent->shared->state); |
402 | 0 | assert(member); |
403 | 0 | assert(name && *name); |
404 | | |
405 | | /* Does NAME already exist in PARENT? */ |
406 | 0 | for (i = 0; i < parent->shared->u.compnd.nmembs; i++) |
407 | 0 | if (!strcmp(parent->shared->u.compnd.memb[i].name, name)) |
408 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINSERT, FAIL, "member name is not unique"); |
409 | | |
410 | | /* Does the new member overlap any existing member ? */ |
411 | 0 | total_size = member->shared->size; |
412 | 0 | for (i = 0; i < parent->shared->u.compnd.nmembs; i++) |
413 | 0 | if ((offset <= parent->shared->u.compnd.memb[i].offset && |
414 | 0 | (offset + total_size) > parent->shared->u.compnd.memb[i].offset) || |
415 | 0 | (parent->shared->u.compnd.memb[i].offset <= offset && |
416 | 0 | (parent->shared->u.compnd.memb[i].offset + parent->shared->u.compnd.memb[i].size) > offset)) |
417 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINSERT, FAIL, "member overlaps with another member"); |
418 | | |
419 | | /* Does the new member overlap the end of the compound type? */ |
420 | 0 | if ((offset + total_size) > parent->shared->size) |
421 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINSERT, FAIL, "member extends past end of compound type"); |
422 | | |
423 | | /* Increase member array if necessary */ |
424 | 0 | if (parent->shared->u.compnd.nmembs >= parent->shared->u.compnd.nalloc) { |
425 | 0 | unsigned na = MAX(1, parent->shared->u.compnd.nalloc * 2); |
426 | 0 | H5T_cmemb_t *x = (H5T_cmemb_t *)H5MM_realloc(parent->shared->u.compnd.memb, na * sizeof(H5T_cmemb_t)); |
427 | |
|
428 | 0 | if (!x) |
429 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL, "memory allocation failed"); |
430 | 0 | parent->shared->u.compnd.nalloc = na; |
431 | 0 | parent->shared->u.compnd.memb = x; |
432 | 0 | } /* end if */ |
433 | | |
434 | | /* Add member to end of member array */ |
435 | 0 | idx = parent->shared->u.compnd.nmembs; |
436 | 0 | parent->shared->u.compnd.memb[idx].offset = offset; |
437 | 0 | parent->shared->u.compnd.memb[idx].size = total_size; |
438 | 0 | if (NULL == (parent->shared->u.compnd.memb[idx].name = H5MM_xstrdup(name))) |
439 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTALLOC, FAIL, "couldn't duplicate name string"); |
440 | 0 | if (NULL == (parent->shared->u.compnd.memb[idx].type = H5T_copy(member, H5T_COPY_ALL))) |
441 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTCOPY, FAIL, "couldn't copy datatype"); |
442 | | |
443 | 0 | parent->shared->u.compnd.sorted = H5T_SORT_NONE; |
444 | 0 | parent->shared->u.compnd.nmembs++; |
445 | 0 | parent->shared->u.compnd.memb_size += total_size; |
446 | | |
447 | | /* It should not be possible to get this far if the type is already packed |
448 | | * - the new member would overlap something */ |
449 | 0 | assert(!(parent->shared->u.compnd.packed)); |
450 | | |
451 | | /* Determine if the compound datatype becomes packed */ |
452 | 0 | H5T__update_packed(parent); |
453 | | |
454 | | /* Set the "force conversion" flag if the field's datatype indicates */ |
455 | 0 | if (member->shared->force_conv == true) |
456 | 0 | parent->shared->force_conv = true; |
457 | | |
458 | | /* Check for member having a later version than the parent */ |
459 | 0 | if (parent->shared->version < member->shared->version) |
460 | | /* Upgrade parent datatype (and all other members also) */ |
461 | | /* (can't use a partial datatype and later versions of the format are |
462 | | * more efficient, so might as well upgrade all members also... -QAK) |
463 | | */ |
464 | 0 | if (H5T__upgrade_version(parent, member->shared->version) < 0) |
465 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTSET, FAIL, "can't upgrade member encoding version"); |
466 | | |
467 | 0 | done: |
468 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
469 | 0 | } /* end H5T__insert() */ |
470 | | |
471 | | /*------------------------------------------------------------------------- |
472 | | * Function: H5T__pack |
473 | | * |
474 | | * Purpose: Recursively packs a compound datatype by removing padding |
475 | | * bytes. This is done in place (that is, destructively). |
476 | | * |
477 | | * Return: Non-negative on success/Negative on failure |
478 | | * |
479 | | *------------------------------------------------------------------------- |
480 | | */ |
481 | | static herr_t |
482 | | H5T__pack(const H5T_t *dt) |
483 | 0 | { |
484 | 0 | herr_t ret_value = SUCCEED; /* Return value */ |
485 | |
|
486 | 0 | FUNC_ENTER_PACKAGE |
487 | |
|
488 | 0 | assert(dt); |
489 | |
|
490 | 0 | if (H5T_detect_class(dt, H5T_COMPOUND, false) > 0) { |
491 | | /* If datatype has been packed, skip packing it and indicate success */ |
492 | 0 | if (true == H5T__is_packed(dt)) |
493 | 0 | HGOTO_DONE(SUCCEED); |
494 | | |
495 | | /* Check for packing unmodifiable datatype */ |
496 | 0 | if (H5T_STATE_TRANSIENT != dt->shared->state) |
497 | 0 | HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "datatype is read-only"); |
498 | | |
499 | 0 | if (dt->shared->parent) { |
500 | 0 | if (H5T__pack(dt->shared->parent) < 0) |
501 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "unable to pack parent of datatype"); |
502 | | |
503 | | /* Adjust size of datatype appropriately */ |
504 | 0 | if (dt->shared->type == H5T_ARRAY) |
505 | 0 | dt->shared->size = dt->shared->parent->shared->size * dt->shared->u.array.nelem; |
506 | 0 | else if (dt->shared->type == H5T_COMPLEX) |
507 | 0 | dt->shared->size = 2 * dt->shared->parent->shared->size; |
508 | 0 | else if (dt->shared->type != H5T_VLEN) |
509 | 0 | dt->shared->size = dt->shared->parent->shared->size; |
510 | 0 | } /* end if */ |
511 | 0 | else if (dt->shared->type == H5T_COMPOUND) { |
512 | 0 | size_t offset; /* Offset of member */ |
513 | 0 | unsigned i; /* Local index variable */ |
514 | | |
515 | | /* Recursively pack the members */ |
516 | 0 | for (i = 0; i < dt->shared->u.compnd.nmembs; i++) { |
517 | 0 | if (H5T__pack(dt->shared->u.compnd.memb[i].type) < 0) |
518 | 0 | HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, |
519 | 0 | "unable to pack part of a compound datatype"); |
520 | | |
521 | | /* Update the member size */ |
522 | 0 | dt->shared->u.compnd.memb[i].size = (dt->shared->u.compnd.memb[i].type)->shared->size; |
523 | 0 | } /* end for */ |
524 | | |
525 | | /* Remove padding between members */ |
526 | 0 | if (H5T__sort_value(dt, NULL) < 0) |
527 | 0 | HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOMPARE, FAIL, "value sort failed"); |
528 | 0 | for (i = 0, offset = 0; i < dt->shared->u.compnd.nmembs; i++) { |
529 | 0 | dt->shared->u.compnd.memb[i].offset = offset; |
530 | 0 | offset += dt->shared->u.compnd.memb[i].size; |
531 | 0 | } |
532 | | |
533 | | /* Change total size */ |
534 | 0 | dt->shared->size = MAX(1, offset); |
535 | | |
536 | | /* Mark the type as packed now */ |
537 | 0 | dt->shared->u.compnd.packed = true; |
538 | 0 | } /* end if */ |
539 | 0 | } /* end if */ |
540 | | |
541 | 0 | done: |
542 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
543 | 0 | } /* end H5T__pack() */ |
544 | | |
545 | | /*------------------------------------------------------------------------- |
546 | | * Function: H5T__is_packed |
547 | | * |
548 | | * Purpose: Checks whether a datatype which is compound (or has compound |
549 | | * components) is packed. |
550 | | * |
551 | | * Return: Non-negative on success/Negative on failure |
552 | | * |
553 | | *------------------------------------------------------------------------- |
554 | | */ |
555 | | static htri_t |
556 | | H5T__is_packed(const H5T_t *dt) |
557 | 0 | { |
558 | 0 | htri_t ret_value = true; /* Return value */ |
559 | |
|
560 | 0 | FUNC_ENTER_PACKAGE_NOERR |
561 | |
|
562 | 0 | assert(dt); |
563 | | |
564 | | /* Go up the chain as far as possible */ |
565 | 0 | while (dt->shared->parent) |
566 | 0 | dt = dt->shared->parent; |
567 | | |
568 | | /* If this is a compound datatype, check if it is packed */ |
569 | 0 | if (dt->shared->type == H5T_COMPOUND) |
570 | 0 | ret_value = (htri_t)(dt->shared->u.compnd.packed); |
571 | |
|
572 | 0 | FUNC_LEAVE_NOAPI(ret_value) |
573 | 0 | } /* end H5T__is_packed() */ |
574 | | |
575 | | /*------------------------------------------------------------------------- |
576 | | * Function: H5T__update_packed |
577 | | * |
578 | | * Purpose: Checks whether a datatype which is compound became packed |
579 | | * after recent changes. This function does not assume that |
580 | | * the status of the "packed" field is correct, and sets |
581 | | * this field to the correct value. |
582 | | * |
583 | | * Return: void |
584 | | * |
585 | | *------------------------------------------------------------------------- |
586 | | */ |
587 | | void |
588 | | H5T__update_packed(const H5T_t *dt) |
589 | 0 | { |
590 | 0 | unsigned i; /* Index */ |
591 | |
|
592 | 0 | FUNC_ENTER_PACKAGE_NOERR |
593 | |
|
594 | 0 | assert(dt); |
595 | 0 | assert(dt->shared->type == H5T_COMPOUND); |
596 | | |
597 | | /* First check if all space is used in the "top level" type */ |
598 | 0 | if (dt->shared->size == dt->shared->u.compnd.memb_size) { |
599 | | /* Set the packed flag to true */ |
600 | 0 | dt->shared->u.compnd.packed = true; |
601 | | |
602 | | /* Now check if all members are packed */ |
603 | 0 | for (i = 0; i < dt->shared->u.compnd.nmembs; i++) |
604 | 0 | if (!H5T__is_packed(dt->shared->u.compnd.memb[i].type)) { |
605 | 0 | dt->shared->u.compnd.packed = false; |
606 | 0 | break; |
607 | 0 | } /* end if */ |
608 | 0 | } /* end if */ |
609 | 0 | else |
610 | 0 | dt->shared->u.compnd.packed = false; |
611 | |
|
612 | 0 | FUNC_LEAVE_NOAPI_VOID |
613 | 0 | } /* end H5T__update_packed() */ |