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