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