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 COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://www.hdfgroup.org/licenses. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 /****************/
15 /* Module Setup */
16 /****************/
17
18 #include "H5Dmodule.h" /* This source code file is part of the H5D module */
19
20 /***********/
21 /* Headers */
22 /***********/
23 #include "H5private.h" /* Generic Functions */
24 #include "H5CXprivate.h" /* API Contexts */
25 #include "H5Dpkg.h" /* Dataset functions */
26 #include "H5Eprivate.h" /* Error handling */
27 #include "H5FLprivate.h" /* Free Lists */
28 #include "H5Iprivate.h" /* IDs */
29 #include "H5MMprivate.h" /* Memory management */
30
31 /****************/
32 /* Local Macros */
33 /****************/
34
35 /******************/
36 /* Local Typedefs */
37 /******************/
38
39 /********************/
40 /* Local Prototypes */
41 /********************/
42 static herr_t H5D__scatter_file(const H5D_io_info_t *io_info, H5S_sel_iter_t *file_iter, size_t nelmts,
43 const void *buf);
44 static size_t H5D__gather_file(const H5D_io_info_t *io_info, H5S_sel_iter_t *file_iter, size_t nelmts,
45 void *buf);
46 static herr_t H5D__compound_opt_read(size_t nelmts, H5S_sel_iter_t *iter, const H5D_type_info_t *type_info,
47 void *user_buf /*out*/);
48 static herr_t H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info);
49
50 /*********************/
51 /* Package Variables */
52 /*********************/
53
54 /*******************/
55 /* Local Variables */
56 /*******************/
57
58 /* Declare extern free list to manage the H5S_sel_iter_t struct */
59 H5FL_EXTERN(H5S_sel_iter_t);
60
61 /* Declare extern free list to manage sequences of size_t */
62 H5FL_SEQ_EXTERN(size_t);
63
64 /* Declare extern free list to manage sequences of hsize_t */
65 H5FL_SEQ_EXTERN(hsize_t);
66
67 /*-------------------------------------------------------------------------
68 * Function: H5D__scatter_file
69 *
70 * Purpose: Scatters dataset elements from the type conversion buffer BUF
71 * to the file F where the data points are arranged according to
72 * the file dataspace FILE_SPACE and stored according to
73 * LAYOUT and EFL. Each element is ELMT_SIZE bytes.
74 * The caller is requesting that NELMTS elements are copied.
75 *
76 * Return: Non-negative on success/Negative on failure
77 *
78 * Programmer: Quincey Koziol
79 * Thursday, June 20, 2002
80 *
81 *-------------------------------------------------------------------------
82 */
83 static herr_t
H5D__scatter_file(const H5D_io_info_t * _io_info,H5S_sel_iter_t * iter,size_t nelmts,const void * _buf)84 H5D__scatter_file(const H5D_io_info_t *_io_info, H5S_sel_iter_t *iter, size_t nelmts, const void *_buf)
85 {
86 H5D_io_info_t tmp_io_info; /* Temporary I/O info object */
87 hsize_t * off = NULL; /* Pointer to sequence offsets */
88 hsize_t mem_off; /* Offset in memory */
89 size_t mem_curr_seq; /* "Current sequence" in memory */
90 size_t dset_curr_seq; /* "Current sequence" in dataset */
91 size_t * len = NULL; /* Array to store sequence lengths */
92 size_t orig_mem_len, mem_len; /* Length of sequence in memory */
93 size_t nseq; /* Number of sequences generated */
94 size_t nelem; /* Number of elements used in sequences */
95 size_t dxpl_vec_size; /* Vector length from API context's DXPL */
96 size_t vec_size; /* Vector length */
97 herr_t ret_value = SUCCEED; /* Return value */
98
99 FUNC_ENTER_STATIC
100
101 /* Check args */
102 HDassert(_io_info);
103 HDassert(iter);
104 HDassert(nelmts > 0);
105 HDassert(_buf);
106
107 /* Set up temporary I/O info object */
108 H5MM_memcpy(&tmp_io_info, _io_info, sizeof(*_io_info));
109 tmp_io_info.op_type = H5D_IO_OP_WRITE;
110 tmp_io_info.u.wbuf = _buf;
111
112 /* Get info from API context */
113 if (H5CX_get_vec_size(&dxpl_vec_size) < 0)
114 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve I/O vector size")
115
116 /* Allocate the vector I/O arrays */
117 if (dxpl_vec_size > H5D_IO_VECTOR_SIZE)
118 vec_size = dxpl_vec_size;
119 else
120 vec_size = H5D_IO_VECTOR_SIZE;
121 if (NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
122 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array")
123 if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
124 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array")
125
126 /* Loop until all elements are written */
127 while (nelmts > 0) {
128 /* Get list of sequences for selection to write */
129 if (H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0)
130 HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
131
132 /* Reset the current sequence information */
133 mem_curr_seq = dset_curr_seq = 0;
134 orig_mem_len = mem_len = nelem * iter->elmt_size;
135 mem_off = 0;
136
137 /* Write sequence list out */
138 if ((*tmp_io_info.layout_ops.writevv)(&tmp_io_info, nseq, &dset_curr_seq, len, off, (size_t)1,
139 &mem_curr_seq, &mem_len, &mem_off) < 0)
140 HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error")
141
142 /* Update buffer */
143 tmp_io_info.u.wbuf = (const uint8_t *)tmp_io_info.u.wbuf + orig_mem_len;
144
145 /* Decrement number of elements left to process */
146 nelmts -= nelem;
147 } /* end while */
148
149 done:
150 /* Release resources, if allocated */
151 if (len)
152 len = H5FL_SEQ_FREE(size_t, len);
153 if (off)
154 off = H5FL_SEQ_FREE(hsize_t, off);
155
156 FUNC_LEAVE_NOAPI(ret_value)
157 } /* H5D__scatter_file() */
158
159 /*-------------------------------------------------------------------------
160 * Function: H5D__gather_file
161 *
162 * Purpose: Gathers data points from file F and accumulates them in the
163 * type conversion buffer BUF. The LAYOUT argument describes
164 * how the data is stored on disk and EFL describes how the data
165 * is organized in external files. ELMT_SIZE is the size in
166 * bytes of a datum which this function treats as opaque.
167 * FILE_SPACE describes the dataspace of the dataset on disk
168 * and the elements that have been selected for reading (via
169 * hyperslab, etc). This function will copy at most NELMTS
170 * elements.
171 *
172 * Return: Success: Number of elements copied.
173 * Failure: 0
174 *
175 * Programmer: Quincey Koziol
176 * Monday, June 24, 2002
177 *
178 *-------------------------------------------------------------------------
179 */
180 static size_t
H5D__gather_file(const H5D_io_info_t * _io_info,H5S_sel_iter_t * iter,size_t nelmts,void * _buf)181 H5D__gather_file(const H5D_io_info_t *_io_info, H5S_sel_iter_t *iter, size_t nelmts, void *_buf /*out*/)
182 {
183 H5D_io_info_t tmp_io_info; /* Temporary I/O info object */
184 hsize_t * off = NULL; /* Pointer to sequence offsets */
185 hsize_t mem_off; /* Offset in memory */
186 size_t mem_curr_seq; /* "Current sequence" in memory */
187 size_t dset_curr_seq; /* "Current sequence" in dataset */
188 size_t * len = NULL; /* Pointer to sequence lengths */
189 size_t orig_mem_len, mem_len; /* Length of sequence in memory */
190 size_t nseq; /* Number of sequences generated */
191 size_t nelem; /* Number of elements used in sequences */
192 size_t dxpl_vec_size; /* Vector length from API context's DXPL */
193 size_t vec_size; /* Vector length */
194 size_t ret_value = nelmts; /* Return value */
195
196 FUNC_ENTER_STATIC
197
198 /* Check args */
199 HDassert(_io_info);
200 HDassert(_io_info->dset);
201 HDassert(_io_info->store);
202 HDassert(iter);
203 HDassert(nelmts > 0);
204 HDassert(_buf);
205
206 /* Set up temporary I/O info object */
207 H5MM_memcpy(&tmp_io_info, _io_info, sizeof(*_io_info));
208 tmp_io_info.op_type = H5D_IO_OP_READ;
209 tmp_io_info.u.rbuf = _buf;
210
211 /* Get info from API context */
212 if (H5CX_get_vec_size(&dxpl_vec_size) < 0)
213 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, 0, "can't retrieve I/O vector size")
214
215 /* Allocate the vector I/O arrays */
216 if (dxpl_vec_size > H5D_IO_VECTOR_SIZE)
217 vec_size = dxpl_vec_size;
218 else
219 vec_size = H5D_IO_VECTOR_SIZE;
220 if (NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
221 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, 0, "can't allocate I/O length vector array")
222 if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
223 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, 0, "can't allocate I/O offset vector array")
224
225 /* Loop until all elements are read */
226 while (nelmts > 0) {
227 /* Get list of sequences for selection to read */
228 if (H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0)
229 HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed")
230
231 /* Reset the current sequence information */
232 mem_curr_seq = dset_curr_seq = 0;
233 orig_mem_len = mem_len = nelem * iter->elmt_size;
234 mem_off = 0;
235
236 /* Read sequence list in */
237 if ((*tmp_io_info.layout_ops.readvv)(&tmp_io_info, nseq, &dset_curr_seq, len, off, (size_t)1,
238 &mem_curr_seq, &mem_len, &mem_off) < 0)
239 HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error")
240
241 /* Update buffer */
242 tmp_io_info.u.rbuf = (uint8_t *)tmp_io_info.u.rbuf + orig_mem_len;
243
244 /* Decrement number of elements left to process */
245 nelmts -= nelem;
246 } /* end while */
247
248 done:
249 /* Release resources, if allocated */
250 if (len)
251 len = H5FL_SEQ_FREE(size_t, len);
252 if (off)
253 off = H5FL_SEQ_FREE(hsize_t, off);
254
255 FUNC_LEAVE_NOAPI(ret_value)
256 } /* H5D__gather_file() */
257
258 /*-------------------------------------------------------------------------
259 * Function: H5D__scatter_mem
260 *
261 * Purpose: Scatters NELMTS data points from the scatter buffer
262 * TSCAT_BUF to the application buffer BUF. Each element is
263 * ELMT_SIZE bytes and they are organized in application memory
264 * according to SPACE.
265 *
266 * Return: Non-negative on success/Negative on failure
267 *
268 * Programmer: Quincey Koziol
269 * Monday, July 8, 2002
270 *
271 *-------------------------------------------------------------------------
272 */
273 herr_t
H5D__scatter_mem(const void * _tscat_buf,H5S_sel_iter_t * iter,size_t nelmts,void * _buf)274 H5D__scatter_mem(const void *_tscat_buf, H5S_sel_iter_t *iter, size_t nelmts, void *_buf /*out*/)
275 {
276 uint8_t * buf = (uint8_t *)_buf; /* Get local copies for address arithmetic */
277 const uint8_t *tscat_buf = (const uint8_t *)_tscat_buf;
278 hsize_t * off = NULL; /* Pointer to sequence offsets */
279 size_t * len = NULL; /* Pointer to sequence lengths */
280 size_t curr_len; /* Length of bytes left to process in sequence */
281 size_t nseq; /* Number of sequences generated */
282 size_t curr_seq; /* Current sequence being processed */
283 size_t nelem; /* Number of elements used in sequences */
284 size_t dxpl_vec_size; /* Vector length from API context's DXPL */
285 size_t vec_size; /* Vector length */
286 herr_t ret_value = SUCCEED; /* Number of elements scattered */
287
288 FUNC_ENTER_PACKAGE
289
290 /* Check args */
291 HDassert(tscat_buf);
292 HDassert(iter);
293 HDassert(nelmts > 0);
294 HDassert(buf);
295
296 /* Get info from API context */
297 if (H5CX_get_vec_size(&dxpl_vec_size) < 0)
298 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve I/O vector size")
299
300 /* Allocate the vector I/O arrays */
301 if (dxpl_vec_size > H5D_IO_VECTOR_SIZE)
302 vec_size = dxpl_vec_size;
303 else
304 vec_size = H5D_IO_VECTOR_SIZE;
305 if (NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
306 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array")
307 if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
308 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array")
309
310 /* Loop until all elements are written */
311 while (nelmts > 0) {
312 /* Get list of sequences for selection to write */
313 if (H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0)
314 HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed")
315
316 /* Loop, while sequences left to process */
317 for (curr_seq = 0; curr_seq < nseq; curr_seq++) {
318 /* Get the number of bytes in sequence */
319 curr_len = len[curr_seq];
320
321 H5MM_memcpy(buf + off[curr_seq], tscat_buf, curr_len);
322
323 /* Advance offset in destination buffer */
324 tscat_buf += curr_len;
325 } /* end for */
326
327 /* Decrement number of elements left to process */
328 nelmts -= nelem;
329 } /* end while */
330
331 done:
332 /* Release resources, if allocated */
333 if (len)
334 len = H5FL_SEQ_FREE(size_t, len);
335 if (off)
336 off = H5FL_SEQ_FREE(hsize_t, off);
337
338 FUNC_LEAVE_NOAPI(ret_value)
339 } /* H5D__scatter_mem() */
340
341 /*-------------------------------------------------------------------------
342 * Function: H5D__gather_mem
343 *
344 * Purpose: Gathers dataset elements from application memory BUF and
345 * copies them into the gather buffer TGATH_BUF.
346 * Each element is ELMT_SIZE bytes and arranged in application
347 * memory according to SPACE.
348 * The caller is requesting that exactly NELMTS be gathered.
349 *
350 * Return: Success: Number of elements copied.
351 * Failure: 0
352 *
353 * Programmer: Quincey Koziol
354 * Monday, June 24, 2002
355 *
356 *-------------------------------------------------------------------------
357 */
358 size_t
H5D__gather_mem(const void * _buf,H5S_sel_iter_t * iter,size_t nelmts,void * _tgath_buf)359 H5D__gather_mem(const void *_buf, H5S_sel_iter_t *iter, size_t nelmts, void *_tgath_buf /*out*/)
360 {
361 const uint8_t *buf = (const uint8_t *)_buf; /* Get local copies for address arithmetic */
362 uint8_t * tgath_buf = (uint8_t *)_tgath_buf;
363 hsize_t * off = NULL; /* Pointer to sequence offsets */
364 size_t * len = NULL; /* Pointer to sequence lengths */
365 size_t curr_len; /* Length of bytes left to process in sequence */
366 size_t nseq; /* Number of sequences generated */
367 size_t curr_seq; /* Current sequence being processed */
368 size_t nelem; /* Number of elements used in sequences */
369 size_t dxpl_vec_size; /* Vector length from API context's DXPL */
370 size_t vec_size; /* Vector length */
371 size_t ret_value = nelmts; /* Number of elements gathered */
372
373 FUNC_ENTER_STATIC
374
375 /* Check args */
376 HDassert(buf);
377 HDassert(iter);
378 HDassert(nelmts > 0);
379 HDassert(tgath_buf);
380
381 /* Get info from API context */
382 if (H5CX_get_vec_size(&dxpl_vec_size) < 0)
383 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, 0, "can't retrieve I/O vector size")
384
385 /* Allocate the vector I/O arrays */
386 if (dxpl_vec_size > H5D_IO_VECTOR_SIZE)
387 vec_size = dxpl_vec_size;
388 else
389 vec_size = H5D_IO_VECTOR_SIZE;
390 if (NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
391 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, 0, "can't allocate I/O length vector array")
392 if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
393 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, 0, "can't allocate I/O offset vector array")
394
395 /* Loop until all elements are written */
396 while (nelmts > 0) {
397 /* Get list of sequences for selection to write */
398 if (H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0)
399 HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed")
400
401 /* Loop, while sequences left to process */
402 for (curr_seq = 0; curr_seq < nseq; curr_seq++) {
403 /* Get the number of bytes in sequence */
404 curr_len = len[curr_seq];
405
406 H5MM_memcpy(tgath_buf, buf + off[curr_seq], curr_len);
407
408 /* Advance offset in gather buffer */
409 tgath_buf += curr_len;
410 } /* end for */
411
412 /* Decrement number of elements left to process */
413 nelmts -= nelem;
414 } /* end while */
415
416 done:
417 /* Release resources, if allocated */
418 if (len)
419 len = H5FL_SEQ_FREE(size_t, len);
420 if (off)
421 off = H5FL_SEQ_FREE(hsize_t, off);
422
423 FUNC_LEAVE_NOAPI(ret_value)
424 } /* H5D__gather_mem() */
425
426 /*-------------------------------------------------------------------------
427 * Function: H5D__scatgath_read
428 *
429 * Purpose: Perform scatter/gather ead from a contiguous [piece of a] dataset.
430 *
431 * Return: Non-negative on success/Negative on failure
432 *
433 * Programmer: Quincey Koziol
434 * Thursday, March 6, 2008
435 *
436 *-------------------------------------------------------------------------
437 */
438 herr_t
H5D__scatgath_read(const H5D_io_info_t * io_info,const H5D_type_info_t * type_info,hsize_t nelmts,const H5S_t * file_space,const H5S_t * mem_space)439 H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
440 const H5S_t *file_space, const H5S_t *mem_space)
441 {
442 void * buf = io_info->u.rbuf; /* Local pointer to application buffer */
443 H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info*/
444 hbool_t mem_iter_init = FALSE; /* Memory selection iteration info has been initialized */
445 H5S_sel_iter_t *bkg_iter = NULL; /* Background iteration info*/
446 hbool_t bkg_iter_init = FALSE; /* Background iteration info has been initialized */
447 H5S_sel_iter_t *file_iter = NULL; /* File selection iteration info*/
448 hbool_t file_iter_init = FALSE; /* File selection iteration info has been initialized */
449 hsize_t smine_start; /* Strip mine start loc */
450 size_t smine_nelmts; /* Elements per strip */
451 herr_t ret_value = SUCCEED; /* Return value */
452
453 FUNC_ENTER_PACKAGE
454
455 /* Sanity check */
456 HDassert(io_info);
457 HDassert(type_info);
458 HDassert(mem_space);
459 HDassert(file_space);
460 HDassert(buf);
461
462 /* Check for NOOP read */
463 if (nelmts == 0)
464 HGOTO_DONE(SUCCEED)
465
466 /* Allocate the iterators */
467 if (NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t)))
468 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate memory iterator")
469 if (NULL == (bkg_iter = H5FL_MALLOC(H5S_sel_iter_t)))
470 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate background iterator")
471 if (NULL == (file_iter = H5FL_MALLOC(H5S_sel_iter_t)))
472 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator")
473
474 /* Figure out the strip mine size. */
475 if (H5S_select_iter_init(file_iter, file_space, type_info->src_type_size,
476 H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 0)
477 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information")
478 file_iter_init = TRUE; /*file selection iteration info has been initialized */
479 if (H5S_select_iter_init(mem_iter, mem_space, type_info->dst_type_size, 0) < 0)
480 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information")
481 mem_iter_init = TRUE; /*file selection iteration info has been initialized */
482 if (H5S_select_iter_init(bkg_iter, mem_space, type_info->dst_type_size, 0) < 0)
483 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information")
484 bkg_iter_init = TRUE; /*file selection iteration info has been initialized */
485
486 /* Start strip mining... */
487 for (smine_start = 0; smine_start < nelmts; smine_start += smine_nelmts) {
488 size_t n; /* Elements operated on */
489
490 /* Go figure out how many elements to read from the file */
491 HDassert(H5S_SELECT_ITER_NELMTS(file_iter) == (nelmts - smine_start));
492 smine_nelmts = (size_t)MIN(type_info->request_nelmts, (nelmts - smine_start));
493
494 /*
495 * Gather the data from disk into the datatype conversion
496 * buffer. Also gather data from application to background buffer
497 * if necessary.
498 */
499
500 /*
501 * Gather data
502 */
503 n = H5D__gather_file(io_info, file_iter, smine_nelmts, type_info->tconv_buf /*out*/);
504 if (n != smine_nelmts)
505 HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed")
506
507 /* If the source and destination are compound types and subset of each other
508 * and no conversion is needed, copy the data directly into user's buffer and
509 * bypass the rest of steps.
510 */
511 if (type_info->cmpd_subset && H5T_SUBSET_FALSE != type_info->cmpd_subset->subset) {
512 if (H5D__compound_opt_read(smine_nelmts, mem_iter, type_info, buf /*out*/) < 0)
513 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
514 } /* end if */
515 else {
516 if (H5T_BKG_YES == type_info->need_bkg) {
517 n = H5D__gather_mem(buf, bkg_iter, smine_nelmts, type_info->bkg_buf /*out*/);
518 if (n != smine_nelmts)
519 HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "mem gather failed")
520 } /* end if */
521
522 /*
523 * Perform datatype conversion.
524 */
525 if (H5T_convert(type_info->tpath, type_info->src_type_id, type_info->dst_type_id, smine_nelmts,
526 (size_t)0, (size_t)0, type_info->tconv_buf, type_info->bkg_buf) < 0)
527 HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed")
528
529 /* Do the data transform after the conversion (since we're using type mem_type) */
530 if (!type_info->is_xform_noop) {
531 H5Z_data_xform_t *data_transform; /* Data transform info */
532
533 /* Retrieve info from API context */
534 if (H5CX_get_data_transform(&data_transform) < 0)
535 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get data transform info")
536
537 if (H5Z_xform_eval(data_transform, type_info->tconv_buf, smine_nelmts, type_info->mem_type) <
538 0)
539 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "Error performing data transform")
540 }
541
542 /* Scatter the data into memory */
543 if (H5D__scatter_mem(type_info->tconv_buf, mem_iter, smine_nelmts, buf /*out*/) < 0)
544 HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed")
545 } /* end else */
546 } /* end for */
547
548 done:
549 /* Release selection iterators */
550 if (file_iter_init && H5S_SELECT_ITER_RELEASE(file_iter) < 0)
551 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
552 if (file_iter)
553 file_iter = H5FL_FREE(H5S_sel_iter_t, file_iter);
554 if (mem_iter_init && H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
555 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
556 if (mem_iter)
557 mem_iter = H5FL_FREE(H5S_sel_iter_t, mem_iter);
558 if (bkg_iter_init && H5S_SELECT_ITER_RELEASE(bkg_iter) < 0)
559 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
560 if (bkg_iter)
561 bkg_iter = H5FL_FREE(H5S_sel_iter_t, bkg_iter);
562
563 FUNC_LEAVE_NOAPI(ret_value)
564 } /* end H5D__scatgath_read() */
565
566 /*-------------------------------------------------------------------------
567 * Function: H5D__scatgath_write
568 *
569 * Purpose: Perform scatter/gather write to a contiguous [piece of a] dataset.
570 *
571 * Return: Non-negative on success/Negative on failure
572 *
573 * Programmer: Quincey Koziol
574 * Thursday, March 6, 2008
575 *
576 *-------------------------------------------------------------------------
577 */
578 herr_t
H5D__scatgath_write(const H5D_io_info_t * io_info,const H5D_type_info_t * type_info,hsize_t nelmts,const H5S_t * file_space,const H5S_t * mem_space)579 H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, hsize_t nelmts,
580 const H5S_t *file_space, const H5S_t *mem_space)
581 {
582 const void * buf = io_info->u.wbuf; /* Local pointer to application buffer */
583 H5S_sel_iter_t *mem_iter = NULL; /* Memory selection iteration info*/
584 hbool_t mem_iter_init = FALSE; /* Memory selection iteration info has been initialized */
585 H5S_sel_iter_t *bkg_iter = NULL; /* Background iteration info*/
586 hbool_t bkg_iter_init = FALSE; /* Background iteration info has been initialized */
587 H5S_sel_iter_t *file_iter = NULL; /* File selection iteration info*/
588 hbool_t file_iter_init = FALSE; /* File selection iteration info has been initialized */
589 hsize_t smine_start; /* Strip mine start loc */
590 size_t smine_nelmts; /* Elements per strip */
591 herr_t ret_value = SUCCEED; /* Return value */
592
593 FUNC_ENTER_PACKAGE
594
595 /* Sanity check */
596 HDassert(io_info);
597 HDassert(type_info);
598 HDassert(mem_space);
599 HDassert(file_space);
600 HDassert(buf);
601
602 /* Check for NOOP write */
603 if (nelmts == 0)
604 HGOTO_DONE(SUCCEED)
605
606 /* Allocate the iterators */
607 if (NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t)))
608 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate memory iterator")
609 if (NULL == (bkg_iter = H5FL_MALLOC(H5S_sel_iter_t)))
610 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate background iterator")
611 if (NULL == (file_iter = H5FL_MALLOC(H5S_sel_iter_t)))
612 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator")
613
614 /* Figure out the strip mine size. */
615 if (H5S_select_iter_init(file_iter, file_space, type_info->dst_type_size,
616 H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 0)
617 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information")
618 file_iter_init = TRUE; /*file selection iteration info has been initialized */
619 if (H5S_select_iter_init(mem_iter, mem_space, type_info->src_type_size, 0) < 0)
620 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information")
621 mem_iter_init = TRUE; /*file selection iteration info has been initialized */
622 if (H5S_select_iter_init(bkg_iter, file_space, type_info->dst_type_size,
623 H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 0)
624 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information")
625 bkg_iter_init = TRUE; /*file selection iteration info has been initialized */
626
627 /* Start strip mining... */
628 for (smine_start = 0; smine_start < nelmts; smine_start += smine_nelmts) {
629 size_t n; /* Elements operated on */
630
631 /* Go figure out how many elements to read from the file */
632 HDassert(H5S_SELECT_ITER_NELMTS(file_iter) == (nelmts - smine_start));
633 smine_nelmts = (size_t)MIN(type_info->request_nelmts, (nelmts - smine_start));
634
635 /*
636 * Gather data from application buffer into the datatype conversion
637 * buffer. Also gather data from the file into the background buffer
638 * if necessary.
639 */
640 n = H5D__gather_mem(buf, mem_iter, smine_nelmts, type_info->tconv_buf /*out*/);
641 if (n != smine_nelmts)
642 HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "mem gather failed")
643
644 /* If the source and destination are compound types and the destination is
645 * is a subset of the source and no conversion is needed, copy the data
646 * directly into user's buffer and bypass the rest of steps. If the source
647 * is a subset of the destination, the optimization is done in conversion
648 * function H5T_conv_struct_opt to protect the background data.
649 */
650 if (type_info->cmpd_subset && H5T_SUBSET_DST == type_info->cmpd_subset->subset &&
651 type_info->dst_type_size == type_info->cmpd_subset->copy_size) {
652 if (H5D__compound_opt_write(smine_nelmts, type_info) < 0)
653 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed")
654 } /* end if */
655 else {
656 if (H5T_BKG_YES == type_info->need_bkg) {
657 n = H5D__gather_file(io_info, bkg_iter, smine_nelmts, type_info->bkg_buf /*out*/);
658 if (n != smine_nelmts)
659 HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed")
660 } /* end if */
661
662 /* Do the data transform before the type conversion (since
663 * transforms must be done in the memory type). */
664 if (!type_info->is_xform_noop) {
665 H5Z_data_xform_t *data_transform; /* Data transform info */
666
667 /* Retrieve info from API context */
668 if (H5CX_get_data_transform(&data_transform) < 0)
669 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get data transform info")
670
671 if (H5Z_xform_eval(data_transform, type_info->tconv_buf, smine_nelmts, type_info->mem_type) <
672 0)
673 HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "Error performing data transform")
674 }
675
676 /*
677 * Perform datatype conversion.
678 */
679 if (H5T_convert(type_info->tpath, type_info->src_type_id, type_info->dst_type_id, smine_nelmts,
680 (size_t)0, (size_t)0, type_info->tconv_buf, type_info->bkg_buf) < 0)
681 HGOTO_ERROR(H5E_DATASET, H5E_CANTCONVERT, FAIL, "datatype conversion failed")
682 } /* end else */
683
684 /*
685 * Scatter the data out to the file.
686 */
687 if (H5D__scatter_file(io_info, file_iter, smine_nelmts, type_info->tconv_buf) < 0)
688 HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "scatter failed")
689 } /* end for */
690
691 done:
692 /* Release selection iterators */
693 if (file_iter_init && H5S_SELECT_ITER_RELEASE(file_iter) < 0)
694 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
695 if (file_iter)
696 file_iter = H5FL_FREE(H5S_sel_iter_t, file_iter);
697 if (mem_iter_init && H5S_SELECT_ITER_RELEASE(mem_iter) < 0)
698 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
699 if (mem_iter)
700 mem_iter = H5FL_FREE(H5S_sel_iter_t, mem_iter);
701 if (bkg_iter_init && H5S_SELECT_ITER_RELEASE(bkg_iter) < 0)
702 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
703 if (bkg_iter)
704 bkg_iter = H5FL_FREE(H5S_sel_iter_t, bkg_iter);
705
706 FUNC_LEAVE_NOAPI(ret_value)
707 } /* end H5D__scatgath_write() */
708
709 /*-------------------------------------------------------------------------
710 * Function: H5D__compound_opt_read
711 *
712 * Purpose: A special optimization case when the source and
713 * destination members are a subset of each other, and
714 * the order is the same, and no conversion is needed.
715 * For example:
716 * struct source { struct destination {
717 * TYPE1 A; --> TYPE1 A;
718 * TYPE2 B; --> TYPE2 B;
719 * TYPE3 C; --> TYPE3 C;
720 * }; TYPE4 D;
721 * TYPE5 E;
722 * };
723 * or
724 * struct destination { struct source {
725 * TYPE1 A; <-- TYPE1 A;
726 * TYPE2 B; <-- TYPE2 B;
727 * TYPE3 C; <-- TYPE3 C;
728 * }; TYPE4 D;
729 * TYPE5 E;
730 * };
731 * The optimization is simply moving data to the appropriate
732 * places in the buffer.
733 *
734 * Return: Non-negative on success/Negative on failure
735 *
736 * Programmer: Raymond Lu
737 * 11 June 2007
738 *
739 *-------------------------------------------------------------------------
740 */
741 static herr_t
H5D__compound_opt_read(size_t nelmts,H5S_sel_iter_t * iter,const H5D_type_info_t * type_info,void * user_buf)742 H5D__compound_opt_read(size_t nelmts, H5S_sel_iter_t *iter, const H5D_type_info_t *type_info,
743 void *user_buf /*out*/)
744 {
745 uint8_t *ubuf = (uint8_t *)user_buf; /* Cast for pointer arithmetic */
746 uint8_t *xdbuf; /* Pointer into dataset buffer */
747 hsize_t *off = NULL; /* Pointer to sequence offsets */
748 size_t * len = NULL; /* Pointer to sequence lengths */
749 size_t src_stride, dst_stride, copy_size;
750 size_t dxpl_vec_size; /* Vector length from API context's DXPL */
751 size_t vec_size; /* Vector length */
752 herr_t ret_value = SUCCEED; /* Return value */
753
754 FUNC_ENTER_STATIC
755
756 /* Check args */
757 HDassert(nelmts > 0);
758 HDassert(iter);
759 HDassert(type_info);
760 HDassert(type_info->cmpd_subset);
761 HDassert(H5T_SUBSET_SRC == type_info->cmpd_subset->subset ||
762 H5T_SUBSET_DST == type_info->cmpd_subset->subset);
763 HDassert(user_buf);
764
765 /* Get info from API context */
766 if (H5CX_get_vec_size(&dxpl_vec_size) < 0)
767 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve I/O vector size")
768
769 /* Allocate the vector I/O arrays */
770 if (dxpl_vec_size > H5D_IO_VECTOR_SIZE)
771 vec_size = dxpl_vec_size;
772 else
773 vec_size = H5D_IO_VECTOR_SIZE;
774 if (NULL == (len = H5FL_SEQ_MALLOC(size_t, vec_size)))
775 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array")
776 if (NULL == (off = H5FL_SEQ_MALLOC(hsize_t, vec_size)))
777 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array")
778
779 /* Get source & destination strides */
780 src_stride = type_info->src_type_size;
781 dst_stride = type_info->dst_type_size;
782
783 /* Get the size, in bytes, to copy for each element */
784 copy_size = type_info->cmpd_subset->copy_size;
785
786 /* Loop until all elements are written */
787 xdbuf = type_info->tconv_buf;
788 while (nelmts > 0) {
789 size_t nseq; /* Number of sequences generated */
790 size_t curr_seq; /* Current sequence being processed */
791 size_t elmtno; /* Element counter */
792
793 /* Get list of sequences for selection to write */
794 if (H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &elmtno, off, len) < 0)
795 HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed")
796
797 /* Loop, while sequences left to process */
798 for (curr_seq = 0; curr_seq < nseq; curr_seq++) {
799 size_t curr_off; /* Offset of bytes left to process in sequence */
800 size_t curr_len; /* Length of bytes left to process in sequence */
801 size_t curr_nelmts; /* Number of elements to process in sequence */
802 uint8_t *xubuf;
803 size_t i; /* Local index variable */
804
805 /* Get the number of bytes and offset in sequence */
806 curr_len = len[curr_seq];
807 H5_CHECK_OVERFLOW(off[curr_seq], hsize_t, size_t);
808 curr_off = (size_t)off[curr_seq];
809
810 /* Decide the number of elements and position in the buffer. */
811 curr_nelmts = curr_len / dst_stride;
812 xubuf = ubuf + curr_off;
813
814 /* Copy the data into the right place. */
815 for (i = 0; i < curr_nelmts; i++) {
816 HDmemmove(xubuf, xdbuf, copy_size);
817
818 /* Update pointers */
819 xdbuf += src_stride;
820 xubuf += dst_stride;
821 } /* end for */
822 } /* end for */
823
824 /* Decrement number of elements left to process */
825 nelmts -= elmtno;
826 } /* end while */
827
828 done:
829 /* Release resources, if allocated */
830 if (len)
831 len = H5FL_SEQ_FREE(size_t, len);
832 if (off)
833 off = H5FL_SEQ_FREE(hsize_t, off);
834
835 FUNC_LEAVE_NOAPI(ret_value)
836 } /* end H5D__compound_opt_read() */
837
838 /*-------------------------------------------------------------------------
839 * Function: H5D__compound_opt_write
840 *
841 * Purpose: A special optimization case when the source and
842 * destination members are a subset of each other, and
843 * the order is the same, and no conversion is needed.
844 * For example:
845 * struct source { struct destination {
846 * TYPE1 A; --> TYPE1 A;
847 * TYPE2 B; --> TYPE2 B;
848 * TYPE3 C; --> TYPE3 C;
849 * }; TYPE4 D;
850 * TYPE5 E;
851 * };
852 * or
853 * struct destination { struct source {
854 * TYPE1 A; <-- TYPE1 A;
855 * TYPE2 B; <-- TYPE2 B;
856 * TYPE3 C; <-- TYPE3 C;
857 * }; TYPE4 D;
858 * TYPE5 E;
859 * };
860 * The optimization is simply moving data to the appropriate
861 * places in the buffer.
862 *
863 *
864 * Return: Non-negative on success/Negative on failure
865 *
866 * Programmer: Raymond Lu
867 * 11 June 2007
868 *
869 *-------------------------------------------------------------------------
870 */
871 static herr_t
H5D__compound_opt_write(size_t nelmts,const H5D_type_info_t * type_info)872 H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info)
873 {
874 uint8_t *xsbuf, *xdbuf; /* Source & destination pointers into dataset buffer */
875 size_t src_stride, dst_stride; /* Strides through source & destination datatypes */
876 size_t i; /* Local index variable */
877
878 FUNC_ENTER_STATIC_NOERR
879
880 /* Check args */
881 HDassert(nelmts > 0);
882 HDassert(type_info);
883
884 /* Initialize values for loop */
885 src_stride = type_info->src_type_size;
886 dst_stride = type_info->dst_type_size;
887
888 /* Loop until all elements are written */
889 xsbuf = (uint8_t *)type_info->tconv_buf;
890 xdbuf = (uint8_t *)type_info->tconv_buf;
891 for (i = 0; i < nelmts; i++) {
892 HDmemmove(xdbuf, xsbuf, dst_stride);
893
894 /* Update pointers */
895 xsbuf += src_stride;
896 xdbuf += dst_stride;
897 } /* end for */
898
899 FUNC_LEAVE_NOAPI(SUCCEED)
900 } /* end H5D__compound_opt_write() */
901
902 /*-------------------------------------------------------------------------
903 * Function: H5Dscatter
904 *
905 * Purpose: Scatters data provided by the callback op to the
906 * destination buffer dst_buf, where the dimensions of
907 * dst_buf and the selection to be scattered to are specified
908 * by the dataspace dst_space_id. The type of the data to be
909 * scattered is specified by type_id.
910 *
911 * Return: Non-negative on success/Negative on failure
912 *
913 * Programmer: Neil Fortner
914 * 14 Jan 2013
915 *
916 *-------------------------------------------------------------------------
917 */
918 herr_t
H5Dscatter(H5D_scatter_func_t op,void * op_data,hid_t type_id,hid_t dst_space_id,void * dst_buf)919 H5Dscatter(H5D_scatter_func_t op, void *op_data, hid_t type_id, hid_t dst_space_id, void *dst_buf)
920 {
921 H5T_t * type; /* Datatype */
922 H5S_t * dst_space; /* Dataspace */
923 H5S_sel_iter_t *iter = NULL; /* Selection iteration info*/
924 hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */
925 const void * src_buf = NULL; /* Source (contiguous) data buffer */
926 size_t src_buf_nbytes = 0; /* Size of src_buf */
927 size_t type_size; /* Datatype element size */
928 hssize_t nelmts; /* Number of remaining elements in selection */
929 size_t nelmts_scatter = 0; /* Number of elements to scatter to dst_buf */
930 herr_t ret_value = SUCCEED; /* Return value */
931
932 FUNC_ENTER_API(FAIL)
933 H5TRACE5("e", "x*xii*x", op, op_data, type_id, dst_space_id, dst_buf);
934
935 /* Check args */
936 if (op == NULL)
937 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid callback function pointer")
938 if (NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
939 HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
940 if (NULL == (dst_space = (H5S_t *)H5I_object_verify(dst_space_id, H5I_DATASPACE)))
941 HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
942 if (dst_buf == NULL)
943 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination buffer provided")
944
945 /* Get datatype element size */
946 if (0 == (type_size = H5T_GET_SIZE(type)))
947 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get datatype size")
948
949 /* Get number of elements in dataspace */
950 if ((nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(dst_space)) < 0)
951 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection")
952
953 /* Allocate the selection iterator */
954 if (NULL == (iter = H5FL_MALLOC(H5S_sel_iter_t)))
955 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate selection iterator")
956
957 /* Initialize selection iterator */
958 if (H5S_select_iter_init(iter, dst_space, type_size, 0) < 0)
959 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize selection iterator information")
960 iter_init = TRUE;
961
962 /* Loop until all data has been scattered */
963 while (nelmts > 0) {
964 /* Make callback to retrieve data */
965 if (op(&src_buf, &src_buf_nbytes, op_data) < 0)
966 HGOTO_ERROR(H5E_DATASET, H5E_CALLBACK, FAIL, "callback operator returned failure")
967
968 /* Calculate number of elements */
969 nelmts_scatter = src_buf_nbytes / type_size;
970
971 /* Check callback results */
972 if (!src_buf)
973 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback did not return a buffer")
974 if (src_buf_nbytes == 0)
975 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback returned a buffer size of 0")
976 if (src_buf_nbytes % type_size)
977 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buffer size is not a multiple of datatype size")
978 if (nelmts_scatter > (size_t)nelmts)
979 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback returned more elements than in selection")
980
981 /* Scatter data */
982 if (H5D__scatter_mem(src_buf, iter, nelmts_scatter, dst_buf) < 0)
983 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "scatter failed")
984
985 nelmts -= (hssize_t)nelmts_scatter;
986 } /* end while */
987
988 done:
989 /* Release selection iterator */
990 if (iter_init && H5S_SELECT_ITER_RELEASE(iter) < 0)
991 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
992 if (iter)
993 iter = H5FL_FREE(H5S_sel_iter_t, iter);
994
995 FUNC_LEAVE_API(ret_value)
996 } /* H5Dscatter() */
997
998 /*-------------------------------------------------------------------------
999 * Function: H5Dgather
1000 *
1001 * Purpose: Gathers data provided from the source buffer src_buf to
1002 * contiguous buffer dst_buf, then calls the callback op.
1003 * The dimensions of src_buf and the selection to be gathered
1004 * are specified by the dataspace src_space_id. The type of
1005 * the data to be gathered is specified by type_id.
1006 *
1007 * Return: Non-negative on success/Negative on failure
1008 *
1009 * Programmer: Neil Fortner
1010 * 16 Jan 2013
1011 *
1012 *-------------------------------------------------------------------------
1013 */
1014 herr_t
H5Dgather(hid_t src_space_id,const void * src_buf,hid_t type_id,size_t dst_buf_size,void * dst_buf,H5D_gather_func_t op,void * op_data)1015 H5Dgather(hid_t src_space_id, const void *src_buf, hid_t type_id, size_t dst_buf_size, void *dst_buf,
1016 H5D_gather_func_t op, void *op_data)
1017 {
1018 H5T_t * type; /* Datatype */
1019 H5S_t * src_space; /* Dataspace */
1020 H5S_sel_iter_t *iter = NULL; /* Selection iteration info*/
1021 hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */
1022 size_t type_size; /* Datatype element size */
1023 hssize_t nelmts; /* Number of remaining elements in selection */
1024 size_t dst_buf_nelmts; /* Number of elements that can fit in dst_buf */
1025 size_t nelmts_gathered; /* Number of elements gathered from src_buf */
1026 herr_t ret_value = SUCCEED; /* Return value */
1027
1028 FUNC_ENTER_API(FAIL)
1029 H5TRACE7("e", "i*xiz*xx*x", src_space_id, src_buf, type_id, dst_buf_size, dst_buf, op, op_data);
1030
1031 /* Check args */
1032 if (NULL == (src_space = (H5S_t *)H5I_object_verify(src_space_id, H5I_DATASPACE)))
1033 HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
1034 if (src_buf == NULL)
1035 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no source buffer provided")
1036 if (NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE)))
1037 HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype")
1038 if (dst_buf_size == 0)
1039 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "destination buffer size is 0")
1040 if (dst_buf == NULL)
1041 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination buffer provided")
1042
1043 /* Get datatype element size */
1044 if (0 == (type_size = H5T_GET_SIZE(type)))
1045 HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get datatype size")
1046
1047 /* Get number of elements in dst_buf_size */
1048 dst_buf_nelmts = dst_buf_size / type_size;
1049 if (dst_buf_nelmts == 0)
1050 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
1051 "destination buffer is not large enough to hold one element")
1052
1053 /* Get number of elements in dataspace */
1054 if ((nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(src_space)) < 0)
1055 HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection")
1056
1057 /* If dst_buf is not large enough to hold all the elements, make sure there
1058 * is a callback */
1059 if (((size_t)nelmts > dst_buf_nelmts) && (op == NULL))
1060 HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no callback supplied and destination buffer too small")
1061
1062 /* Allocate the selection iterator */
1063 if (NULL == (iter = H5FL_MALLOC(H5S_sel_iter_t)))
1064 HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate selection iterator")
1065
1066 /* Initialize selection iterator */
1067 if (H5S_select_iter_init(iter, src_space, type_size, 0) < 0)
1068 HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize selection iterator information")
1069 iter_init = TRUE;
1070
1071 /* Loop until all data has been scattered */
1072 while (nelmts > 0) {
1073 /* Gather data */
1074 if (0 ==
1075 (nelmts_gathered = H5D__gather_mem(src_buf, iter, MIN(dst_buf_nelmts, (size_t)nelmts), dst_buf)))
1076 HGOTO_ERROR(H5E_IO, H5E_CANTCOPY, FAIL, "gather failed")
1077 HDassert(nelmts_gathered == MIN(dst_buf_nelmts, (size_t)nelmts));
1078
1079 /* Make callback to process dst_buf */
1080 if (op && op(dst_buf, nelmts_gathered * type_size, op_data) < 0)
1081 HGOTO_ERROR(H5E_DATASET, H5E_CALLBACK, FAIL, "callback operator returned failure")
1082
1083 nelmts -= (hssize_t)nelmts_gathered;
1084 HDassert(op || (nelmts == 0));
1085 } /* end while */
1086
1087 done:
1088 /* Release selection iterator */
1089 if (iter_init && H5S_SELECT_ITER_RELEASE(iter) < 0)
1090 HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator")
1091 if (iter)
1092 iter = H5FL_FREE(H5S_sel_iter_t, iter);
1093
1094 FUNC_LEAVE_API(ret_value)
1095 } /* H5Dgather() */
1096