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