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