From 0e3517d34fb6b4c2c1016ea6be80f3046f6d8549 Mon Sep 17 00:00:00 2001 From: Neil Fortner Date: Tue, 5 Feb 2013 12:07:02 -0500 Subject: [svn-r23230] Purpose: Implement H5Dscatter and H5Dgather Description: Adds 2 new API functions, H5Dscatter and H5Dgather. H5Dscatter retrieves data from a specified callback function and scatters it into a selection, defined by a supplied dataspace, within a supplied memory buffer. H5Dgather gathers data from a selection within a supplied memory buffer and passes it in a contiguous form to a supplied callback function. Added tests for these functions Tested: jam, ostrich, koala (h5committest); ummon --- bin/trace | 2 + release_docs/RELEASE.txt | 3 + src/H5Dpublic.h | 13 + src/H5Dscatgath.c | 200 ++++++++- test/dsets.c | 1012 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1229 insertions(+), 1 deletion(-) diff --git a/bin/trace b/bin/trace index 67aeb17..657ac92 100755 --- a/bin/trace +++ b/bin/trace @@ -99,7 +99,9 @@ $Source = ""; "H5A_operator2_t" => "x", "H5A_info_t" => "x", "H5AC_cache_config_t" => "x", + "H5D_gather_func_t" => "x", "H5D_operator_t" => "x", + "H5D_scatter_func_t" => "x", "H5E_auto_t" => "x", "H5E_auto1_t" => "x", "H5E_auto2_t" => "x", diff --git a/release_docs/RELEASE.txt b/release_docs/RELEASE.txt index 6d329bb..a67c613 100644 --- a/release_docs/RELEASE.txt +++ b/release_docs/RELEASE.txt @@ -106,6 +106,9 @@ New Features Library: -------- + - Added new API functions H5Dscatter and H5Dgather to scatter data to and + and gather data from a selection within a memory buffer. + (NAF - 2013/02/05) - The library now supports the data conversion from enumeration to numeric (integer and floating-point number) datatypes. See Issue 8221. (SLU - 2012/10/23) diff --git a/src/H5Dpublic.h b/src/H5Dpublic.h index 523f2b2..484b176 100644 --- a/src/H5Dpublic.h +++ b/src/H5Dpublic.h @@ -107,6 +107,15 @@ extern "C" { typedef herr_t (*H5D_operator_t)(void *elem, hid_t type_id, unsigned ndim, const hsize_t *point, void *operator_data); +/* Define the operator function pointer for H5Dscatter() */ +typedef herr_t (*H5D_scatter_func_t)(void **src_buf/*out*/, + size_t *src_buf_bytes_used/*out*/, + void *op_data); + +/* Define the operator function pointer for H5Dgather() */ +typedef herr_t (*H5D_gather_func_t)(const void *dst_buf, + size_t dst_buf_bytes_used, void *op_data); + H5_DLL hid_t H5Dcreate2(hid_t loc_id, const char *name, hid_t type_id, hid_t space_id, hid_t lcpl_id, hid_t dcpl_id, hid_t dapl_id); H5_DLL hid_t H5Dcreate_anon(hid_t file_id, hid_t type_id, hid_t space_id, @@ -131,6 +140,10 @@ H5_DLL herr_t H5Dvlen_get_buf_size(hid_t dataset_id, hid_t type_id, hid_t space_ H5_DLL herr_t H5Dfill(const void *fill, hid_t fill_type, void *buf, hid_t buf_type, hid_t space); H5_DLL herr_t H5Dset_extent(hid_t dset_id, const hsize_t size[]); +H5_DLL herr_t H5Dscatter(H5D_scatter_func_t op, void *op_data, hid_t type_id, + hid_t dst_space_id, void *dst_buf); +H5_DLL herr_t H5Dgather(hid_t src_space_id, void *src_buf, hid_t type_id, + size_t dst_buf_size, void *dst_buf, H5D_gather_func_t op, void *op_data); H5_DLL herr_t H5Ddebug(hid_t dset_id); /* Symbols defined for compatibility with previous versions of the HDF5 API. diff --git a/src/H5Dscatgath.c b/src/H5Dscatgath.c index 49b6132..74d6749 100644 --- a/src/H5Dscatgath.c +++ b/src/H5Dscatgath.c @@ -27,6 +27,7 @@ #include "H5Dpkg.h" /* Dataset functions */ #include "H5Eprivate.h" /* Error handling */ #include "H5FLprivate.h" /* Free Lists */ +#include "H5Iprivate.h" /* IDs */ /****************/ @@ -361,7 +362,7 @@ done: * copies them into the gather buffer TGATH_BUF. * Each element is ELMT_SIZE bytes and arranged in application * memory according to SPACE. - * The caller is requesting that at most NELMTS be gathered. + * The caller is requesting that exactly NELMTS be gathered. * * Return: Success: Number of elements copied. * Failure: 0 @@ -899,3 +900,200 @@ H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info) FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5D__compound_opt_write() */ + +/*------------------------------------------------------------------------- + * Function: H5Dscatter + * + * Purpose: Scatters data provided by the callback op to the + * destination buffer dst_buf, where the dimensions of + * dst_buf and the selection to be scattered to are specified + * by the dataspace dst_space_id. The type of the data to be + * scattered is specified by type_id. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Neil Fortner + * 14 Jan 2013 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Dscatter(H5D_scatter_func_t op, void *op_data, hid_t type_id, + hid_t dst_space_id, void *dst_buf) +{ + H5T_t *type; /* Datatype */ + H5S_t *dst_space; /* Dataspace */ + H5S_sel_iter_t iter; /* Selection iteration info*/ + hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */ + void *src_buf = NULL; /* Source (contiguous) data buffer */ + size_t src_buf_nbytes = 0; /* Size of src_buf */ + size_t type_size; /* Datatype element size */ + hssize_t nelmts; /* Number of remaining elements in selection */ + size_t nelmts_scatter = 0; /* Number of elements to scatter to dst_buf */ + H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ + H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE5("e", "x*xii*x", op, op_data, type_id, dst_space_id, dst_buf); + + /* Check args */ + if(op == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid callback function pointer") + if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype") + if(NULL == (dst_space= (H5S_t *)H5I_object_verify(dst_space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + if(dst_buf == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination buffer provided") + + /* Fill the DXPL cache values for later use */ + if(H5D__get_dxpl_cache(H5P_DATASET_XFER_DEFAULT, &dxpl_cache) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") + + /* Get datatype element size */ + if(0 == (type_size = H5T_GET_SIZE(type))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get datatype size") + + /* Get number of elements in dataspace */ + if((nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(dst_space)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection") + + /* Initialize selection iterator */ + if(H5S_select_iter_init(&iter, dst_space, type_size) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize selection iterator information") + iter_init = TRUE; + + /* Loop until all data has been scattered */ + while(nelmts > 0) { + /* Make callback to retrieve data */ + if(op(&src_buf, &src_buf_nbytes, op_data) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CALLBACK, FAIL, "callback operator returned failure") + + /* Calculate number of elements */ + nelmts_scatter = src_buf_nbytes / type_size; + + /* Check callback results */ + if(!src_buf) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback did not return a buffer") + if(src_buf_nbytes == 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback returned a buffer size of 0") + if(src_buf_nbytes % type_size) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "buffer size is not a multiple of datatype size") + if(nelmts_scatter > (size_t)nelmts) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "callback returned more elements than in selection") + + /* Scatter data */ + if(H5D__scatter_mem(src_buf, dst_space, &iter, nelmts_scatter, dxpl_cache, dst_buf) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "scatter failed") + + nelmts -= (hssize_t)nelmts_scatter; + } /* end while */ + +done: + /* Release selection iterator */ + if(iter_init) { + if(H5S_SELECT_ITER_RELEASE(&iter) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") + } /* end if */ + + FUNC_LEAVE_API(ret_value) +} /* H5Dscatter() */ + + +/*------------------------------------------------------------------------- + * Function: H5Dgather + * + * Purpose: Gathers data provided from the source buffer src_buf to + * contiguous buffer dst_buf, then calls the callback op. + * The dimensions of src_buf and the selection to be gathered + * are specified by the dataspace src_space_id. The type of + * the data to be gathered is specified by type_id. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Neil Fortner + * 16 Jan 2013 + * + *------------------------------------------------------------------------- + */ +herr_t +H5Dgather(hid_t src_space_id, void *src_buf, hid_t type_id, size_t dst_buf_size, + void *dst_buf, H5D_gather_func_t op, void *op_data) +{ + H5T_t *type; /* Datatype */ + H5S_t *src_space; /* Dataspace */ + H5S_sel_iter_t iter; /* Selection iteration info*/ + hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */ + size_t type_size; /* Datatype element size */ + hssize_t nelmts; /* Number of remaining elements in selection */ + size_t dst_buf_nelmts; /* Number of elements that can fit in dst_buf */ + size_t nelmts_gathered; /* Number of elements gathered from src_buf */ + H5D_dxpl_cache_t _dxpl_cache; /* Data transfer property cache buffer */ + H5D_dxpl_cache_t *dxpl_cache = &_dxpl_cache; /* Data transfer property cache */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE7("e", "i*xiz*xx*x", src_space_id, src_buf, type_id, dst_buf_size, + dst_buf, op, op_data); + + /* Check args */ + if(NULL == (src_space= (H5S_t *)H5I_object_verify(src_space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + if(src_buf == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no source buffer provided") + if(NULL == (type = (H5T_t *)H5I_object_verify(type_id, H5I_DATATYPE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a datatype") + if(dst_buf_size == 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "destination buffer size is 0") + if(dst_buf == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no destination buffer provided") + if(op == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid callback function pointer") + + /* Fill the DXPL cache values for later use */ + if(H5D__get_dxpl_cache(H5P_DATASET_XFER_DEFAULT, &dxpl_cache) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't fill dxpl cache") + + /* Get datatype element size */ + if(0 == (type_size = H5T_GET_SIZE(type))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get datatype size") + + /* Get number of elements in dst_buf_size */ + dst_buf_nelmts = dst_buf_size / type_size; + if(dst_buf_nelmts == 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "destination buffer is not large enough to hold one element") + + /* Get number of elements in dataspace */ + if((nelmts = (hssize_t)H5S_GET_SELECT_NPOINTS(src_space)) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "unable to get number of elements in selection") + + /* Initialize selection iterator */ + if(H5S_select_iter_init(&iter, src_space, type_size) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize selection iterator information") + iter_init = TRUE; + + /* Loop until all data has been scattered */ + while(nelmts > 0) { + /* Gather data */ + if(0 == (nelmts_gathered = H5D__gather_mem(src_buf, src_space, &iter, MIN(dst_buf_nelmts, (size_t)nelmts), dxpl_cache, dst_buf))) + HGOTO_ERROR(H5E_IO, H5E_CANTCOPY, FAIL, "gather failed") + HDassert(nelmts_gathered == MIN(dst_buf_nelmts, (size_t)nelmts)); + + /* Make callback to process dst_buf */ + if(op(dst_buf, nelmts_gathered * type_size, op_data) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CALLBACK, FAIL, "callback operator returned failure") + + nelmts -= (hssize_t)nelmts_gathered; + } /* end while */ + +done: + /* Release selection iterator */ + if(iter_init) { + if(H5S_SELECT_ITER_RELEASE(&iter) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "Can't release selection iterator") + } /* end if */ + + FUNC_LEAVE_API(ret_value) +} /* H5Dgather() */ + diff --git a/test/dsets.c b/test/dsets.c index 838ef48..96611d9 100644 --- a/test/dsets.c +++ b/test/dsets.c @@ -8181,6 +8181,1012 @@ error: /*------------------------------------------------------------------------- + * Function: test_scatter + * + * Purpose: Tests H5Dscatter with a variety of different selections + * and source buffer sizes. + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Neil Fortner + * Wednesday, January 16, 2013 + * + *------------------------------------------------------------------------- + */ +typedef struct scatter_info_t { + int *src_buf; /* Source data buffer */ + size_t block; /* Maximum number of elements to return to H5Dscatter() */ + size_t size; /* Remaining number of elements to return */ +} scatter_info_t; + +#define TEST_SCATTER_CHECK_ARR(ARR, EXP) \ + for(i=0; i<(int)(sizeof(ARR)/sizeof(ARR[0])); i++) \ + for(j=0; j<(int)(sizeof(ARR[0])/sizeof(ARR[0][0])); j++) \ + for(k=0; k<(int)(sizeof(ARR[0][0])/sizeof(ARR[0][0][0])); k++) \ + if(ARR[i][j][k] != EXP[i][j][k]) { \ + H5_FAILED(); AT(); \ + printf(" " #ARR "[%d][%d][%d] == %d, " #EXP "[%d][%d][%d] == %d\n", i, j, k, ARR[i][j][k], i, j, k, EXP[i][j][k]); \ + goto error; \ + } + +static herr_t +scatter_cb(void **src_buf/*out*/, size_t *src_buf_bytes_used/*out*/, + void *_scatter_info) +{ + scatter_info_t *scatter_info = (scatter_info_t *)_scatter_info; + size_t nelmts; /* Number of elements to return in src_buf */ + + /* Calculate number of elements */ + nelmts = MIN(scatter_info->block, scatter_info->size); + HDassert(nelmts > 0); + + /* Set output variables */ + *src_buf = (void *)scatter_info->src_buf; + *src_buf_bytes_used = nelmts * sizeof(scatter_info->src_buf[0]); + + /* Update scatter_info */ + scatter_info->src_buf += nelmts; + scatter_info->size -= nelmts; + + return SUCCEED; +} + +static herr_t +test_scatter(void) +{ + hid_t sid = -1; /* Dataspace ID */ + hsize_t dim[3] = {8, 4, 8}; /* Dataspace dimensions */ + hsize_t start[3] = {0, 0, 0}; + hsize_t stride[3] = {0, 0, 0}; + hsize_t count[3] = {0, 0, 0}; + hsize_t block[3] = {0, 0, 0}; + hsize_t start2[3] = {0, 0, 0}; + hsize_t count2[3] = {0, 0, 0}; + hsize_t point[4][3] = {{2, 3, 2}, {3, 0, 2}, {7, 2, 0}, {0, 1, 5}}; + size_t src_buf_size; + int src_buf[36]; /* Source data buffer */ + int dst_buf[8][4][8]; /* Destination data buffer */ + int expect_dst_buf[8][4][8]; /* Expected destination data buffer */ + scatter_info_t scatter_info; /* Operator data for callback */ + int i, j, k, src_i; /* Local index variables */ + + TESTING("H5Dscatter()"); + + /* Create dataspace */ + if((sid = H5Screate_simple(3, dim, NULL)) < 0) TEST_ERROR + + /* Initialize src_buf */ + for(i=0; i<(int)(sizeof(src_buf)/sizeof(src_buf[0])); i++) + src_buf[i] = i + 1; + + + /* + * Test 1: Simple case + */ + /* Select hyperslab */ + count[0] = 1; + count[1] = 1; + count[2] = 8; + if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL ,count, NULL) < 0) + TEST_ERROR + + /* Initialize dst_buf and expect_dst_buf */ + (void)HDmemset(expect_dst_buf, 0, sizeof(expect_dst_buf)); + for(i=0; i<8; i++) + expect_dst_buf[0][0][i] = src_buf[i]; + + /* Loop over buffer sizes */ + for(src_buf_size=1; src_buf_size<=9; src_buf_size++) { + /* Reset dst_buf */ + (void)HDmemset(dst_buf, 0, sizeof(dst_buf)); + + /* Set up scatter info */ + scatter_info.src_buf = src_buf; + scatter_info.block = src_buf_size; + scatter_info.size = 8; + + /* Scatter data */ + if(H5Dscatter(scatter_cb, &scatter_info, H5T_NATIVE_INT, sid, dst_buf) < 0) + TEST_ERROR + + /* Verify data */ + TEST_SCATTER_CHECK_ARR(dst_buf, expect_dst_buf) + } /* end for */ + + + /* + * Test 2: Single block in dataset + */ + /* Select hyperslab */ + start[0] = 3; + start[1] = 2; + start[2] = 4; + count[0] = 2; + count[1] = 3; + count[2] = 2; + if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL ,count, NULL) < 0) + TEST_ERROR + + /* Initialize expect_dst_buf */ + (void)HDmemset(expect_dst_buf, 0, sizeof(expect_dst_buf)); + src_i = 0; + for(i=3; i<5; i++) + for(j=2; j<5; j++) + for(k=4; k<6; k++) + expect_dst_buf[i][j][k] = src_buf[src_i++]; + + /* Loop over buffer sizes */ + for(src_buf_size=1; src_buf_size<=13; src_buf_size++) { + /* Reset dst_buf */ + (void)HDmemset(dst_buf, 0, sizeof(dst_buf)); + + /* Set up scatter info */ + scatter_info.src_buf = src_buf; + scatter_info.block = src_buf_size; + scatter_info.size = 12; + + /* Scatter data */ + if(H5Dscatter(scatter_cb, &scatter_info, H5T_NATIVE_INT, sid, dst_buf) < 0) + TEST_ERROR + + /* Verify data */ + TEST_SCATTER_CHECK_ARR(dst_buf, expect_dst_buf) + } /* end for */ + + + /* + * Test 3: Multiple blocks + */ + /* Select hyperslab */ + start[0] = 1; + start[1] = 1; + start[2] = 1; + stride[0] = 3; + stride[1] = 4; + stride[2] = 5; + count[0] = 3; + count[1] = 1; + count[2] = 2; + block[0] = 1; + block[1] = 3; + block[2] = 2; + if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride ,count, block) < 0) + TEST_ERROR + + /* Initialize expect_dst_buf */ + /* Iterate over block containing selection, checking if each element is in + * selection. Note that the algorithm used here (if statement) would not + * work for overlapping hyperslabs. */ + (void)HDmemset(expect_dst_buf, 0, sizeof(expect_dst_buf)); + src_i = 0; + for(i=1; i<8; i++) + for(j=1; j<4; j++) + for(k=1; k<8; k++) + if((hsize_t)i >= start[0] + && ((hsize_t)i - start[0]) % stride[0] < block[0] + && ((hsize_t)i - start[0]) / stride[0] < count[0] + && (hsize_t)j >= start[1] + && ((hsize_t)j - start[1]) % stride[1] < block[1] + && ((hsize_t)j - start[1]) / stride[1] < count[1] + && (hsize_t)k >= start[2] + && ((hsize_t)k - start[2]) % stride[2] < block[2] + && ((hsize_t)k - start[2]) / stride[2] < count[2]) + expect_dst_buf[i][j][k] = src_buf[src_i++]; + + /* Loop over buffer sizes */ + for(src_buf_size=1; src_buf_size<=37; src_buf_size++) { + /* Reset dst_buf */ + (void)HDmemset(dst_buf, 0, sizeof(dst_buf)); + + /* Set up scatter info */ + scatter_info.src_buf = src_buf; + scatter_info.block = src_buf_size; + scatter_info.size = 36; + + /* Scatter data */ + if(H5Dscatter(scatter_cb, &scatter_info, H5T_NATIVE_INT, sid, dst_buf) < 0) + TEST_ERROR + + /* Verify data */ + TEST_SCATTER_CHECK_ARR(dst_buf, expect_dst_buf) + } /* end for */ + + + /* + * Test 4: Compound selection + */ + /* Select hyperslabs */ + start[0] = 2; + start[1] = 1; + start[2] = 1; + count[0] = 2; + count[1] = 3; + count[2] = 2; + if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL ,count, NULL) < 0) + TEST_ERROR + start2[0] = 1; + start2[1] = 2; + start2[2] = 2; + count2[0] = 3; + count2[1] = 2; + count2[2] = 2; + if(H5Sselect_hyperslab(sid, H5S_SELECT_XOR, start2, NULL ,count2, NULL) < 0) + TEST_ERROR + + /* Initialize expect_dst_buf */ + /* Iterate over block containing selection, checking if each element is in + * selection. */ + (void)HDmemset(expect_dst_buf, 0, sizeof(expect_dst_buf)); + src_i = 0; + for(i=1; i<4; i++) + for(j=1; j<4; j++) + for(k=1; k<4; k++) + if(!(((hsize_t)i >= start[0] && (hsize_t)i < start[0] + count[0]) + && ((hsize_t)j >= start[1] && (hsize_t)j < start[1] + count[1]) + && ((hsize_t)k >= start[2] && (hsize_t)k < start[2] + count[2])) + != !(((hsize_t)i >= start2[0] && (hsize_t)i < start2[0] + count2[0]) + && ((hsize_t)j >= start2[1] && (hsize_t)j < start2[1] + count2[1]) + && ((hsize_t)k >= start2[2] && (hsize_t)k < start2[2] + count2[2]))) + expect_dst_buf[i][j][k] = src_buf[src_i++]; + + /* Loop over buffer sizes */ + for(src_buf_size=1; src_buf_size<=17; src_buf_size++) { + /* Reset dst_buf */ + (void)HDmemset(dst_buf, 0, sizeof(dst_buf)); + + /* Set up scatter info */ + scatter_info.src_buf = src_buf; + scatter_info.block = src_buf_size; + scatter_info.size = 16; + + /* Scatter data */ + if(H5Dscatter(scatter_cb, &scatter_info, H5T_NATIVE_INT, sid, dst_buf) < 0) + TEST_ERROR + + /* Verify data */ + TEST_SCATTER_CHECK_ARR(dst_buf, expect_dst_buf) + } /* end for */ + + + /* + * Test 5: Point selection + */ + /* Select hyperslabs */ + if(H5Sselect_elements(sid, H5S_SELECT_SET, sizeof(point) / sizeof(point[0]), (hsize_t *)point) < 0) + TEST_ERROR + + /* Initialize expect_dst_buf */ + /* Iterate over block containing selection, checking if each element is in + * selection. */ + (void)HDmemset(expect_dst_buf, 0, sizeof(expect_dst_buf)); + for(i=0; i<(int)(sizeof(point) / sizeof(point[0])); i++) + expect_dst_buf[point[i][0]][point[i][1]][point[i][2]] + = src_buf[i]; + + /* Loop over buffer sizes */ + for(src_buf_size=1; src_buf_size<=5; src_buf_size++) { + /* Reset dst_buf */ + (void)HDmemset(dst_buf, 0, sizeof(dst_buf)); + + /* Set up scatter info */ + scatter_info.src_buf = src_buf; + scatter_info.block = src_buf_size; + scatter_info.size = 4; + + /* Scatter data */ + if(H5Dscatter(scatter_cb, &scatter_info, H5T_NATIVE_INT, sid, dst_buf) < 0) + TEST_ERROR + + /* Verify data */ + TEST_SCATTER_CHECK_ARR(dst_buf, expect_dst_buf) + } /* end for */ + + + /* Close everything */ + if(H5Sclose(sid) < 0) TEST_ERROR + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY { + H5Sclose(sid); + } H5E_END_TRY; + return -1; +} /* end test_scatter() */ + + +/*------------------------------------------------------------------------- + * Function: test_gather + * + * Purpose: Tests H5Dgather with a variety of different selections and + * destination buffer sizes. + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Neil Fortner + * Wednesday, January 16, 2013 + * + *------------------------------------------------------------------------- + */ +typedef struct gather_info_t { + int *expect_dst_buf; /* Expected destination data buffer */ + size_t max_nelmts; /* Maximum number of elements passed to callback */ + hbool_t last_call; /* Whether this should be the last time the callback is called */ +} gather_info_t; + +static herr_t +gather_cb(const void *dst_buf, size_t dst_buf_bytes_used, + void *_gather_info) +{ + gather_info_t *gather_info = (gather_info_t *)_gather_info; + size_t nelmts; /* Number of elements in src_buf */ + int i; /* Local index variable */ + + HDassert(dst_buf_bytes_used > 0); + + /* Calculate number of elements */ + nelmts = dst_buf_bytes_used / sizeof(gather_info->expect_dst_buf[0]); + + /* Make sure the number of bytes is a multiple of the number of elements */ + if(nelmts * sizeof(gather_info->expect_dst_buf[0]) != dst_buf_bytes_used) + TEST_ERROR + + /* Make sure we weren't passed more data than we requested to be passed at + * once */ + if(nelmts > gather_info->max_nelmts) + TEST_ERROR + + /* If we were passed less data than requested, make sure this is the last + * time the callback was called */ + if(gather_info->last_call) + TEST_ERROR + if(nelmts < gather_info->max_nelmts) + gather_info->last_call = TRUE; + + /* Compare data and expected data */ + for(i=0; i<(int)nelmts; i++) + if(((const int *)dst_buf)[i] != *((gather_info->expect_dst_buf)++)) + TEST_ERROR + + return SUCCEED; + +error: + return FAIL; +} + +static herr_t +test_gather(void) +{ + hid_t sid = -1; /* Dataspace ID */ + hsize_t dim[3] = {8, 4, 8}; /* Dataspace dimensions */ + hsize_t start[3] = {0, 0, 0}; + hsize_t stride[3] = {0, 0, 0}; + hsize_t count[3] = {0, 0, 0}; + hsize_t block[3] = {0, 0, 0}; + hsize_t start2[3] = {0, 0, 0}; + hsize_t count2[3] = {0, 0, 0}; + hsize_t point[4][3] = {{2, 3, 2}, {3, 0, 2}, {7, 2, 0}, {0, 1, 5}}; + size_t dst_buf_size; + int src_buf[8][4][8]; /* Source data buffer */ + int dst_buf[36]; /* Destination data buffer */ + int expect_dst_buf[36]; /* Expected destination data buffer */ + gather_info_t gather_info; /* Operator data for callback */ + int i, j, k, dst_i; /* Local index variables */ + + TESTING("H5Dgather()"); + + /* Create dataspace */ + if((sid = H5Screate_simple(3, dim, NULL)) < 0) TEST_ERROR + + /* Initialize src_buf */ + for(i=0; i<(int)(sizeof(src_buf)/sizeof(src_buf[0])); i++) + for(j=0; j<(int)(sizeof(src_buf[0])/sizeof(src_buf[0][0])); j++) + for(k=0; k<(int)(sizeof(src_buf[0][0])/sizeof(src_buf[0][0][0])); k++) + src_buf[i][j][k] = 1 + k + + (int)(sizeof(src_buf[0][0]) / sizeof(src_buf[0][0][0])) * j + + (int)(sizeof(src_buf[0]) / sizeof(src_buf[0][0][0])) * i; + + + /* + * Test 1: Simple case + */ + /* Select hyperslab */ + count[0] = 1; + count[1] = 1; + count[2] = 10; + if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL ,count, NULL) < 0) + TEST_ERROR + + /* Initialize expect_dst_buf */ + (void)HDmemset(expect_dst_buf, 0, sizeof(expect_dst_buf)); + for(i=0; i<10; i++) + expect_dst_buf[i] = src_buf[0][0][i]; + + /* Loop over buffer sizes */ + for(dst_buf_size=1; dst_buf_size<=11; dst_buf_size++) { + /* Reset dst_buf */ + (void)HDmemset(dst_buf, 0, sizeof(dst_buf)); + + /* Initialize gather_info */ + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.max_nelmts = dst_buf_size; + gather_info.last_call = FALSE; + + /* Gather data */ + if(H5Dgather(sid, src_buf, H5T_NATIVE_INT, dst_buf_size * sizeof(dst_buf[0]), dst_buf, gather_cb, &gather_info) < 0) + TEST_ERROR + + /* Verify that all data has been gathered (and verified) */ + if(gather_info.expect_dst_buf - expect_dst_buf != 10) TEST_ERROR + } /* end for */ + + /* Test with a dst_buf_size that is not a multiple of the datatype size */ + /* Reset dst_buf */ + dst_buf_size = 7; + (void)HDmemset(dst_buf, 0, sizeof(dst_buf)); + + /* Initialize gather_info */ + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.max_nelmts = dst_buf_size - 1; + gather_info.last_call = FALSE; + + /* Gather data */ + if(H5Dgather(sid, src_buf, H5T_NATIVE_INT, dst_buf_size * sizeof(dst_buf[0]) - 1, dst_buf, gather_cb, &gather_info) < 0) + TEST_ERROR + + /* Verify that all data has been gathered (and verified) */ + if(gather_info.expect_dst_buf - expect_dst_buf != 10) TEST_ERROR + + + /* + * Test 2: Single block in dataset + */ + /* Select hyperslab */ + start[0] = 3; + start[1] = 2; + start[2] = 4; + count[0] = 2; + count[1] = 3; + count[2] = 2; + if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL ,count, NULL) < 0) + TEST_ERROR + + /* Initialize expect_dst_buf */ + (void)HDmemset(expect_dst_buf, 0, sizeof(expect_dst_buf)); + dst_i = 0; + for(i=3; i<5; i++) + for(j=2; j<5; j++) + for(k=4; k<6; k++) + expect_dst_buf[dst_i++] = src_buf[i][j][k]; + + /* Loop over buffer sizes */ + for(dst_buf_size=1; dst_buf_size<=13; dst_buf_size++) { + /* Reset dst_buf */ + (void)HDmemset(dst_buf, 0, sizeof(dst_buf)); + + /* Initialize gather_info */ + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.max_nelmts = dst_buf_size; + gather_info.last_call = FALSE; + + /* Gather data */ + if(H5Dgather(sid, src_buf, H5T_NATIVE_INT, dst_buf_size * sizeof(dst_buf[0]), dst_buf, gather_cb, &gather_info) < 0) + TEST_ERROR + + /* Verify that all data has been gathered (and verified) */ + if(gather_info.expect_dst_buf - expect_dst_buf != 12) TEST_ERROR + } /* end for */ + + + /* + * Test 3: Multiple blocks + */ + /* Select hyperslab */ + start[0] = 1; + start[1] = 1; + start[2] = 1; + stride[0] = 3; + stride[1] = 4; + stride[2] = 5; + count[0] = 3; + count[1] = 1; + count[2] = 2; + block[0] = 1; + block[1] = 3; + block[2] = 2; + if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride ,count, block) < 0) + TEST_ERROR + + /* Initialize expect_dst_buf */ + /* Iterate over block containing selection, checking if each element is in + * selection. Note that the algorithm used here (if statement) would not + * work for overlapping hyperslabs. */ + (void)HDmemset(expect_dst_buf, 0, sizeof(expect_dst_buf)); + dst_i = 0; + for(i=1; i<8; i++) + for(j=1; j<4; j++) + for(k=1; k<8; k++) + if((hsize_t)i >= start[0] + && ((hsize_t)i - start[0]) % stride[0] < block[0] + && ((hsize_t)i - start[0]) / stride[0] < count[0] + && (hsize_t)j >= start[1] + && ((hsize_t)j - start[1]) % stride[1] < block[1] + && ((hsize_t)j - start[1]) / stride[1] < count[1] + && (hsize_t)k >= start[2] + && ((hsize_t)k - start[2]) % stride[2] < block[2] + && ((hsize_t)k - start[2]) / stride[2] < count[2]) + expect_dst_buf[dst_i++] = src_buf[i][j][k]; + + /* Loop over buffer sizes */ + for(dst_buf_size=1; dst_buf_size<=37; dst_buf_size++) { + /* Reset dst_buf */ + (void)HDmemset(dst_buf, 0, sizeof(dst_buf)); + + /* Initialize gather_info */ + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.max_nelmts = dst_buf_size; + gather_info.last_call = FALSE; + + /* Gather data */ + if(H5Dgather(sid, src_buf, H5T_NATIVE_INT, dst_buf_size * sizeof(dst_buf[0]), dst_buf, gather_cb, &gather_info) < 0) + TEST_ERROR + + /* Verify that all data has been gathered (and verified) */ + if(gather_info.expect_dst_buf - expect_dst_buf != 36) TEST_ERROR + } /* end for */ + + + /* + * Test 4: Compound selection + */ + /* Select hyperslabs */ + start[0] = 2; + start[1] = 1; + start[2] = 1; + count[0] = 2; + count[1] = 3; + count[2] = 2; + if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL ,count, NULL) < 0) + TEST_ERROR + start2[0] = 1; + start2[1] = 2; + start2[2] = 2; + count2[0] = 3; + count2[1] = 2; + count2[2] = 2; + if(H5Sselect_hyperslab(sid, H5S_SELECT_XOR, start2, NULL ,count2, NULL) < 0) + TEST_ERROR + + /* Initialize expect_dst_buf */ + /* Iterate over block containing selection, checking if each element is in + * selection. */ + (void)HDmemset(expect_dst_buf, 0, sizeof(expect_dst_buf)); + dst_i = 0; + for(i=1; i<4; i++) + for(j=1; j<4; j++) + for(k=1; k<4; k++) + if(!(((hsize_t)i >= start[0] && (hsize_t)i < start[0] + count[0]) + && ((hsize_t)j >= start[1] && (hsize_t)j < start[1] + count[1]) + && ((hsize_t)k >= start[2] && (hsize_t)k < start[2] + count[2])) + != !(((hsize_t)i >= start2[0] && (hsize_t)i < start2[0] + count2[0]) + && ((hsize_t)j >= start2[1] && (hsize_t)j < start2[1] + count2[1]) + && ((hsize_t)k >= start2[2] && (hsize_t)k < start2[2] + count2[2]))) + expect_dst_buf[dst_i++] = src_buf[i][j][k]; + + /* Loop over buffer sizes */ + for(dst_buf_size=1; dst_buf_size<=17; dst_buf_size++) { + /* Reset dst_buf */ + (void)HDmemset(dst_buf, 0, sizeof(dst_buf)); + + /* Initialize gather_info */ + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.max_nelmts = dst_buf_size; + gather_info.last_call = FALSE; + + /* Gather data */ + if(H5Dgather(sid, src_buf, H5T_NATIVE_INT, dst_buf_size * sizeof(dst_buf[0]), dst_buf, gather_cb, &gather_info) < 0) + TEST_ERROR + + /* Verify that all data has been gathered (and verified) */ + if(gather_info.expect_dst_buf - expect_dst_buf != 16) TEST_ERROR + } /* end for */ + + + /* + * Test 5: Point selection + */ + /* Select hyperslabs */ + if(H5Sselect_elements(sid, H5S_SELECT_SET, sizeof(point) / sizeof(point[0]), (hsize_t *)point) < 0) + TEST_ERROR + + /* Initialize expect_dst_buf */ + /* Iterate over block containing selection, checking if each element is in + * selection. */ + (void)HDmemset(expect_dst_buf, 0, sizeof(expect_dst_buf)); + for(i=0; i<(int)(sizeof(point) / sizeof(point[0])); i++) + expect_dst_buf[i] = src_buf[point[i][0]][point[i][1]][point[i][2]]; + + /* Loop over buffer sizes */ + for(dst_buf_size=1; dst_buf_size<=5; dst_buf_size++) { + /* Reset dst_buf */ + (void)HDmemset(dst_buf, 0, sizeof(dst_buf)); + + /* Initialize gather_info */ + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.max_nelmts = dst_buf_size; + gather_info.last_call = FALSE; + + /* Gather data */ + if(H5Dgather(sid, src_buf, H5T_NATIVE_INT, dst_buf_size * sizeof(dst_buf[0]), dst_buf, gather_cb, &gather_info) < 0) + TEST_ERROR + + /* Verify that all data has been gathered (and verified) */ + if(gather_info.expect_dst_buf - expect_dst_buf != 4) TEST_ERROR + } /* end for */ + + + /* Close everything */ + if(H5Sclose(sid) < 0) TEST_ERROR + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY { + H5Sclose(sid); + } H5E_END_TRY; + return -1; +} /* end test_gather() */ + + +/*------------------------------------------------------------------------- + * Function: test_scatter_error + * + * Purpose: Tests H5Dscatter with a variety of different conditions + * that should cause errors. + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Neil Fortner + * Monday, February 4, 2013 + * + *------------------------------------------------------------------------- + */ +static herr_t +scatter_error_cb_fail(void **src_buf/*out*/, size_t *src_buf_bytes_used/*out*/, + void *_scatter_info) +{ + scatter_info_t *scatter_info = (scatter_info_t *)_scatter_info; + size_t nelmts; /* Number of elements to return in src_buf */ + + /* Calculate number of elements */ + nelmts = MIN(scatter_info->block, scatter_info->size); + HDassert(nelmts > 0); + + /* Set output variables */ + *src_buf = (void *)scatter_info->src_buf; + *src_buf_bytes_used = nelmts * sizeof(scatter_info->src_buf[0]); + + return FAIL; +} + +static herr_t +scatter_error_cb_null(void **src_buf/*out*/, size_t *src_buf_bytes_used/*out*/, + void *_scatter_info) +{ + scatter_info_t *scatter_info = (scatter_info_t *)_scatter_info; + size_t nelmts; /* Number of elements to return in src_buf */ + + /* Calculate number of elements */ + nelmts = MIN(scatter_info->block, scatter_info->size); + HDassert(nelmts > 0); + + /* Set output variables */ + *src_buf = NULL; + *src_buf_bytes_used = nelmts * sizeof(scatter_info->src_buf[0]); + + return SUCCEED; +} + +static herr_t +scatter_error_cb_unalign(void **src_buf/*out*/, size_t *src_buf_bytes_used/*out*/, + void *_src_buf_bytes_used) +{ + /* Set output variables */ + *src_buf = _src_buf_bytes_used; + *src_buf_bytes_used = *(size_t *)_src_buf_bytes_used; + + return SUCCEED; +} + +static herr_t +test_scatter_error(void) +{ + hid_t sid = -1; /* Dataspace ID */ + hsize_t dim[1] = {10}; /* Dataspace dimensions */ + hsize_t start[3] = {2}; + hsize_t count[3] = {6}; + int src_buf[7]; /* Source data buffer */ + int dst_buf[10]; /* Destination data buffer */ + scatter_info_t scatter_info; /* Operator data for callback */ + size_t cb_unalign_nbytes; /* Number of bytes to return for unaligned test */ + herr_t ret; /* Return value */ + int i; /* Local index variable */ + + TESTING("H5Dscatter() error conditions"); + + /* Create dataspace */ + if((sid = H5Screate_simple(1, dim, NULL)) < 0) TEST_ERROR + + /* Initialize src_buf */ + for(i=0; i<(int)(sizeof(src_buf)/sizeof(src_buf[0])); i++) + src_buf[i] = i + 1; + + /* Select hyperslab */ + if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL ,count, NULL) < 0) + TEST_ERROR + + /* Verify that base configuration passes */ + scatter_info.src_buf = src_buf; + scatter_info.block = sizeof(src_buf)/sizeof(src_buf[0]); + scatter_info.size = 6; + if(H5Dscatter(scatter_cb, &scatter_info, H5T_NATIVE_INT, sid, dst_buf) < 0) + TEST_ERROR + + + /* + * Test invalid parameters + */ + scatter_info.src_buf = src_buf; + scatter_info.size = 6; + H5E_BEGIN_TRY { + ret = H5Dscatter(NULL, NULL, H5T_NATIVE_INT, sid, dst_buf); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + scatter_info.src_buf = src_buf; + scatter_info.size = 6; + H5E_BEGIN_TRY { + ret = H5Dscatter(scatter_cb, &scatter_info, sid, sid, dst_buf); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + scatter_info.src_buf = src_buf; + scatter_info.size = 6; + H5E_BEGIN_TRY { + ret = H5Dscatter(scatter_cb, &scatter_info, H5T_NATIVE_INT, H5T_NATIVE_INT, dst_buf); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + scatter_info.src_buf = src_buf; + scatter_info.size = 6; + H5E_BEGIN_TRY { + ret = H5Dscatter(scatter_cb, &scatter_info, H5T_NATIVE_INT, sid, NULL); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + + /* + * Test returning too many elements in callback + */ + scatter_info.src_buf = src_buf; + scatter_info.size = 7; + H5E_BEGIN_TRY { + ret = H5Dscatter(scatter_cb, &scatter_info, H5T_NATIVE_INT, sid, dst_buf); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + + /* + * Test callback returns failure + */ + scatter_info.src_buf = src_buf; + scatter_info.size = 6; + H5E_BEGIN_TRY { + ret = H5Dscatter(scatter_error_cb_fail, &scatter_info, H5T_NATIVE_INT, sid, dst_buf); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + + /* + * Test callback returns NULL buffer + */ + scatter_info.src_buf = src_buf; + scatter_info.size = 6; + H5E_BEGIN_TRY { + ret = H5Dscatter(scatter_error_cb_null, &scatter_info, H5T_NATIVE_INT, sid, dst_buf); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + + /* + * Test callback returns 0 for src_buf_bytes_used + */ + cb_unalign_nbytes = 0; + H5E_BEGIN_TRY { + ret = H5Dscatter(scatter_error_cb_unalign, &cb_unalign_nbytes, H5T_NATIVE_INT, sid, dst_buf); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + + /* + * Test callback returns src_buf_bytes_used that is not a multiple of + * datatype size + */ + cb_unalign_nbytes = sizeof(src_buf[0]) - 1; + H5E_BEGIN_TRY { + ret = H5Dscatter(scatter_error_cb_unalign, &cb_unalign_nbytes, H5T_NATIVE_INT, sid, dst_buf); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + cb_unalign_nbytes = sizeof(src_buf[0]) + 1; + H5E_BEGIN_TRY { + ret = H5Dscatter(scatter_error_cb_unalign, &cb_unalign_nbytes, H5T_NATIVE_INT, sid, dst_buf); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + + /* Close everything */ + if(H5Sclose(sid) < 0) TEST_ERROR + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY { + H5Sclose(sid); + } H5E_END_TRY; + return -1; +} /* end test_scatter_error() */ + + +/*------------------------------------------------------------------------- + * Function: test_gather_error + * + * Purpose: Tests H5Dgather with a variety of different conditions + * that should cause errors. + * + * Return: Success: 0 + * Failure: -1 + * + * Programmer: Neil Fortner + * Monday, February 4, 2013 + * + *------------------------------------------------------------------------- + */ +static herr_t +gather_error_cb_fail(const void UNUSED *dst_buf, + size_t UNUSED dst_buf_bytes_used, void UNUSED *op_data) +{ + return FAIL; +} + +static herr_t +test_gather_error(void) +{ + hid_t sid = -1; /* Dataspace ID */ + hsize_t dim[1] = {10}; /* Dataspace dimensions */ + hsize_t start[1] = {2}; + hsize_t count[1] = {6}; + int src_buf[10]; /* Source data buffer */ + int dst_buf[6]; /* Destination data buffer */ + int expect_dst_buf[6]; /* Expected destination data buffer */ + gather_info_t gather_info; /* Operator data for callback */ + herr_t ret; /* Return value */ + int i; /* Local index variable */ + + TESTING("H5Dgather() error conditions"); + + /* Create dataspace */ + if((sid = H5Screate_simple(1, dim, NULL)) < 0) TEST_ERROR + + /* Initialize src_buf */ + for(i=0; i<(int)(sizeof(src_buf)/sizeof(src_buf[0])); i++) + src_buf[i] = 1 + i; + + /* Select hyperslab */ + if(H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL ,count, NULL) < 0) + TEST_ERROR + + /* Initialize expect_dst_buf */ + (void)HDmemset(expect_dst_buf, 0, sizeof(expect_dst_buf)); + for(i=0; i<6; i++) + expect_dst_buf[i] = src_buf[i + 2]; + + /* Verify that base configuration passes */ + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.max_nelmts = 6; + gather_info.last_call = FALSE; + if(H5Dgather(sid, src_buf, H5T_NATIVE_INT, 6 * sizeof(dst_buf[0]), dst_buf, gather_cb, &gather_info) < 0) + TEST_ERROR + + /* + * Test invalid parameters + */ + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.last_call = FALSE; + H5E_BEGIN_TRY { + ret = H5Dgather(H5T_NATIVE_INT, src_buf, H5T_NATIVE_INT, 6 * sizeof(dst_buf[0]), dst_buf, gather_cb, &gather_info); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.last_call = FALSE; + H5E_BEGIN_TRY { + ret = H5Dgather(sid, NULL, H5T_NATIVE_INT, 6 * sizeof(dst_buf[0]), dst_buf, gather_cb, &gather_info); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.last_call = FALSE; + H5E_BEGIN_TRY { + ret = H5Dgather(sid, src_buf, sid, 6 * sizeof(dst_buf[0]), dst_buf, gather_cb, &gather_info); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.last_call = FALSE; + H5E_BEGIN_TRY { + ret = H5Dgather(sid, src_buf, H5T_NATIVE_INT, 0, dst_buf, gather_cb, &gather_info); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.last_call = FALSE; + H5E_BEGIN_TRY { + ret = H5Dgather(sid, src_buf, H5T_NATIVE_INT, 1, dst_buf, gather_cb, &gather_info); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.last_call = FALSE; + H5E_BEGIN_TRY { + ret = H5Dgather(sid, src_buf, H5T_NATIVE_INT, 6 * sizeof(dst_buf[0]), NULL, gather_cb, &gather_info); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.last_call = FALSE; + H5E_BEGIN_TRY { + ret = H5Dgather(sid, src_buf, H5T_NATIVE_INT, 6 * sizeof(dst_buf[0]), dst_buf, NULL, &gather_info); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + + /* + * Test callback returns failure + */ + gather_info.expect_dst_buf = expect_dst_buf; + gather_info.last_call = FALSE; + H5E_BEGIN_TRY { + ret = H5Dgather(sid, src_buf, H5T_NATIVE_INT, 6 * sizeof(dst_buf[0]), dst_buf, gather_error_cb_fail, NULL); + } H5E_END_TRY + if(ret >= 0) TEST_ERROR + + + /* Close everything */ + if(H5Sclose(sid) < 0) TEST_ERROR + + PASSED(); + + return 0; + +error: + H5E_BEGIN_TRY { + H5Sclose(sid); + } H5E_END_TRY; + return -1; +} /* end test_gather_error() */ + + +/*------------------------------------------------------------------------- * Function: main * * Purpose: Tests the dataset interface (H5D) @@ -8315,6 +9321,12 @@ main(void) /* Close 2nd FAPL */ if(H5Pclose(fapl2) < 0) TEST_ERROR + /* Tests that do not use files */ + nerrors += (test_scatter() < 0 ? 1 : 0); + nerrors += (test_gather() < 0 ? 1 : 0); + nerrors += (test_scatter_error() < 0 ? 1 : 0); + nerrors += (test_gather_error() < 0 ? 1 : 0); + /* Verify symbol table messages are cached */ nerrors += (h5_verify_cached_stabs(FILENAME, fapl) < 0 ? 1 : 0); -- cgit v0.12