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