From 02762e8244741b9ff1f9203788e7237f53cf8d96 Mon Sep 17 00:00:00 2001 From: Dana Robinson Date: Thu, 16 Jul 2020 12:16:05 -0700 Subject: Merge of dataspace improvements from develop. --- src/H5Dchunk.c | 579 +- src/H5Dfill.c | 4 +- src/H5Dio.c | 14 +- src/H5Dmpio.c | 66 +- src/H5Dpkg.h | 17 +- src/H5Dscatgath.c | 79 +- src/H5Dselect.c | 67 +- src/H5Dvirtual.c | 17 +- src/H5Fint.c | 3 +- src/H5Gloc.c | 182 +- src/H5Gname.c | 4 +- src/H5Gtest.c | 1 + src/H5I.c | 56 +- src/H5Ipublic.h | 1 + src/H5O.c | 399 +- src/H5Oflush.c | 15 +- src/H5Oint.c | 14 +- src/H5Sall.c | 293 +- src/H5Shyper.c | 15697 +++++++++++++++++++++++------------------- src/H5Smpio.c | 481 +- src/H5Snone.c | 227 +- src/H5Spkg.h | 110 +- src/H5Spoint.c | 902 ++- src/H5Sprivate.h | 40 +- src/H5Spublic.h | 43 +- src/H5Sselect.c | 853 ++- src/H5Stest.c | 281 +- src/H5T.c | 15 +- src/H5err.txt | 1 + src/H5trace.c | 154 +- test/links.c | 23 +- test/objcopy.c | 2 +- test/testfiles/err_compat_1 | 4 +- test/tfile.c | 1 + test/th5s.c | 2 +- test/tselect.c | 4561 ++++++++---- testpar/t_shapesame.c | 120 +- testpar/t_span_tree.c | 12 +- 38 files changed, 15214 insertions(+), 10126 deletions(-) diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c index 36c47d0..ae4300e 100644 --- a/src/H5Dchunk.c +++ b/src/H5Dchunk.c @@ -254,6 +254,8 @@ static herr_t H5D__chunk_init(H5F_t *f, const H5D_t *dset, hid_t dapl_id); static herr_t H5D__chunk_io_init(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, H5D_chunk_map_t *fm); +static herr_t H5D__chunk_io_init_selections(const H5D_io_info_t *io_info, + const H5D_type_info_t *type_info, H5D_chunk_map_t *fm); static herr_t H5D__chunk_read(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, H5D_chunk_map_t *fm); @@ -293,8 +295,13 @@ static hbool_t H5D__chunk_cinfo_cache_found(const H5D_chunk_cached_t *last, static herr_t H5D__free_chunk_info(void *item, void *key, void *opdata); static herr_t H5D__create_chunk_map_single(H5D_chunk_map_t *fm, const H5D_io_info_t *io_info); +static herr_t H5D__create_chunk_file_map_all(H5D_chunk_map_t *fm, + const H5D_io_info_t *io_info); static herr_t H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t *io_info); + +static herr_t H5D__create_chunk_mem_map_1d(const H5D_chunk_map_t *fm); + static herr_t H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm); static herr_t H5D__chunk_file_cb(void *elem, const H5T_t *type, unsigned ndims, const hsize_t *coords, void *fm); @@ -409,7 +416,6 @@ H5D__chunk_direct_write(const H5D_t *dset, uint32_t filters, hsize_t *offset, H5D_chk_idx_info_t idx_info; /* Chunked index info */ hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */ hbool_t need_insert = FALSE; /* Whether the chunk needs to be inserted into the index */ - H5D_io_info_t io_info; /* to hold the dset info */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE_TAG(dset->oloc.addr) @@ -417,10 +423,12 @@ H5D__chunk_direct_write(const H5D_t *dset, uint32_t filters, hsize_t *offset, /* Sanity checks */ HDassert(layout->type == H5D_CHUNKED); - io_info.dset = dset; - /* Allocate dataspace and initialize it if it hasn't been. */ if(!H5D__chunk_is_space_alloc(&layout->storage)) { + H5D_io_info_t io_info; /* to hold the dset info */ + + io_info.dset = dset; + /* Allocate storage */ if(H5D__alloc_storage(&io_info, H5D_ALLOC_WRITE, FALSE, NULL) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize storage") @@ -1092,16 +1100,10 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf H5D_chunk_map_t *fm) { const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */ - const H5T_t *mem_type = type_info->mem_type; /* Local pointer to memory datatype */ - H5S_t *tmp_mspace = NULL; /* Temporary memory dataspace */ hssize_t old_offset[H5O_LAYOUT_NDIMS]; /* Old selection offset */ htri_t file_space_normalized = FALSE; /* File dataspace was normalized */ - H5T_t *file_type = NULL; /* Temporary copy of file datatype for iteration */ - hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */ unsigned f_ndims; /* The number of dimensions of the file's dataspace */ int sm_ndims; /* The number of dimensions of the memory buffer's dataspace (signed) */ - H5SL_node_t *curr_node; /* Current node in skip list */ - char bogus; /* "bogus" buffer to pass to selection iterator */ unsigned u; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ @@ -1154,13 +1156,54 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf fm->file_space = file_space; fm->mem_space = mem_space; + if(H5D__chunk_io_init_selections(io_info, type_info, fm) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file and memory chunk selections") + +done: + /* Reset the global dataspace info */ + fm->file_space = NULL; + fm->mem_space = NULL; + + if(file_space_normalized == TRUE) + if(H5S_hyper_denormalize_offset((H5S_t *)file_space, old_offset) < 0) /* (Casting away const OK -QAK) */ + HDONE_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't denormalize selection") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__chunk_io_init() */ + + +/*------------------------------------------------------------------------- + * Function: H5D__chunk_io_init_selections + * + * Purpose: Initialize the chunk mappings + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, March 20, 2008 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__chunk_io_init_selections(const H5D_io_info_t *io_info, const H5D_type_info_t *type_info, H5D_chunk_map_t *fm) +{ + const H5D_t *dataset = io_info->dset; /* Local pointer to dataset info */ + const H5T_t *mem_type = type_info->mem_type; /* Local pointer to memory datatype */ + H5S_t *tmp_mspace = NULL; /* Temporary memory dataspace */ + H5T_t *file_type = NULL; /* Temporary copy of file datatype for iteration */ + hbool_t iter_init = FALSE; /* Selection iteration info has been initialized */ + char bogus; /* "bogus" buffer to pass to selection iterator */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + /* Special case for only one element in selection */ /* (usually appending a record) */ - if(nelmts == 1 + if(fm->nelmts == 1 #ifdef H5_HAVE_PARALLEL && !(io_info->using_mpi_vfd) #endif /* H5_HAVE_PARALLEL */ - && H5S_SEL_ALL != H5S_GET_SELECT_TYPE(file_space)) { + && H5S_SEL_ALL != H5S_GET_SELECT_TYPE(fm->file_space)) { /* Initialize skip list for chunk selections */ fm->sel_chunks = NULL; fm->use_single = TRUE; @@ -1168,7 +1211,7 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf /* Initialize single chunk dataspace */ if(NULL == dataset->shared->cache.chunk.single_space) { /* Make a copy of the dataspace for the dataset */ - if((dataset->shared->cache.chunk.single_space = H5S_copy(file_space, TRUE, FALSE)) == NULL) + if((dataset->shared->cache.chunk.single_space = H5S_copy(fm->file_space, TRUE, FALSE)) == NULL) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy file space") /* Resize chunk's dataspace dimensions to size of chunk */ @@ -1210,9 +1253,9 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf fm->use_single = FALSE; /* Get type of selection on disk & in memory */ - if((fm->fsel_type = H5S_GET_SELECT_TYPE(file_space)) < H5S_SEL_NONE) + if((fm->fsel_type = H5S_GET_SELECT_TYPE(fm->file_space)) < H5S_SEL_NONE) HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection") - if((fm->msel_type = H5S_GET_SELECT_TYPE(mem_space)) < H5S_SEL_NONE) + if((fm->msel_type = H5S_GET_SELECT_TYPE(fm->mem_space)) < H5S_SEL_NONE) HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection") /* If the selection is NONE or POINTS, set the flag to FALSE */ @@ -1224,25 +1267,17 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf /* Check if file selection is a not a hyperslab selection */ if(sel_hyper_flag) { /* Build the file selection for each chunk */ - if(H5D__create_chunk_file_map_hyper(fm, io_info) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") - - /* Clean file chunks' hyperslab span "scratch" information */ - curr_node = H5SL_first(fm->sel_chunks); - while(curr_node) { - H5D_chunk_info_t *chunk_info; /* Pointer chunk information */ - - /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - HDassert(chunk_info); - - /* Clean hyperslab span's "scratch" information */ - if(H5S_hyper_reset_scratch(chunk_info->fspace) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info") + if(H5S_SEL_ALL == fm->fsel_type) { + if(H5D__create_chunk_file_map_all(fm, io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") + } /* end if */ + else { + /* Sanity check */ + HDassert(fm->fsel_type == H5S_SEL_HYPERSLABS); - /* Get the next chunk node in the skip list */ - curr_node = H5SL_next(curr_node); - } /* end while */ + if(H5D__create_chunk_file_map_hyper(fm, io_info) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") + } /* end else */ } /* end if */ else { H5S_sel_iter_op_t iter_op; /* Operator for iteration */ @@ -1262,7 +1297,7 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf iter_op.u.lib_op = H5D__chunk_file_cb; /* Spaces might not be the same shape, iterate over the file selection directly */ - if(H5S_select_iterate(&bogus, file_type, file_space, &iter_op, &udata) < 0) + if(H5S_select_iterate(&bogus, file_type, fm->file_space, &iter_op, &udata) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") /* Reset "last chunk" info */ @@ -1271,7 +1306,7 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf } /* end else */ /* Build the memory selection for each chunk */ - if(sel_hyper_flag && H5S_SELECT_SHAPE_SAME(file_space, mem_space) == TRUE) { + if(sel_hyper_flag && H5S_SELECT_SHAPE_SAME(fm->file_space, fm->mem_space) == TRUE) { /* Reset chunk template information */ fm->mchunk_tmpl = NULL; @@ -1281,12 +1316,17 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf if(H5D__create_chunk_mem_map_hyper(fm) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections") } /* end if */ + else if(sel_hyper_flag && fm->f_ndims == 1 && fm->m_ndims == 1 && + H5S_SELECT_IS_REGULAR(fm->mem_space) && H5S_SELECT_IS_SINGLE(fm->mem_space)) { + if(H5D__create_chunk_mem_map_1d(fm) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create file chunk selections") + } /* end else-if */ else { H5S_sel_iter_op_t iter_op; /* Operator for iteration */ size_t elmt_size; /* Memory datatype size */ /* Make a copy of equivalent memory space */ - if((tmp_mspace = H5S_copy(mem_space, TRUE, FALSE)) == NULL) + if((tmp_mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") /* De-select the mem space copy */ @@ -1304,7 +1344,7 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf /* Create selection iterator for memory selection */ if(0 == (elmt_size = H5T_get_size(mem_type))) HGOTO_ERROR(H5E_DATATYPE, H5E_BADSIZE, FAIL, "datatype size invalid") - if(H5S_select_iter_init(&(fm->mem_iter), mem_space, elmt_size) < 0) + if(H5S_select_iter_init(&(fm->mem_iter), fm->mem_space, elmt_size, 0) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") iter_init = TRUE; /* Selection iteration info has been initialized */ @@ -1312,59 +1352,28 @@ H5D__chunk_io_init(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf iter_op.u.lib_op = H5D__chunk_mem_cb; /* Spaces aren't the same shape, iterate over the memory selection directly */ - if(H5S_select_iterate(&bogus, file_type, file_space, &iter_op, fm) < 0) + if(H5S_select_iterate(&bogus, file_type, fm->file_space, &iter_op, fm) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to create memory chunk selections") - - /* Clean up hyperslab stuff, if necessary */ - if(fm->msel_type != H5S_SEL_POINTS) { - /* Clean memory chunks' hyperslab span "scratch" information */ - curr_node = H5SL_first(fm->sel_chunks); - while(curr_node) { - H5D_chunk_info_t *chunk_info; /* Pointer chunk information */ - - /* Get pointer to chunk's information */ - chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); - HDassert(chunk_info); - - /* Clean hyperslab span's "scratch" information */ - if(H5S_hyper_reset_scratch(chunk_info->mspace) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTFREE, FAIL, "unable to reset span scratch info") - - /* Get the next chunk node in the skip list */ - curr_node = H5SL_next(curr_node); - } /* end while */ - } /* end if */ } /* end else */ } /* end else */ done: /* Release the [potentially partially built] chunk mapping information if an error occurs */ if(ret_value < 0) { - if(tmp_mspace && !fm->mchunk_tmpl) { + if(tmp_mspace && !fm->mchunk_tmpl) if(H5S_close(tmp_mspace) < 0) HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "can't release memory chunk dataspace template") - } /* end if */ - if(H5D__chunk_io_term(fm) < 0) HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release chunk mapping") } /* end if */ - /* Reset the global dataspace info */ - fm->file_space = NULL; - fm->mem_space = NULL; - if(iter_init && H5S_SELECT_ITER_RELEASE(&(fm->mem_iter)) < 0) HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator") if(file_type && (H5T_close_real(file_type) < 0)) HDONE_ERROR(H5E_DATATYPE, H5E_CANTFREE, FAIL, "Can't free temporary datatype") - if(file_space_normalized == TRUE) { - /* (Casting away const OK -QAK) */ - if(H5S_hyper_denormalize_offset((H5S_t *)file_space, old_offset) < 0) - HDONE_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "can't denormalize selection") - } /* end if */ FUNC_LEAVE_NOAPI(ret_value) -} /* end H5D__chunk_io_init() */ +} /* end H5D__chunk_io_init_selections() */ /*------------------------------------------------------------------------- @@ -1591,9 +1600,213 @@ done: /*------------------------------------------------------------------------- + * Function: H5D__create_chunk_file_map_all + * + * Purpose: Create all chunk selections in file, for an "all" selection. + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Monday, January 21, 2019 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__create_chunk_file_map_all(H5D_chunk_map_t *fm, const H5D_io_info_t +#ifndef H5_HAVE_PARALLEL + H5_ATTR_UNUSED +#endif /* H5_HAVE_PARALLEL */ + *io_info) +{ + H5S_t *tmp_fchunk = NULL; /* Temporary file dataspace */ + hsize_t file_dims[H5S_MAX_RANK]; /* File dataspace dims */ + hsize_t sel_points; /* Number of elements in file selection */ + hsize_t zeros[H5S_MAX_RANK]; /* All zero vector (for start parameter to setting hyperslab on partial chunks) */ + hsize_t coords[H5S_MAX_RANK]; /* Current coordinates of chunk */ + hsize_t end[H5S_MAX_RANK]; /* Final coordinates of chunk */ + hsize_t scaled[H5S_MAX_RANK]; /* Scaled coordinates for this chunk */ + hsize_t chunk_index; /* "Index" of chunk */ + hsize_t curr_partial_clip[H5S_MAX_RANK]; /* Current partial dimension sizes to clip against */ + hsize_t partial_dim_size[H5S_MAX_RANK]; /* Size of a partial dimension */ + hbool_t is_partial_dim[H5S_MAX_RANK]; /* Whether a dimension is currently a partial chunk */ + unsigned num_partial_dims; /* Current number of partial dimensions */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity check */ + HDassert(fm->f_ndims > 0); + + /* Get number of elements selected in file */ + sel_points = fm->nelmts; + + /* Get dataspace dimensions */ + if(H5S_get_simple_extent_dims(fm->file_space, file_dims, NULL) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") + + /* Set initial chunk location, partial dimensions, etc */ + num_partial_dims = 0; + HDmemset(zeros, 0, sizeof(zeros)); + for(u = 0; u < fm->f_ndims; u++) { + /* Validate this chunk dimension */ + if(fm->layout->u.chunk.dim[u] == 0) + HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "chunk size must be > 0, dim = %u ", u) + + /* Set up start / end coordinates for first chunk */ + scaled[u] = 0; + coords[u] = 0; + end[u] = fm->chunk_dim[u] - 1; + + /* Iniitialize partial chunk dimension information */ + partial_dim_size[u] = file_dims[u] % fm->chunk_dim[u]; + if(file_dims[u] < fm->chunk_dim[u]) { + curr_partial_clip[u] = partial_dim_size[u]; + is_partial_dim[u] = TRUE; + num_partial_dims++; + } /* end if */ + else { + curr_partial_clip[u] = fm->chunk_dim[u]; + is_partial_dim[u] = FALSE; + } /* end else */ + } /* end for */ + + /* Set the index of this chunk */ + chunk_index = 0; + + /* Create "temporary" chunk for selection operations (copy file space) */ + if(NULL == (tmp_fchunk = H5S_create_simple(fm->f_ndims, fm->chunk_dim, NULL))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCREATE, FAIL, "unable to create dataspace for chunk") + + /* Iterate through each chunk in the dataset */ + while(sel_points) { + H5D_chunk_info_t *new_chunk_info; /* chunk information to insert into skip list */ + hsize_t chunk_points; /* Number of elements in chunk selection */ + + /* Add temporary chunk to the list of chunks */ + + /* Allocate the file & memory chunk information */ + if(NULL == (new_chunk_info = H5FL_MALLOC(H5D_chunk_info_t))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk info") + + /* Initialize the chunk information */ + + /* Set the chunk index */ + new_chunk_info->index = chunk_index; + +#ifdef H5_HAVE_PARALLEL + /* Store chunk selection information, for multi-chunk I/O */ + if(io_info->using_mpi_vfd) + fm->select_chunk[chunk_index] = new_chunk_info; +#endif /* H5_HAVE_PARALLEL */ + + /* Set the file chunk dataspace */ + if(NULL == (new_chunk_info->fspace = H5S_copy(tmp_fchunk, TRUE, FALSE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy chunk dataspace") + new_chunk_info->fspace_shared = FALSE; + + /* If there are partial dimensions for this chunk, set the hyperslab for them */ + if(num_partial_dims > 0) + if(H5S_select_hyperslab(new_chunk_info->fspace, H5S_SELECT_SET, zeros, NULL, curr_partial_clip, NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "can't create chunk selection") + + /* Set the memory chunk dataspace */ + new_chunk_info->mspace = NULL; + new_chunk_info->mspace_shared = FALSE; + + /* Copy the chunk's scaled coordinates */ + H5MM_memcpy(new_chunk_info->scaled, scaled, sizeof(hsize_t) * fm->f_ndims); + new_chunk_info->scaled[fm->f_ndims] = 0; + + /* Insert the new chunk into the skip list */ + if(H5SL_insert(fm->sel_chunks, new_chunk_info, &new_chunk_info->index) < 0) { + H5D__free_chunk_info(new_chunk_info, NULL, NULL); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert chunk into skip list") + } /* end if */ + + /* Get number of elements selected in chunk */ + chunk_points = H5S_GET_SELECT_NPOINTS(new_chunk_info->fspace); + H5_CHECKED_ASSIGN(new_chunk_info->chunk_points, uint32_t, chunk_points, hsize_t); + + /* Decrement # of points left in file selection */ + sel_points -= chunk_points; + + /* Advance to next chunk if we are not done */ + if(sel_points > 0) { + int curr_dim; /* Current dimension to increment */ + + /* Increment chunk index */ + chunk_index++; + + /* Set current increment dimension */ + curr_dim = (int)fm->f_ndims - 1; + + /* Increment chunk location in fastest changing dimension */ + coords[curr_dim] += fm->chunk_dim[curr_dim]; + scaled[curr_dim]++; + end[curr_dim] += fm->chunk_dim[curr_dim]; + + /* Bring chunk location back into bounds, if necessary */ + if(coords[curr_dim] >= file_dims[curr_dim]) { + do { + /* Reset current dimension's location to 0 */ + coords[curr_dim] = 0; + scaled[curr_dim] = 0; + end[curr_dim] = fm->chunk_dim[curr_dim] - 1; + + /* Check for previous partial chunk in this dimension */ + if(is_partial_dim[curr_dim] && end[curr_dim] < file_dims[curr_dim]) { + /* Sanity check */ + HDassert(num_partial_dims > 0); + + /* Reset partial chunk information for this dimension */ + curr_partial_clip[curr_dim] = fm->chunk_dim[curr_dim]; + is_partial_dim[curr_dim] = FALSE; + num_partial_dims--; + } /* end if */ + + /* Decrement current dimension */ + curr_dim--; + + /* Check for valid current dim */ + if(curr_dim >= 0) { + /* Increment chunk location in current dimension */ + coords[curr_dim] += fm->chunk_dim[curr_dim]; + scaled[curr_dim]++; + end[curr_dim] = (coords[curr_dim] + fm->chunk_dim[curr_dim]) - 1; + } /* end if */ + } while(curr_dim >= 0 && (coords[curr_dim] >= file_dims[curr_dim])); + } /* end if */ + + /* Check for valid current dim */ + if(curr_dim >= 0) { + /* Check for partial chunk in this dimension */ + if(!is_partial_dim[curr_dim] && file_dims[curr_dim] <= end[curr_dim]) { + /* Set partial chunk information for this dimension */ + curr_partial_clip[curr_dim] = partial_dim_size[curr_dim]; + is_partial_dim[curr_dim] = TRUE; + num_partial_dims++; + + /* Sanity check */ + HDassert(num_partial_dims <= fm->f_ndims); + } /* end if */ + } /* end if */ + } /* end if */ + } /* end while */ + +done: + /* Clean up */ + if(tmp_fchunk && H5S_close(tmp_fchunk) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "can't release temporary dataspace") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__create_chunk_file_map_all() */ + + +/*------------------------------------------------------------------------- * Function: H5D__create_chunk_file_map_hyper * - * Purpose: Create all chunk selections in file. + * Purpose: Create all chunk selections in file, for a hyperslab selection. * * Return: Non-negative on success/Negative on failure * @@ -1609,8 +1822,9 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t #endif /* H5_HAVE_PARALLEL */ *io_info) { - hsize_t sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ - hsize_t sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ + H5S_t *tmp_fchunk = NULL; /* Temporary file dataspace */ + hsize_t sel_start[H5O_LAYOUT_NDIMS]; /* Offset of low bound of file selection */ + hsize_t sel_end[H5O_LAYOUT_NDIMS]; /* Offset of high bound of file selection */ hsize_t sel_points; /* Number of elements in file selection */ hsize_t start_coords[H5O_LAYOUT_NDIMS]; /* Starting coordinates of selection */ hsize_t coords[H5O_LAYOUT_NDIMS]; /* Current coordinates of chunk */ @@ -1649,34 +1863,21 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t /* Iterate through each chunk in the dataset */ while(sel_points) { - /* Check for intersection of temporary chunk and file selection */ + /* Check for intersection of current chunk and file selection */ /* (Casting away const OK - QAK) */ - if(TRUE == H5S_hyper_intersect_block(fm->file_space, coords, end)) { - H5S_t *tmp_fchunk; /* Temporary file dataspace */ + if(TRUE == H5S_SELECT_INTERSECT_BLOCK(fm->file_space, coords, end)) { H5D_chunk_info_t *new_chunk_info; /* chunk information to insert into skip list */ hsize_t chunk_points; /* Number of elements in chunk selection */ - /* Create "temporary" chunk for selection operations (copy file space) */ - if(NULL == (tmp_fchunk = H5S_copy(fm->file_space, TRUE, FALSE))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") - - /* Make certain selections are stored in span tree form (not "optimized hyperslab" or "all") */ - if(H5S_hyper_convert(tmp_fchunk) < 0) { - (void)H5S_close(tmp_fchunk); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to convert selection to span trees") - } /* end if */ - - /* "AND" temporary chunk and current chunk */ - if(H5S_select_hyperslab(tmp_fchunk,H5S_SELECT_AND,coords,NULL,fm->chunk_dim,NULL) < 0) { - (void)H5S_close(tmp_fchunk); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't create chunk selection") - } /* end if */ + /* Create dataspace for chunk, 'AND'ing the overall selection with + * the current chunk. + */ + if(H5S_combine_hyperslab(fm->file_space, H5S_SELECT_AND, coords, NULL, fm->chunk_dim, NULL, &tmp_fchunk) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to combine file space selection with chunk block") /* Resize chunk's dataspace dimensions to size of chunk */ - if(H5S_set_extent_real(tmp_fchunk,fm->chunk_dim) < 0) { - (void)H5S_close(tmp_fchunk); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't adjust chunk dimensions") - } /* end if */ + if(H5S_set_extent_real(tmp_fchunk, fm->chunk_dim) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "can't adjust chunk dimensions") /* Move selection back to have correct offset in chunk */ if(H5S_SELECT_ADJUST_U(tmp_fchunk, coords) < 0) @@ -1685,10 +1886,8 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t /* Add temporary chunk to the list of chunks */ /* Allocate the file & memory chunk information */ - if(NULL == (new_chunk_info = H5FL_MALLOC(H5D_chunk_info_t))) { - (void)H5S_close(tmp_fchunk); - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate chunk info") - } /* end if */ + if(NULL == (new_chunk_info = H5FL_MALLOC(H5D_chunk_info_t))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk info") /* Initialize the chunk information */ @@ -1704,6 +1903,7 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t /* Set the file chunk dataspace */ new_chunk_info->fspace = tmp_fchunk; new_chunk_info->fspace_shared = FALSE; + tmp_fchunk = NULL; /* Set the memory chunk dataspace */ new_chunk_info->mspace = NULL; @@ -1720,7 +1920,7 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t } /* end if */ /* Get number of elements selected in chunk */ - chunk_points = H5S_GET_SELECT_NPOINTS(tmp_fchunk); + chunk_points = H5S_GET_SELECT_NPOINTS(new_chunk_info->fspace); H5_CHECKED_ASSIGN(new_chunk_info->chunk_points, uint32_t, chunk_points, hsize_t); /* Decrement # of points left in file selection */ @@ -1738,7 +1938,6 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t curr_dim = (int)fm->f_ndims - 1; /* Increment chunk location in fastest changing dimension */ - H5_CHECK_OVERFLOW(fm->chunk_dim[curr_dim],hsize_t,hssize_t); coords[curr_dim] += fm->chunk_dim[curr_dim]; end[curr_dim] += fm->chunk_dim[curr_dim]; scaled[curr_dim]++; @@ -1754,11 +1953,14 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t /* Decrement current dimension */ curr_dim--; - /* Increment chunk location in current dimension */ - scaled[curr_dim]++; - coords[curr_dim] += fm->chunk_dim[curr_dim]; - end[curr_dim] = (coords[curr_dim] + fm->chunk_dim[curr_dim]) - 1; - } while(coords[curr_dim] > sel_end[curr_dim]); + /* Check for valid current dim */ + if(curr_dim >= 0) { + /* Increment chunk location in current dimension */ + scaled[curr_dim]++; + coords[curr_dim] += fm->chunk_dim[curr_dim]; + end[curr_dim] = (coords[curr_dim] + fm->chunk_dim[curr_dim]) - 1; + } /* end if */ + } while(curr_dim >= 0 && (coords[curr_dim] > sel_end[curr_dim])); /* Re-calculate the index of this chunk */ chunk_index = H5VM_array_offset_pre(fm->f_ndims, fm->layout->u.chunk.down_chunks, scaled); @@ -1766,6 +1968,11 @@ H5D__create_chunk_file_map_hyper(H5D_chunk_map_t *fm, const H5D_io_info_t } /* end while */ done: + /* Clean up on failure */ + if(ret_value < 0) + if(tmp_fchunk && H5S_close(tmp_fchunk) < 0) + HDONE_ERROR(H5E_DATASET, H5E_CANTRELEASE, FAIL, "can't release temporary dataspace") + FUNC_LEAVE_NOAPI(ret_value) } /* end H5D__create_chunk_file_map_hyper() */ @@ -1789,13 +1996,13 @@ done: static herr_t H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm) { + H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */ H5SL_node_t *curr_node; /* Current node in skip list */ hsize_t file_sel_start[H5S_MAX_RANK]; /* Offset of low bound of file selection */ hsize_t file_sel_end[H5S_MAX_RANK]; /* Offset of high bound of file selection */ hsize_t mem_sel_start[H5S_MAX_RANK]; /* Offset of low bound of file selection */ hsize_t mem_sel_end[H5S_MAX_RANK]; /* Offset of high bound of file selection */ hssize_t adjust[H5S_MAX_RANK]; /* Adjustment to make to all file chunks */ - hssize_t chunk_adjust[H5S_MAX_RANK]; /* Adjustment to make to a particular chunk */ unsigned u; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ @@ -1806,8 +2013,6 @@ H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm) /* Check for all I/O going to a single chunk */ if(H5SL_count(fm->sel_chunks)==1) { - H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */ - /* Get the node */ curr_node = H5SL_first(fm->sel_chunks); @@ -1842,41 +2047,57 @@ H5D__create_chunk_mem_map_hyper(const H5D_chunk_map_t *fm) /* Iterate over each chunk in the chunk list */ curr_node = H5SL_first(fm->sel_chunks); while(curr_node) { - H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */ + hsize_t coords[H5S_MAX_RANK]; /* Current coordinates of chunk */ + hssize_t chunk_adjust[H5S_MAX_RANK]; /* Adjustment to make to a particular chunk */ + H5S_sel_type chunk_sel_type; /* Chunk's selection type */ /* Get pointer to chunk's information */ chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); HDassert(chunk_info); + /* Compute the chunk coordinates from the scaled coordinates */ + for(u = 0; u < fm->f_ndims; u++) + coords[u] = chunk_info->scaled[u] * fm->layout->u.chunk.dim[u]; + /* Copy the information */ /* Copy the memory dataspace */ if((chunk_info->mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") - /* Release the current selection */ - if(H5S_SELECT_RELEASE(chunk_info->mspace) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection") + /* Get the chunk's selection type */ + if((chunk_sel_type = H5S_GET_SELECT_TYPE(chunk_info->fspace)) < H5S_SEL_NONE) + HGOTO_ERROR(H5E_DATASET, H5E_BADSELECT, FAIL, "unable to get type of selection") - /* Copy the file chunk's selection */ - if(H5S_select_copy(chunk_info->mspace,chunk_info->fspace,FALSE) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy selection") + /* Set memory selection for "all" chunk selections */ + if(H5S_SEL_ALL == chunk_sel_type) { + /* Adjust the chunk coordinates */ + for(u = 0; u < fm->f_ndims; u++) + coords[u] = (hsize_t)((hssize_t)coords[u] - adjust[u]); - /* Compute the adjustment for this chunk */ - for(u = 0; u < fm->f_ndims; u++) { - hsize_t coords[H5O_LAYOUT_NDIMS]; /* Current coordinates of chunk */ + /* Set to same shape as chunk */ + if(H5S_select_hyperslab(chunk_info->mspace, H5S_SELECT_SET, coords, NULL, fm->chunk_dim, NULL) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "can't create chunk memory selection") + } /* end if */ + else { + /* Sanity check */ + HDassert(H5S_SEL_HYPERSLABS == chunk_sel_type); - /* Compute the chunk coordinates from the scaled coordinates */ - coords[u] = chunk_info->scaled[u] * fm->layout->u.chunk.dim[u]; + /* Copy the file chunk's selection */ + if(H5S_SELECT_COPY(chunk_info->mspace, chunk_info->fspace, FALSE) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy selection") - /* Compensate for the chunk offset */ - H5_CHECK_OVERFLOW(coords[u], hsize_t, hssize_t); - chunk_adjust[u] = adjust[u] - (hssize_t)coords[u]; /*lint !e771 The adjust array will always be initialized */ - } /* end for */ + /* Compute the adjustment for this chunk */ + for(u = 0; u < fm->f_ndims; u++) { + /* Compensate for the chunk offset */ + H5_CHECK_OVERFLOW(coords[u], hsize_t, hssize_t); + chunk_adjust[u] = adjust[u] - (hssize_t)coords[u]; + } /* end for */ - /* Adjust the selection */ - if(H5S_hyper_adjust_s(chunk_info->mspace, chunk_adjust) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to adjust selection") + /* Adjust the selection */ + if(H5S_SELECT_ADJUST_S(chunk_info->mspace, chunk_adjust) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSET, FAIL, "unable to adjust selection") + } /* end else */ /* Get the next chunk node in the skip list */ curr_node = H5SL_next(curr_node); @@ -1889,6 +2110,87 @@ done: /*------------------------------------------------------------------------- + * Function: H5D__create_mem_map_1d + * + * Purpose: Create all chunk selections for 1-dimensional regular memory space + * that has only one single block in the selection + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Vailin Choi + * Sept 18, 2019 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D__create_chunk_mem_map_1d(const H5D_chunk_map_t *fm) +{ + H5D_chunk_info_t *chunk_info; /* Pointer to chunk information */ + H5SL_node_t *curr_node; /* Current node in skip list */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity check */ + HDassert(fm->f_ndims>0); + + /* Check for all I/O going to a single chunk */ + if(H5SL_count(fm->sel_chunks)==1) { + /* Get the node */ + curr_node = H5SL_first(fm->sel_chunks); + + /* Get pointer to chunk's information */ + chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); + HDassert(chunk_info); + + /* Just point at the memory dataspace & selection */ + /* (Casting away const OK -QAK) */ + chunk_info->mspace = (H5S_t *)fm->mem_space; + + /* Indicate that the chunk's memory space is shared */ + chunk_info->mspace_shared = TRUE; + } /* end if */ + else { + hsize_t mem_sel_start[H5S_MAX_RANK]; /* Offset of low bound of file selection */ + hsize_t mem_sel_end[H5S_MAX_RANK]; /* Offset of high bound of file selection */ + + HDassert(fm->m_ndims == 1); + + if(H5S_SELECT_BOUNDS(fm->mem_space, mem_sel_start, mem_sel_end) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get file selection bound info") + + /* Iterate over each chunk in the chunk list */ + curr_node = H5SL_first(fm->sel_chunks); + while(curr_node) { + hsize_t chunk_points; /* Number of elements in chunk selection */ + hsize_t tmp_count = 1; + + /* Get pointer to chunk's information */ + chunk_info = (H5D_chunk_info_t *)H5SL_item(curr_node); + HDassert(chunk_info); + + /* Copy the memory dataspace */ + if((chunk_info->mspace = H5S_copy(fm->mem_space, TRUE, FALSE)) == NULL) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy memory space") + + chunk_points = H5S_GET_SELECT_NPOINTS(chunk_info->fspace); + + if(H5S_select_hyperslab(chunk_info->mspace, H5S_SELECT_SET, mem_sel_start, NULL, &tmp_count, &chunk_points) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTSELECT, FAIL, "can't create chunk memory selection") + + mem_sel_start[0] += chunk_points; + + /* Get the next chunk node in the skip list */ + curr_node = H5SL_next(curr_node); + } /* end while */ + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5D__create_chunk_mem_map_1d() */ + + +/*------------------------------------------------------------------------- * Function: H5D__chunk_file_cb * * Purpose: Callback routine for file selection iterator. Used when @@ -1994,7 +2296,7 @@ H5D__chunk_file_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, coords_in_chunk[u] = coords[u] - (scaled[u] * fm->layout->u.chunk.dim[u]); /* Add point to file selection for chunk */ - if(H5S_select_elements(chunk_info->fspace, H5S_SELECT_APPEND, (hsize_t)1, coords_in_chunk) < 0) + if(H5S_select_elements(chunk_info->fspace, H5S_SELECT_APPEND, (size_t)1, coords_in_chunk) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "unable to select element") /* Increment the number of elemented selected in chunk */ @@ -2023,7 +2325,7 @@ H5D__chunk_mem_cb(void H5_ATTR_UNUSED *elem, const H5T_t H5_ATTR_UNUSED *type, u { H5D_chunk_map_t *fm = (H5D_chunk_map_t *)_fm; /* File<->memory chunk mapping info */ H5D_chunk_info_t *chunk_info; /* Chunk information for current chunk */ - hsize_t coords_in_mem[H5O_LAYOUT_NDIMS]; /* Coordinates of element in memory */ + hsize_t coords_in_mem[H5S_MAX_RANK]; /* Coordinates of element in memory */ hsize_t chunk_index; /* Chunk index */ herr_t ret_value = SUCCEED; /* Return value */ @@ -2841,8 +3143,8 @@ done: /*------------------------------------------------------------------------- * Function: H5D__chunk_hash_val * - * Purpose: To calculate an index based on the dataset's scaled coordinates and - * sizes of the faster dimensions. + * Purpose: To calculate an index based on the dataset's scaled + * coordinates and sizes of the faster dimensions. * * Return: Hash value index * @@ -3227,8 +3529,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__chunk_cache_evict(const H5D_t *dset, H5D_rdcc_ent_t *ent, - hbool_t flush) +H5D__chunk_cache_evict(const H5D_t *dset, H5D_rdcc_ent_t *ent, hbool_t flush) { H5D_rdcc_t *rdcc = &(dset->shared->cache.chunk); herr_t ret_value = SUCCEED; /* Return value */ @@ -4713,7 +5014,6 @@ H5D__chunk_collective_fill(const H5D_t *dset, H5D_chunk_coll_info_t *chunk_info, to processes 0 -> leftover. */ if(leftover && leftover > mpi_rank) { chunk_disp_array[blocks] = (MPI_Aint)chunk_info->addr[blocks*mpi_size + mpi_rank]; - chunk_disp_array[blocks] = (MPI_Aint)chunk_info->addr[blocks*mpi_size + mpi_rank]; if(blocks && (chunk_disp_array[blocks] < chunk_disp_array[blocks - 1])) need_addr_sort = TRUE; block_lens[blocks] = block_len; @@ -4837,7 +5137,7 @@ H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk) const hsize_t *scaled = udata->common.scaled; /* Scaled chunk offset */ H5S_sel_iter_t *chunk_iter = NULL; /* Memory selection iteration info */ hbool_t chunk_iter_init = FALSE; /* Whether the chunk iterator has been initialized */ - hssize_t sel_nelmts; /* Number of elements in selection */ + hsize_t sel_nelmts; /* Number of elements in selection */ hsize_t count[H5O_LAYOUT_NDIMS]; /* Element count of hyperslab */ size_t chunk_size; /*size of a chunk */ void *chunk; /* The file chunk */ @@ -4898,8 +5198,7 @@ H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk) /* Get the number of elements in the selection */ sel_nelmts = H5S_GET_SELECT_NPOINTS(udata->chunk_space); - HDassert(sel_nelmts >= 0); - H5_CHECK_OVERFLOW(sel_nelmts, hssize_t, size_t); + H5_CHECK_OVERFLOW(sel_nelmts, hsize_t, size_t); /* Check for VL datatype & non-default fill value */ if(udata->fb_info.has_vlen_fill_type) @@ -4912,12 +5211,12 @@ H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata, hbool_t new_unfilt_chunk) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate chunk selection iterator") /* Create a selection iterator for scattering the elements to memory buffer */ - if(H5S_select_iter_init(chunk_iter, udata->chunk_space, layout->u.chunk.dim[rank]) < 0) + if(H5S_select_iter_init(chunk_iter, udata->chunk_space, layout->u.chunk.dim[rank], 0) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize chunk selection information") chunk_iter_init = TRUE; /* Scatter the data into memory */ - if(H5D__scatter_mem(udata->fb_info.fill_buf, udata->chunk_space, chunk_iter, (size_t)sel_nelmts, chunk/*out*/) < 0) + if(H5D__scatter_mem(udata->fb_info.fill_buf, chunk_iter, (size_t)sel_nelmts, chunk/*out*/) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "scatter failed") diff --git a/src/H5Dfill.c b/src/H5Dfill.c index e67926c..94c7b1c 100644 --- a/src/H5Dfill.c +++ b/src/H5Dfill.c @@ -275,12 +275,12 @@ H5D__fill(const void *fill, const H5T_t *fill_type, void *buf, HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate memory selection iterator") /* Create a selection iterator for scattering the elements to memory buffer */ - if(H5S_select_iter_init(mem_iter, space, dst_type_size) < 0) + if(H5S_select_iter_init(mem_iter, space, dst_type_size, 0) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") mem_iter_init = TRUE; /* Scatter the data into memory */ - if(H5D__scatter_mem(tmp_buf, space, mem_iter, (size_t)nelmts, buf/*out*/) < 0) + if(H5D__scatter_mem(tmp_buf, mem_iter, (size_t)nelmts, buf/*out*/) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed") } /* end if */ else { diff --git a/src/H5Dio.c b/src/H5Dio.c index 7762a5a..f8303fd 100644 --- a/src/H5Dio.c +++ b/src/H5Dio.c @@ -442,7 +442,6 @@ H5D__read(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, /* projected mem space must be discarded at the */ /* end of the function to avoid a memory leak. */ H5D_storage_t store; /* union of EFL and chunk pointer in file space */ - hssize_t snelmts; /* total number of elmts (signed) */ hsize_t nelmts; /* total number of elmts */ hbool_t io_op_init = FALSE; /* Whether the I/O op has been initialized */ char fake_char; /* Temporary variable for NULL buffer pointers */ @@ -457,9 +456,7 @@ H5D__read(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, file_space = dataset->shared->space; if(!mem_space) mem_space = file_space; - if((snelmts = H5S_GET_SELECT_NPOINTS(mem_space)) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dst dataspace has invalid selection") - H5_CHECKED_ASSIGN(nelmts, hsize_t, snelmts, hssize_t); + nelmts = H5S_GET_SELECT_NPOINTS(mem_space); /* Set up datatype info for operation */ if(H5D__typeinfo_init(dataset, mem_type_id, FALSE, &type_info) < 0) @@ -482,7 +479,7 @@ H5D__read(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, #endif /*H5_HAVE_PARALLEL*/ /* Make certain that the number of elements in each selection is the same */ - if(nelmts != (hsize_t)H5S_GET_SELECT_NPOINTS(file_space)) + if(nelmts != H5S_GET_SELECT_NPOINTS(file_space)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src and dest dataspaces have different number of elements selected") /* Check for a NULL buffer, after the H5S_ALL dataspace selection has been handled */ @@ -656,7 +653,6 @@ H5D__write(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, /* projected mem space must be discarded at the */ /* end of the function to avoid a memory leak. */ H5D_storage_t store; /* union of EFL and chunk pointer in file space */ - hssize_t snelmts; /* total number of elmts (signed) */ hsize_t nelmts; /* total number of elmts */ hbool_t io_op_init = FALSE; /* Whether the I/O op has been initialized */ char fake_char; /* Temporary variable for NULL buffer pointers */ @@ -712,12 +708,10 @@ H5D__write(H5D_t *dataset, hid_t mem_type_id, const H5S_t *mem_space, if(!mem_space) mem_space = file_space; - if((snelmts = H5S_GET_SELECT_NPOINTS(mem_space)) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src dataspace has invalid selection") - H5_CHECKED_ASSIGN(nelmts, hsize_t, snelmts, hssize_t); + nelmts = H5S_GET_SELECT_NPOINTS(mem_space); /* Make certain that the number of elements in each selection is the same */ - if(nelmts != (hsize_t)H5S_GET_SELECT_NPOINTS(file_space)) + if(nelmts != H5S_GET_SELECT_NPOINTS(file_space)) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "src and dest dataspaces have different number of elements selected") /* Check for a NULL buffer, after the H5S_ALL dataspace selection has been handled */ diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c index edb8d99..38a6dbd 100644 --- a/src/H5Dmpio.c +++ b/src/H5Dmpio.c @@ -544,8 +544,7 @@ H5D__mpio_array_gatherv(void *local_array, size_t local_array_num_entries, MPI_Comm_size(comm, &mpi_size); MPI_Comm_rank(comm, &mpi_rank); - /* - * Determine the size of the end result array by collecting the number + /* Determine the size of the end result array by collecting the number * of entries contributed by each processor into a single total. */ if (MPI_SUCCESS != (mpi_code = MPI_Allreduce(&local_array_num_entries, &gathered_array_num_entries, 1, MPI_INT, MPI_SUM, comm))) @@ -2525,7 +2524,9 @@ H5D__obtain_mpio_mode(H5D_io_info_t* io_info, H5D_chunk_map_t *fm, } /* end if */ /* Broadcasting the MPI_IO option info. and chunk address info. */ - if(MPI_SUCCESS != (mpi_code = MPI_Bcast(mergebuf, ((sizeof(haddr_t) + 1) * total_chunks), MPI_BYTE, root, comm))) + if((sizeof(haddr_t) + 1) * total_chunks > INT_MAX) + HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "result overflow") + if(MPI_SUCCESS != (mpi_code = MPI_Bcast(mergebuf, (int)((sizeof(haddr_t) + 1) * total_chunks), MPI_BYTE, root, comm))) HMPI_GOTO_ERROR(FAIL, "MPI_BCast failed", mpi_code) H5MM_memcpy(assign_io_mode, mergebuf, total_chunks); @@ -2607,7 +2608,7 @@ H5D__construct_filtered_io_info_list(const H5D_io_info_t *io_info, const H5D_typ H5D_chunk_info_t *chunk_info; H5D_chunk_ud_t udata; H5SL_node_t *chunk_node; - hssize_t select_npoints; + hsize_t select_npoints; hssize_t chunk_npoints; if(NULL == (local_info_array = (H5D_filtered_collective_io_info_t *) H5MM_malloc(num_chunks_selected * sizeof(H5D_filtered_collective_io_info_t)))) @@ -2633,8 +2634,7 @@ H5D__construct_filtered_io_info_list(const H5D_io_info_t *io_info, const H5D_typ H5MM_memcpy(local_info_array[i].scaled, chunk_info->scaled, sizeof(chunk_info->scaled)); - if ((select_npoints = H5S_GET_SELECT_NPOINTS(chunk_info->mspace)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "dataspace is invalid") + select_npoints = H5S_GET_SELECT_NPOINTS(chunk_info->mspace); local_info_array[i].io_size = (size_t) select_npoints * type_info->src_type_size; /* Currently the full overwrite status of a chunk is only obtained on a per-process @@ -2807,8 +2807,9 @@ H5D__chunk_redistribute_shared_chunks(const H5D_io_info_t *io_info, const H5D_ty /* Sort the new list in order of previous owner so that each original owner of a chunk * entry gets that entry back, with the possibly newly-modified "new_owner" field */ - HDqsort(shared_chunks_info_array, shared_chunks_info_array_num_entries, - sizeof(H5D_filtered_collective_io_info_t), H5D__cmp_filtered_collective_io_info_entry_owner); + if(shared_chunks_info_array_num_entries > 1) + HDqsort(shared_chunks_info_array, shared_chunks_info_array_num_entries, + sizeof(H5D_filtered_collective_io_info_t), H5D__cmp_filtered_collective_io_info_entry_owner); send_displacements[0] = 0; for (i = 1; i < (size_t) mpi_size; i++) @@ -2841,7 +2842,7 @@ H5D__chunk_redistribute_shared_chunks(const H5D_io_info_t *io_info, const H5D_ty if (mpi_rank != chunk_entry->owners.new_owner) { H5D_chunk_info_t *chunk_info = NULL; unsigned char *mod_data_p = NULL; - hssize_t iter_nelmts; + hsize_t iter_nelmts; size_t mod_data_size; /* Look up the chunk and get its file and memory dataspaces */ @@ -2854,9 +2855,9 @@ H5D__chunk_redistribute_shared_chunks(const H5D_io_info_t *io_info, const H5D_ty if(H5S_encode(chunk_info->fspace, &mod_data_p, &mod_data_size) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "unable to get encoded dataspace size") - if((iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->mspace)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "dataspace is invalid") + iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->mspace); + H5_CHECK_OVERFLOW(iter_nelmts, hsize_t, size_t); mod_data_size += (size_t) iter_nelmts * type_info->src_type_size; if(NULL == (mod_data[num_send_requests] = (unsigned char *) H5MM_malloc(mod_data_size))) @@ -2868,12 +2869,12 @@ H5D__chunk_redistribute_shared_chunks(const H5D_io_info_t *io_info, const H5D_ty HGOTO_ERROR(H5E_DATASET, H5E_CANTENCODE, FAIL, "unable to encode dataspace") /* Initialize iterator for memory selection */ - if(H5S_select_iter_init(mem_iter, chunk_info->mspace, type_info->src_type_size) < 0) + if(H5S_select_iter_init(mem_iter, chunk_info->mspace, type_info->src_type_size, 0) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") mem_iter_init = TRUE; /* Collect the modification data into the buffer */ - if(!H5D__gather_mem(io_info->u.wbuf, chunk_info->mspace, mem_iter, (size_t)iter_nelmts, mod_data_p)) + if(0 == H5D__gather_mem(io_info->u.wbuf, mem_iter, (size_t)iter_nelmts, mod_data_p)) HGOTO_ERROR(H5E_IO, H5E_CANTGATHER, FAIL, "couldn't gather from write buffer") /* Send modification data to new owner */ @@ -3088,7 +3089,7 @@ H5D__filtered_collective_chunk_entry_io(H5D_filtered_collective_io_info_t *chunk H5Z_EDC_t err_detect; /* Error detection info */ H5Z_cb_t filter_cb; /* I/O filter callback function */ unsigned filter_mask = 0; - hssize_t iter_nelmts; /* Number of points to iterate over for the chunk IO operation */ + hsize_t iter_nelmts; /* Number of points to iterate over for the chunk IO operation */ hssize_t extent_npoints; hsize_t true_chunk_size; hbool_t mem_iter_init = FALSE; @@ -3174,7 +3175,7 @@ H5D__filtered_collective_chunk_entry_io(H5D_filtered_collective_io_info_t *chunk if (NULL == (mem_iter = (H5S_sel_iter_t *) H5MM_malloc(sizeof(H5S_sel_iter_t)))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate memory iterator") - if (H5S_select_iter_init(mem_iter, chunk_info->mspace, type_info->src_type_size) < 0) + if(H5S_select_iter_init(mem_iter, chunk_info->mspace, type_info->src_type_size, 0) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") mem_iter_init = TRUE; @@ -3189,36 +3190,33 @@ H5D__filtered_collective_chunk_entry_io(H5D_filtered_collective_io_info_t *chunk if(NULL == (file_iter = (H5S_sel_iter_t *) H5MM_malloc(sizeof(H5S_sel_iter_t)))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate file iterator") - if(H5S_select_iter_init(file_iter, chunk_info->fspace, type_info->src_type_size) < 0) + if(H5S_select_iter_init(file_iter, chunk_info->fspace, type_info->src_type_size, 0) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") file_iter_init = TRUE; - if((iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->fspace)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "dataspace is invalid") + iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->fspace); - if(NULL == (tmp_gath_buf = H5MM_malloc((hsize_t) iter_nelmts * type_info->src_type_size))) + if(NULL == (tmp_gath_buf = H5MM_malloc(iter_nelmts * type_info->src_type_size))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate temporary gather buffer") - if(!H5D__gather_mem(chunk_entry->buf, chunk_info->fspace, file_iter, (size_t) iter_nelmts, tmp_gath_buf)) + if(!H5D__gather_mem(chunk_entry->buf, file_iter, (size_t) iter_nelmts, tmp_gath_buf)) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "couldn't gather from chunk buffer") - if((iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->mspace)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "dataspace is invalid") + iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->mspace); - if(H5D__scatter_mem(tmp_gath_buf, chunk_info->mspace, mem_iter, (size_t) iter_nelmts, io_info->u.rbuf) < 0) + if(H5D__scatter_mem(tmp_gath_buf, mem_iter, (size_t) iter_nelmts, io_info->u.rbuf) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "couldn't scatter to read buffer") break; case H5D_IO_OP_WRITE: - if((iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->mspace)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "dataspace is invalid") + iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->mspace); - if(NULL == (tmp_gath_buf = H5MM_malloc((hsize_t) iter_nelmts * type_info->src_type_size))) + if(NULL == (tmp_gath_buf = H5MM_malloc(iter_nelmts * type_info->src_type_size))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "couldn't allocate temporary gather buffer") /* Gather modification data from the application write buffer into a temporary buffer */ - if(!H5D__gather_mem(io_info->u.wbuf, chunk_info->mspace, mem_iter, (size_t) iter_nelmts, tmp_gath_buf)) + if(0 == H5D__gather_mem(io_info->u.wbuf, mem_iter, (size_t) iter_nelmts, tmp_gath_buf)) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "couldn't gather from write buffer") if(H5S_SELECT_ITER_RELEASE(mem_iter) < 0) @@ -3226,17 +3224,16 @@ H5D__filtered_collective_chunk_entry_io(H5D_filtered_collective_io_info_t *chunk mem_iter_init = FALSE; /* Initialize iterator for file selection */ - if(H5S_select_iter_init(mem_iter, chunk_info->fspace, type_info->dst_type_size) < 0) + if(H5S_select_iter_init(mem_iter, chunk_info->fspace, type_info->dst_type_size, 0) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information") mem_iter_init = TRUE; - if((iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->fspace)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "dataspace is invalid") + iter_nelmts = H5S_GET_SELECT_NPOINTS(chunk_info->fspace); /* Scatter the owner's modification data into the chunk data buffer according to * the file space. */ - if(H5D__scatter_mem(tmp_gath_buf, chunk_info->fspace, mem_iter, (size_t) iter_nelmts, chunk_entry->buf) < 0) + if(H5D__scatter_mem(tmp_gath_buf, mem_iter, (size_t) iter_nelmts, chunk_entry->buf) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "couldn't scatter to chunk data buffer") if(H5S_SELECT_ITER_RELEASE(mem_iter) < 0) @@ -3258,15 +3255,14 @@ H5D__filtered_collective_chunk_entry_io(H5D_filtered_collective_io_info_t *chunk if(NULL == (dataspace = H5S_decode(&mod_data_p))) HGOTO_ERROR(H5E_DATASET, H5E_CANTDECODE, FAIL, "unable to decode dataspace") - if(H5S_select_iter_init(mem_iter, dataspace, type_info->dst_type_size) < 0) + if(H5S_select_iter_init(mem_iter, dataspace, type_info->dst_type_size, 0) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") mem_iter_init = TRUE; - if((iter_nelmts = H5S_GET_SELECT_NPOINTS(dataspace)) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTCOUNT, FAIL, "dataspace is invalid") + iter_nelmts = H5S_GET_SELECT_NPOINTS(dataspace); /* Update the chunk data with the received modification data */ - if(H5D__scatter_mem(mod_data_p, dataspace, mem_iter, (size_t) iter_nelmts, chunk_entry->buf) < 0) + if(H5D__scatter_mem(mod_data_p, mem_iter, (size_t) iter_nelmts, chunk_entry->buf) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "couldn't scatter to write buffer") if(H5S_SELECT_ITER_RELEASE(mem_iter) < 0) diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index f44b250..3353a8e 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -563,18 +563,15 @@ H5_DLL H5D_t *H5D__open_name(const H5G_loc_t *loc, const char *name, hid_t dapl_ H5_DLL hid_t H5D__get_space(const H5D_t *dset); H5_DLL hid_t H5D__get_type(const H5D_t *dset); H5_DLL herr_t H5D__get_space_status(const H5D_t *dset, H5D_space_status_t *allocation); -H5_DLL herr_t H5D__alloc_storage(const H5D_io_info_t *io_info, H5D_time_alloc_t time_alloc, - hbool_t full_overwrite, hsize_t old_dim[]); +H5_DLL herr_t H5D__alloc_storage(const H5D_io_info_t *io_info, H5D_time_alloc_t time_alloc, hbool_t full_overwrite, hsize_t old_dim[]); H5_DLL herr_t H5D__get_storage_size(const H5D_t *dset, hsize_t *storage_size); -H5_DLL herr_t H5D__get_chunk_storage_size(H5D_t *dset, const hsize_t *offset, - hsize_t *storage_size); +H5_DLL herr_t H5D__get_chunk_storage_size(H5D_t *dset, const hsize_t *offset, hsize_t *storage_size); H5_DLL herr_t H5D__get_num_chunks(const H5D_t *dset, const H5S_t *space, hsize_t *nchunks); H5_DLL herr_t H5D__get_chunk_info(const H5D_t *dset, const H5S_t *space, hsize_t chk_idx, hsize_t *coord, unsigned *filter_mask, haddr_t *offset, hsize_t *size); H5_DLL herr_t H5D__get_chunk_info_by_coord(const H5D_t *dset, const hsize_t *coord, unsigned *filter_mask, haddr_t *addr, hsize_t *size); H5_DLL haddr_t H5D__get_offset(const H5D_t *dset); H5_DLL void *H5D__vlen_get_buf_size_alloc(size_t size, void *info); -H5_DLL herr_t H5D__vlen_get_buf_size(void *elem, hid_t type_id, unsigned ndim, - const hsize_t *point, void *op_data); +H5_DLL herr_t H5D__vlen_get_buf_size(void *elem, hid_t type_id, unsigned ndim, const hsize_t *point, void *op_data); H5_DLL herr_t H5D__check_filters(H5D_t *dataset); H5_DLL herr_t H5D__set_extent(H5D_t *dataset, const hsize_t *size); H5_DLL herr_t H5D__flush_sieve_buf(H5D_t *dataset); @@ -601,10 +598,10 @@ H5_DLL herr_t H5D__select_write(const H5D_io_info_t *io_info, hsize_t nelmts, const H5S_t *file_space, const H5S_t *mem_space); /* Functions that perform scatter-gather serial I/O operations */ -H5_DLL herr_t H5D__scatter_mem(const void *_tscat_buf, const H5S_t *space, - H5S_sel_iter_t *iter, size_t nelmts, void *_buf); -H5_DLL size_t H5D__gather_mem(const void *_buf, const H5S_t *space, - H5S_sel_iter_t *iter, size_t nelmts, void *_tgath_buf/*out*/); +H5_DLL herr_t H5D__scatter_mem(const void *_tscat_buf, H5S_sel_iter_t *iter, + size_t nelmts, void *_buf); +H5_DLL size_t H5D__gather_mem(const void *_buf, H5S_sel_iter_t *iter, + size_t nelmts, void *_tgath_buf/*out*/); H5_DLL 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); diff --git a/src/H5Dscatgath.c b/src/H5Dscatgath.c index 0e0edf7..cdf9da2 100644 --- a/src/H5Dscatgath.c +++ b/src/H5Dscatgath.c @@ -44,13 +44,11 @@ /* Local Prototypes */ /********************/ static herr_t H5D__scatter_file(const H5D_io_info_t *io_info, - const H5S_t *file_space, H5S_sel_iter_t *file_iter, size_t nelmts, - const void *buf); + H5S_sel_iter_t *file_iter, size_t nelmts, const void *buf); static size_t H5D__gather_file(const H5D_io_info_t *io_info, - const H5S_t *file_space, H5S_sel_iter_t *file_iter, size_t nelmts, - void *buf); -static herr_t H5D__compound_opt_read(size_t nelmts, const H5S_t *mem_space, - H5S_sel_iter_t *iter, const H5D_type_info_t *type_info, void *user_buf/*out*/); + H5S_sel_iter_t *file_iter, size_t nelmts, void *buf); +static herr_t H5D__compound_opt_read(size_t nelmts, H5S_sel_iter_t *iter, + const H5D_type_info_t *type_info, void *user_buf/*out*/); static herr_t H5D__compound_opt_write(size_t nelmts, const H5D_type_info_t *type_info); @@ -91,9 +89,8 @@ H5FL_SEQ_EXTERN(hsize_t); *------------------------------------------------------------------------- */ 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) +H5D__scatter_file(const H5D_io_info_t *_io_info, H5S_sel_iter_t *iter, + size_t nelmts, const void *_buf) { H5D_io_info_t tmp_io_info; /* Temporary I/O info object */ hsize_t *off = NULL; /* Pointer to sequence offsets */ @@ -112,7 +109,6 @@ H5D__scatter_file(const H5D_io_info_t *_io_info, /* Check args */ HDassert(_io_info); - HDassert(space); HDassert(iter); HDassert(nelmts > 0); HDassert(_buf); @@ -139,7 +135,7 @@ H5D__scatter_file(const H5D_io_info_t *_io_info, /* Loop until all elements are written */ while(nelmts > 0) { /* Get list of sequences for selection to write */ - if(H5S_SELECT_GET_SEQ_LIST(space, H5S_GET_SEQ_LIST_SORTED, iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0) + if(H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") /* Reset the current sequence information */ @@ -192,9 +188,8 @@ done: *------------------------------------------------------------------------- */ 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/*out*/) +H5D__gather_file(const H5D_io_info_t *_io_info, H5S_sel_iter_t *iter, + size_t nelmts, void *_buf/*out*/) { H5D_io_info_t tmp_io_info; /* Temporary I/O info object */ hsize_t *off = NULL; /* Pointer to sequence offsets */ @@ -215,7 +210,6 @@ H5D__gather_file(const H5D_io_info_t *_io_info, HDassert(_io_info); HDassert(_io_info->dset); HDassert(_io_info->store); - HDassert(space); HDassert(iter); HDassert(nelmts > 0); HDassert(_buf); @@ -242,7 +236,7 @@ H5D__gather_file(const H5D_io_info_t *_io_info, /* Loop until all elements are read */ while(nelmts > 0) { /* Get list of sequences for selection to read */ - if(H5S_SELECT_GET_SEQ_LIST(space, H5S_GET_SEQ_LIST_SORTED, iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0) + if(H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed") /* Reset the current sequence information */ @@ -289,8 +283,8 @@ done: *------------------------------------------------------------------------- */ herr_t -H5D__scatter_mem (const void *_tscat_buf, const H5S_t *space, - H5S_sel_iter_t *iter, size_t nelmts, void *_buf/*out*/) +H5D__scatter_mem(const void *_tscat_buf, H5S_sel_iter_t *iter, size_t nelmts, + void *_buf/*out*/) { uint8_t *buf = (uint8_t *)_buf; /* Get local copies for address arithmetic */ const uint8_t *tscat_buf = (const uint8_t *)_tscat_buf; @@ -308,7 +302,6 @@ H5D__scatter_mem (const void *_tscat_buf, const H5S_t *space, /* Check args */ HDassert(tscat_buf); - HDassert(space); HDassert(iter); HDassert(nelmts > 0); HDassert(buf); @@ -330,7 +323,7 @@ H5D__scatter_mem (const void *_tscat_buf, const H5S_t *space, /* Loop until all elements are written */ while(nelmts > 0) { /* Get list of sequences for selection to write */ - if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0) + if(H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0) HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed") /* Loop, while sequences left to process */ @@ -377,8 +370,8 @@ done: *------------------------------------------------------------------------- */ size_t -H5D__gather_mem(const void *_buf, const H5S_t *space, - H5S_sel_iter_t *iter, size_t nelmts, void *_tgath_buf/*out*/) +H5D__gather_mem(const void *_buf, H5S_sel_iter_t *iter, size_t nelmts, + void *_tgath_buf/*out*/) { const uint8_t *buf = (const uint8_t *)_buf; /* Get local copies for address arithmetic */ uint8_t *tgath_buf = (uint8_t *)_tgath_buf; @@ -396,7 +389,6 @@ H5D__gather_mem(const void *_buf, const H5S_t *space, /* Check args */ HDassert(buf); - HDassert(space); HDassert(iter); HDassert(nelmts > 0); HDassert(tgath_buf); @@ -418,7 +410,7 @@ H5D__gather_mem(const void *_buf, const H5S_t *space, /* Loop until all elements are written */ while(nelmts > 0) { /* Get list of sequences for selection to write */ - if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0) + if(H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &nelem, off, len) < 0) HGOTO_ERROR (H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed") /* Loop, while sequences left to process */ @@ -496,13 +488,13 @@ H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator") /* Figure out the strip mine size. */ - if(H5S_select_iter_init(file_iter, file_space, type_info->src_type_size) < 0) + if(H5S_select_iter_init(file_iter, file_space, type_info->src_type_size, H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information") file_iter_init = TRUE; /*file selection iteration info has been initialized */ - if(H5S_select_iter_init(mem_iter, mem_space, type_info->dst_type_size) < 0) + if(H5S_select_iter_init(mem_iter, mem_space, type_info->dst_type_size, 0) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") mem_iter_init = TRUE; /*file selection iteration info has been initialized */ - if(H5S_select_iter_init(bkg_iter, mem_space, type_info->dst_type_size) < 0) + if(H5S_select_iter_init(bkg_iter, mem_space, type_info->dst_type_size, 0) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information") bkg_iter_init = TRUE; /*file selection iteration info has been initialized */ @@ -523,7 +515,7 @@ H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf /* * Gather data */ - n = H5D__gather_file(io_info, file_space, file_iter, smine_nelmts, type_info->tconv_buf/*out*/); + n = H5D__gather_file(io_info, file_iter, smine_nelmts, type_info->tconv_buf/*out*/); if(n != smine_nelmts) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed") @@ -532,12 +524,12 @@ H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf * bypass the rest of steps. */ if(type_info->cmpd_subset && H5T_SUBSET_FALSE != type_info->cmpd_subset->subset) { - if(H5D__compound_opt_read(smine_nelmts, mem_space, mem_iter, type_info, buf /*out*/) < 0) + if(H5D__compound_opt_read(smine_nelmts, mem_iter, type_info, buf /*out*/) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "datatype conversion failed") } /* end if */ else { if(H5T_BKG_YES == type_info->need_bkg) { - n = H5D__gather_mem(buf, mem_space, bkg_iter, smine_nelmts, type_info->bkg_buf/*out*/); + n = H5D__gather_mem(buf, bkg_iter, smine_nelmts, type_info->bkg_buf/*out*/); if(n != smine_nelmts) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "mem gather failed") } /* end if */ @@ -563,7 +555,7 @@ H5D__scatgath_read(const H5D_io_info_t *io_info, const H5D_type_info_t *type_inf } /* Scatter the data into memory */ - if(H5D__scatter_mem(type_info->tconv_buf, mem_space, mem_iter, smine_nelmts, buf/*out*/) < 0) + if(H5D__scatter_mem(type_info->tconv_buf, mem_iter, smine_nelmts, buf/*out*/) < 0) HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "scatter failed") } /* end else */ } /* end for */ @@ -636,13 +628,13 @@ H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_in HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator") /* Figure out the strip mine size. */ - if(H5S_select_iter_init(file_iter, file_space, type_info->dst_type_size) < 0) + if(H5S_select_iter_init(file_iter, file_space, type_info->dst_type_size, H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information") file_iter_init = TRUE; /*file selection iteration info has been initialized */ - if(H5S_select_iter_init(mem_iter, mem_space, type_info->src_type_size) < 0) + if(H5S_select_iter_init(mem_iter, mem_space, type_info->src_type_size, 0) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information") mem_iter_init = TRUE; /*file selection iteration info has been initialized */ - if(H5S_select_iter_init(bkg_iter, file_space, type_info->dst_type_size) < 0) + if(H5S_select_iter_init(bkg_iter, file_space, type_info->dst_type_size, H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information") bkg_iter_init = TRUE; /*file selection iteration info has been initialized */ @@ -659,7 +651,7 @@ H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_in * buffer. Also gather data from the file into the background buffer * if necessary. */ - n = H5D__gather_mem(buf, mem_space, mem_iter, smine_nelmts, type_info->tconv_buf/*out*/); + n = H5D__gather_mem(buf, mem_iter, smine_nelmts, type_info->tconv_buf/*out*/); if(n != smine_nelmts) HGOTO_ERROR(H5E_IO, H5E_WRITEERROR, FAIL, "mem gather failed") @@ -676,7 +668,7 @@ H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_in } /* end if */ else { if(H5T_BKG_YES == type_info->need_bkg) { - n = H5D__gather_file(io_info, file_space, bkg_iter, smine_nelmts, type_info->bkg_buf/*out*/); + n = H5D__gather_file(io_info, bkg_iter, smine_nelmts, type_info->bkg_buf/*out*/); if(n != smine_nelmts) HGOTO_ERROR(H5E_IO, H5E_READERROR, FAIL, "file gather failed") } /* end if */ @@ -706,7 +698,7 @@ H5D__scatgath_write(const H5D_io_info_t *io_info, const H5D_type_info_t *type_in /* * Scatter the data out to the file. */ - if(H5D__scatter_file(io_info, file_space, file_iter, smine_nelmts, type_info->tconv_buf) < 0) + if(H5D__scatter_file(io_info, file_iter, smine_nelmts, type_info->tconv_buf) < 0) HGOTO_ERROR(H5E_DATASET, H5E_WRITEERROR, FAIL, "scatter failed") } /* end for */ @@ -762,7 +754,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5D__compound_opt_read(size_t nelmts, const H5S_t *space, H5S_sel_iter_t *iter, +H5D__compound_opt_read(size_t nelmts, H5S_sel_iter_t *iter, const H5D_type_info_t *type_info, void *user_buf/*out*/) { uint8_t *ubuf = (uint8_t *)user_buf; /* Cast for pointer arithmetic */ @@ -778,7 +770,6 @@ H5D__compound_opt_read(size_t nelmts, const H5S_t *space, H5S_sel_iter_t *iter, /* Check args */ HDassert(nelmts > 0); - HDassert(space); HDassert(iter); HDassert(type_info); HDassert(type_info->cmpd_subset); @@ -815,7 +806,7 @@ H5D__compound_opt_read(size_t nelmts, const H5S_t *space, H5S_sel_iter_t *iter, size_t elmtno; /* Element counter */ /* Get list of sequences for selection to write */ - if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, vec_size, nelmts, &nseq, &elmtno, off, len) < 0) + if(H5S_SELECT_ITER_GET_SEQ_LIST(iter, vec_size, nelmts, &nseq, &elmtno, off, len) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, 0, "sequence length generation failed") /* Loop, while sequences left to process */ @@ -982,7 +973,7 @@ H5Dscatter(H5D_scatter_func_t op, void *op_data, hid_t type_id, HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate selection iterator") /* Initialize selection iterator */ - if(H5S_select_iter_init(iter, dst_space, type_size) < 0) + if(H5S_select_iter_init(iter, dst_space, type_size, 0) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize selection iterator information") iter_init = TRUE; @@ -1006,7 +997,7 @@ H5Dscatter(H5D_scatter_func_t op, void *op_data, hid_t type_id, 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, dst_buf) < 0) + if(H5D__scatter_mem(src_buf, iter, nelmts_scatter, dst_buf) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCOPY, FAIL, "scatter failed") nelmts -= (hssize_t)nelmts_scatter; @@ -1092,14 +1083,14 @@ H5Dgather(hid_t src_space_id, const void *src_buf, hid_t type_id, HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate selection iterator") /* Initialize selection iterator */ - if(H5S_select_iter_init(iter, src_space, type_size) < 0) + if(H5S_select_iter_init(iter, src_space, type_size, 0) < 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), dst_buf))) + if(0 == (nelmts_gathered = H5D__gather_mem(src_buf, iter, MIN(dst_buf_nelmts, (size_t)nelmts), dst_buf))) HGOTO_ERROR(H5E_IO, H5E_CANTCOPY, FAIL, "gather failed") HDassert(nelmts_gathered == MIN(dst_buf_nelmts, (size_t)nelmts)); diff --git a/src/H5Dselect.c b/src/H5Dselect.c index 8b84c3e..5a5c491 100644 --- a/src/H5Dselect.c +++ b/src/H5Dselect.c @@ -113,51 +113,38 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, HDassert(io_info->store); HDassert(io_info->u.rbuf); - /* Get info from API context */ - if(H5CX_get_vec_size(&dxpl_vec_size) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve I/O vector size") - - /* Allocate the vector I/O arrays */ - if(dxpl_vec_size > H5D_IO_VECTOR_SIZE) - vec_size = dxpl_vec_size; - else - vec_size = H5D_IO_VECTOR_SIZE; - if(NULL == (mem_len = H5FL_SEQ_MALLOC(size_t, vec_size))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array") - if(NULL == (mem_off = H5FL_SEQ_MALLOC(hsize_t, vec_size))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array") - if(NULL == (file_len = H5FL_SEQ_MALLOC(size_t, vec_size))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array") - if(NULL == (file_off = H5FL_SEQ_MALLOC(hsize_t, vec_size))) - HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array") - /* Check for only one element in selection */ if(nelmts == 1) { + hsize_t single_mem_off; /* Offset in memory */ + hsize_t single_file_off; /* Offset in the file */ + size_t single_mem_len; /* Length in memory */ + size_t single_file_len; /* Length in the file */ + /* Get offset of first element in selections */ - if(H5S_SELECT_OFFSET(file_space, file_off) < 0) + if(H5S_SELECT_OFFSET(file_space, &single_file_off) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "can't retrieve file selection offset") - if(H5S_SELECT_OFFSET(mem_space, mem_off) < 0) + if(H5S_SELECT_OFFSET(mem_space, &single_mem_off) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "can't retrieve memory selection offset") /* Set up necessary information for I/O operation */ file_nseq = mem_nseq = 1; curr_mem_seq = curr_file_seq = 0; - *file_off *= elmt_size; - *mem_off *= elmt_size; - *file_len = *mem_len = elmt_size; + single_file_off *= elmt_size; + single_mem_off *= elmt_size; + single_file_len = single_mem_len = elmt_size; /* Perform I/O on memory and file sequences */ if(io_info->op_type == H5D_IO_OP_READ) { if((tmp_file_len = (*io_info->layout_ops.readvv)(io_info, - file_nseq, &curr_file_seq, file_len, file_off, - mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0) + file_nseq, &curr_file_seq, &single_file_len, &single_file_off, + mem_nseq, &curr_mem_seq, &single_mem_len, &single_mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, FAIL, "read error") } /* end if */ else { HDassert(io_info->op_type == H5D_IO_OP_WRITE); if((tmp_file_len = (*io_info->layout_ops.writevv)(io_info, - file_nseq, &curr_file_seq, file_len, file_off, - mem_nseq, &curr_mem_seq, mem_len, mem_off)) < 0) + file_nseq, &curr_file_seq, &single_file_len, &single_file_off, + mem_nseq, &curr_mem_seq, &single_mem_len, &single_mem_off)) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error") } /* end else */ @@ -168,6 +155,24 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, size_t mem_nelem; /* Number of elements used in memory sequences */ size_t file_nelem; /* Number of elements used in file sequences */ + /* Get info from API context */ + if(H5CX_get_vec_size(&dxpl_vec_size) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't retrieve I/O vector size") + + /* Allocate the vector I/O arrays */ + if(dxpl_vec_size > H5D_IO_VECTOR_SIZE) + vec_size = dxpl_vec_size; + else + vec_size = H5D_IO_VECTOR_SIZE; + if(NULL == (mem_len = H5FL_SEQ_MALLOC(size_t, vec_size))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array") + if(NULL == (mem_off = H5FL_SEQ_MALLOC(hsize_t, vec_size))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array") + if(NULL == (file_len = H5FL_SEQ_MALLOC(size_t, vec_size))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O length vector array") + if(NULL == (file_off = H5FL_SEQ_MALLOC(hsize_t, vec_size))) + HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate I/O offset vector array") + /* Allocate the iterators */ if(NULL == (mem_iter = H5FL_MALLOC(H5S_sel_iter_t))) HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate memory iterator") @@ -175,12 +180,12 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, HGOTO_ERROR(H5E_DATASET, H5E_CANTALLOC, FAIL, "can't allocate file iterator") /* Initialize file iterator */ - if(H5S_select_iter_init(file_iter, file_space, elmt_size) < 0) + if(H5S_select_iter_init(file_iter, file_space, elmt_size, H5S_SEL_ITER_GET_SEQ_LIST_SORTED) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") file_iter_init = 1; /* File selection iteration info has been initialized */ /* Initialize memory iterator */ - if(H5S_select_iter_init(mem_iter, mem_space, elmt_size) < 0) + if(H5S_select_iter_init(mem_iter, mem_space, elmt_size, 0) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") mem_iter_init = 1; /* Memory selection iteration info has been initialized */ @@ -193,7 +198,7 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, /* Check if more file sequences are needed */ if(curr_file_seq >= file_nseq) { /* Get sequences for file selection */ - if(H5S_SELECT_GET_SEQ_LIST(file_space, H5S_GET_SEQ_LIST_SORTED, file_iter, vec_size, nelmts, &file_nseq, &file_nelem, file_off, file_len) < 0) + if(H5S_SELECT_ITER_GET_SEQ_LIST(file_iter, vec_size, nelmts, &file_nseq, &file_nelem, file_off, file_len) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") /* Start at the beginning of the sequences again */ @@ -203,7 +208,7 @@ H5D__select_io(const H5D_io_info_t *io_info, size_t elmt_size, /* Check if more memory sequences are needed */ if(curr_mem_seq >= mem_nseq) { /* Get sequences for memory selection */ - if(H5S_SELECT_GET_SEQ_LIST(mem_space, 0, mem_iter, vec_size, nelmts, &mem_nseq, &mem_nelem, mem_off, mem_len) < 0) + if(H5S_SELECT_ITER_GET_SEQ_LIST(mem_iter, vec_size, nelmts, &mem_nseq, &mem_nelem, mem_off, mem_len) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") /* Start at the beginning of the sequences again */ diff --git a/src/H5Dvirtual.c b/src/H5Dvirtual.c index f11b904..f6aa3f9 100644 --- a/src/H5Dvirtual.c +++ b/src/H5Dvirtual.c @@ -35,6 +35,13 @@ * until the virtual dataset is closed. */ +/* + * Note: H5S_select_project_intersection has been updated to no longer require + * that the source and source intersect spaces have the same extent. This file + * should therefore be updated to remove code that ensures this condition, which + * should improve both maintainability and performance. + */ + /****************/ /* Module Setup */ /****************/ @@ -2399,7 +2406,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, /* Project intersection of virtual space and clipped * virtual space onto source space (create * clipped_source_select) */ - if(H5S_select_project_intersection(storage->list[i].sub_dset[j].virtual_select, storage->list[i].source_select, storage->list[i].sub_dset[j].clipped_virtual_select, &storage->list[i].sub_dset[j].clipped_source_select) < 0) + if(H5S_select_project_intersection(storage->list[i].sub_dset[j].virtual_select, storage->list[i].source_select, storage->list[i].sub_dset[j].clipped_virtual_select, &storage->list[i].sub_dset[j].clipped_source_select, TRUE) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto memory space") /* Set extents of virtual_select and @@ -2416,7 +2423,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, if(storage->list[i].sub_dset[j].clipped_virtual_select) { /* Project intersection of file space and mapping virtual space * onto memory space */ - if(H5S_select_project_intersection(file_space, mem_space, storage->list[i].sub_dset[j].clipped_virtual_select, &storage->list[i].sub_dset[j].projected_mem_space) < 0) + if(H5S_select_project_intersection(file_space, mem_space, storage->list[i].sub_dset[j].clipped_virtual_select, &storage->list[i].sub_dset[j].projected_mem_space, TRUE) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto memory space") /* Check number of elements selected */ @@ -2453,7 +2460,7 @@ H5D__virtual_pre_io(H5D_io_info_t *io_info, if(storage->list[i].source_dset.clipped_virtual_select) { /* Project intersection of file space and mapping virtual space onto * memory space */ - if(H5S_select_project_intersection(file_space, mem_space, storage->list[i].source_dset.clipped_virtual_select, &storage->list[i].source_dset.projected_mem_space) < 0) + if(H5S_select_project_intersection(file_space, mem_space, storage->list[i].source_dset.clipped_virtual_select, &storage->list[i].source_dset.projected_mem_space, TRUE) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto memory space") /* Check number of elements selected, add to tot_nelmts */ @@ -2583,7 +2590,7 @@ H5D__virtual_read_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, /* Project intersection of file space and mapping virtual space onto * mapping source space */ - if(H5S_select_project_intersection(source_dset->clipped_virtual_select, source_dset->clipped_source_select, file_space, &projected_src_space) < 0) + if(H5S_select_project_intersection(source_dset->clipped_virtual_select, source_dset->clipped_source_select, file_space, &projected_src_space, TRUE) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto source space") /* Perform read on source dataset */ @@ -2774,7 +2781,7 @@ H5D__virtual_write_one(H5D_io_info_t *io_info, const H5D_type_info_t *type_info, * extent in the unlimited dimension. -NAF */ /* Project intersection of file space and mapping virtual space onto * mapping source space */ - if(H5S_select_project_intersection(source_dset->virtual_select, source_dset->clipped_source_select, file_space, &projected_src_space) < 0) + if(H5S_select_project_intersection(source_dset->virtual_select, source_dset->clipped_source_select, file_space, &projected_src_space, TRUE) < 0) HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project virtual intersection onto source space") /* Perform write on source dataset */ diff --git a/src/H5Fint.c b/src/H5Fint.c index badf60b..eb023d6 100644 --- a/src/H5Fint.c +++ b/src/H5Fint.c @@ -443,6 +443,7 @@ H5F__get_objects_cb(void *obj_ptr, hid_t obj_id, void *key) case H5I_ERROR_CLASS: case H5I_ERROR_MSG: case H5I_ERROR_STACK: + case H5I_SPACE_SEL_ITER: case H5I_NTYPES: default: HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5_ITER_ERROR, "unknown or invalid data object") @@ -758,7 +759,7 @@ H5F_prefix_open_file(H5F_t *primary_file, H5F_prefix_open_t prefix_type, H5E_clear_stack(NULL); } /* end if */ - /* Success */ + /* Set return value (possibly NULL or valid H5F_t *) */ ret_value = src_file; done: diff --git a/src/H5Gloc.c b/src/H5Gloc.c index f5a14a1..de9268c 100644 --- a/src/H5Gloc.c +++ b/src/H5Gloc.c @@ -137,14 +137,14 @@ static herr_t H5G__loc_get_comment_cb(H5G_loc_t *grp_loc, const char *name, /*------------------------------------------------------------------------- - * Function: H5G_loc + * Function: H5G_loc * - * Purpose: Given an object ID return a location for the object. + * Purpose: Given an object ID return a location for the object. * - * Return: Success: Group pointer. - * Failure: NULL + * Return: Success: Group pointer. + * Failure: NULL * - * Programmer: Quincey Koziol + * Programmer: Quincey Koziol * Tuesday, September 13, 2005 * *------------------------------------------------------------------------- @@ -158,92 +158,97 @@ H5G_loc(hid_t loc_id, H5G_loc_t *loc) switch(H5I_get_type(loc_id)) { case H5I_FILE: - { - H5F_t *f; + { + H5F_t *f; - /* Get the file struct */ - if(NULL == (f = (H5F_t *)H5I_object(loc_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file ID") + /* Get the file struct */ + if(NULL == (f = (H5F_t *)H5I_object(loc_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid file ID") - /* Construct a group location for root group of the file */ - if(H5G_root_loc(f, loc) < 0) - HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unable to create location for file") - } /* end case */ + /* Construct a group location for root group of the file */ + if(H5G_root_loc(f, loc) < 0) + HGOTO_ERROR(H5E_SYM, H5E_BADVALUE, FAIL, "unable to create location for file") break; - - case H5I_GENPROP_CLS: - case H5I_GENPROP_LST: - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of property list") - - case H5I_ERROR_CLASS: - case H5I_ERROR_MSG: - case H5I_ERROR_STACK: - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of error class, message or stack") + } case H5I_GROUP: - { - H5G_t *group; - - if(NULL == (group = (H5G_t *)H5I_object(loc_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid group ID") - if(NULL == (loc->oloc = H5G_oloc(group))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location of group") - if(NULL == (loc->path = H5G_nameof(group))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path of group") - } /* end case */ + { + H5G_t *group; + + if(NULL == (group = (H5G_t *)H5I_object(loc_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid group ID") + if(NULL == (loc->oloc = H5G_oloc(group))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location of group") + if(NULL == (loc->path = H5G_nameof(group))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path of group") break; + } case H5I_DATATYPE: - { - H5T_t *dt; - - if(NULL == (dt = (H5T_t *)H5I_object(loc_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid type ID") - if(NULL == (loc->oloc = H5T_oloc(dt))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location of datatype") - if(NULL == (loc->path = H5T_nameof(dt))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path of datatype") - } /* end case */ + { + H5T_t *dt; + + if(NULL == (dt = (H5T_t *)H5I_object(loc_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid type ID") + if(NULL == (loc->oloc = H5T_oloc(dt))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location of datatype") + if(NULL == (loc->path = H5T_nameof(dt))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path of datatype") break; - - case H5I_DATASPACE: - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of dataspace") + } case H5I_DATASET: - { - H5D_t *dset; - - if(NULL == (dset = (H5D_t *)H5I_object(loc_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid data ID") - if(NULL == (loc->oloc = H5D_oloc(dset))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location of dataset") - if(NULL == (loc->path = H5D_nameof(dset))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path of dataset") - } /* end case */ + { + H5D_t *dset; + + if(NULL == (dset = (H5D_t *)H5I_object(loc_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid data ID") + if(NULL == (loc->oloc = H5D_oloc(dset))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location of dataset") + if(NULL == (loc->path = H5D_nameof(dset))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path of dataset") break; + } case H5I_ATTR: - { - H5A_t *attr; - - if(NULL == (attr = (H5A_t *)H5I_object(loc_id))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid attribute ID") - if(NULL == (loc->oloc = H5A_oloc(attr))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location of attribute") - if(NULL == (loc->path = H5A_nameof(attr))) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path of attribute") - } /* end case */ + { + H5A_t *attr; + + if(NULL == (attr = (H5A_t *)H5I_object(loc_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid attribute ID") + if(NULL == (loc->oloc = H5A_oloc(attr))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get object location of attribute") + if(NULL == (loc->path = H5A_nameof(attr))) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get path of attribute") break; + } + + case H5I_DATASPACE: + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of dataspace") + + case H5I_GENPROP_CLS: + case H5I_GENPROP_LST: + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of property list") + + case H5I_ERROR_CLASS: + case H5I_ERROR_MSG: + case H5I_ERROR_STACK: + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of error class, message or stack") + + case H5I_VFL: + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of a virtual file driver (VFD)") + + case H5I_SPACE_SEL_ITER: + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of a dataspace selection iterator") case H5I_REFERENCE: HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "unable to get group location of reference") case H5I_UNINIT: case H5I_BADID: - case H5I_VFL: case H5I_NTYPES: default: - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid object ID") + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid location ID") } /* end switch */ done: @@ -659,25 +664,25 @@ done: /*------------------------------------------------------------------------- - * Function: H5G_loc_info_cb + * Function: H5G__loc_info_cb * - * Purpose: Callback for retrieving object info for an object in a group + * Purpose: Callback for retrieving object info for an object in a group * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol + * Programmer: Quincey Koziol * Thursday, November 23, 2006 * *------------------------------------------------------------------------- */ static herr_t -H5G_loc_info_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name, const H5O_link_t H5_ATTR_UNUSED *lnk, +H5G__loc_info_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_ATTR_UNUSED *name, const H5O_link_t H5_ATTR_UNUSED *lnk, H5G_loc_t *obj_loc, void *_udata/*in,out*/, H5G_own_loc_t *own_loc/*out*/) { H5G_loc_info_t *udata = (H5G_loc_info_t *)_udata; /* User data passed in */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Check if the name in this group resolved to a valid link */ if(obj_loc == NULL) @@ -693,7 +698,7 @@ done: *own_loc = H5G_OWN_NONE; FUNC_LEAVE_NOAPI(ret_value) -} /* end H5G_loc_info_cb() */ +} /* end H5G__loc_info_cb() */ /*------------------------------------------------------------------------- @@ -727,7 +732,7 @@ H5G_loc_info(const H5G_loc_t *loc, const char *name, H5O_info_t *oinfo/*out*/, u udata.oinfo = oinfo; /* Traverse group hierarchy to locate object */ - if(H5G_traverse(loc, name, H5G_TARGET_NORMAL, H5G_loc_info_cb, &udata) < 0) + if(H5G_traverse(loc, name, H5G_TARGET_NORMAL, H5G__loc_info_cb, &udata) < 0) HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "can't find object") done: @@ -764,7 +769,7 @@ H5G__loc_set_comment_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_A /* Check for existing comment message */ if((exists = H5O_msg_exists(obj_loc->oloc, H5O_NAME_ID)) < 0) - HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to read object header") + HGOTO_ERROR(H5E_SYM, H5E_NOTFOUND, FAIL, "unable to read object header") /* Remove the previous comment message if any */ if(exists) @@ -774,9 +779,9 @@ H5G__loc_set_comment_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_A /* Add the new message */ if(udata->comment && *udata->comment) { /* Casting away const OK -QAK */ - comment.s = (char *)udata->comment; - if(H5O_msg_create(obj_loc->oloc, H5O_NAME_ID, 0, H5O_UPDATE_TIME, &comment) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to set comment object header message") + comment.s = (char *)udata->comment; + if(H5O_msg_create(obj_loc->oloc, H5O_NAME_ID, 0, H5O_UPDATE_TIME, &comment) < 0) + HGOTO_ERROR(H5E_OHDR, H5E_CANTINIT, FAIL, "unable to set comment object header message") } /* end if */ done: @@ -854,20 +859,21 @@ H5G__loc_get_comment_cb(H5G_loc_t H5_ATTR_UNUSED *grp_loc/*in*/, const char H5_A /* Query object comment */ comment.s = NULL; if(NULL == H5O_msg_read(obj_loc->oloc, H5O_NAME_ID, &comment)) { - if(udata->comment && udata->bufsize > 0) + if(udata->comment && udata->bufsize > 0) udata->comment[0] = '\0'; - udata->comment_size = 0; - } /* end if */ + udata->comment_size = 0; + } else { if(udata->comment && udata->bufsize) - HDstrncpy(udata->comment, comment.s, udata->bufsize); - udata->comment_size = (ssize_t)HDstrlen(comment.s); - H5O_msg_reset(H5O_NAME_ID, &comment); - } /* end else */ + HDstrncpy(udata->comment, comment.s, udata->bufsize); + udata->comment_size = (ssize_t)HDstrlen(comment.s); + H5O_msg_reset(H5O_NAME_ID, &comment); + } done: /* Indicate that this callback didn't take ownership of the group * - * location for the object */ + * location for the object. + */ *own_loc = H5G_OWN_NONE; FUNC_LEAVE_NOAPI(ret_value) diff --git a/src/H5Gname.c b/src/H5Gname.c index 3114fcc..1367b18 100644 --- a/src/H5Gname.c +++ b/src/H5Gname.c @@ -840,6 +840,7 @@ H5G_name_replace_cb(void *obj_ptr, hid_t obj_id, void *key) case H5I_ERROR_CLASS: case H5I_ERROR_MSG: case H5I_ERROR_STACK: + case H5I_SPACE_SEL_ITER: case H5I_NTYPES: default: HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unknown data object") @@ -1281,8 +1282,7 @@ done: *------------------------------------------------------------------------- */ ssize_t -H5G_get_name_by_addr(hid_t file, const H5O_loc_t *loc, - char *name, size_t size) +H5G_get_name_by_addr(hid_t file, const H5O_loc_t *loc, char *name, size_t size) { H5G_gnba_iter_t udata; /* User data for iteration */ H5G_loc_t root_loc; /* Root group's location */ diff --git a/src/H5Gtest.c b/src/H5Gtest.c index 02a1dd2..113dbe2 100644 --- a/src/H5Gtest.c +++ b/src/H5Gtest.c @@ -615,6 +615,7 @@ H5G__user_path_test(hid_t obj_id, char *user_path, size_t *user_path_len, unsign case H5I_ERROR_CLASS: case H5I_ERROR_MSG: case H5I_ERROR_STACK: + case H5I_SPACE_SEL_ITER: case H5I_NTYPES: default: HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unknown data object type") diff --git a/src/H5I.c b/src/H5I.c index b7ab6a5..0ce083f 100644 --- a/src/H5I.c +++ b/src/H5I.c @@ -136,7 +136,7 @@ static int H5I__id_dump_cb(void *_item, void *_key, void *_udata); * Return: Success: Positive if any action was taken that might * affect some other interface; zero otherwise. * - * Failure: Negative. + * Failure: Negative * *------------------------------------------------------------------------- */ @@ -340,10 +340,10 @@ H5Itype_exists(H5I_type_t type) /* Validate parameter */ if(H5I_IS_LIB_TYPE(type)) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "cannot call public function on library type") - if (type <= H5I_BADID || (int)type >= H5I_next_type) + if(type <= H5I_BADID || (int)type >= H5I_next_type) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number") - if (NULL == H5I_id_type_list_g[type]) + if(NULL == H5I_id_type_list_g[type]) ret_value = FALSE; done: @@ -437,7 +437,7 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5I_nmembers() */ - + /*------------------------------------------------------------------------- * Function: H5Iclear_type * @@ -1143,8 +1143,6 @@ done: * calling H5I_object(). * Failure: NULL * - * Programmer: Unknown - * *------------------------------------------------------------------------- */ void * @@ -1521,13 +1519,13 @@ H5Iinc_type_ref(H5I_type_t type) H5TRACE1("Is", "It", type); /* Check arguments */ - if (type <= 0 || (int)type >= H5I_next_type) + if(type <= 0 || (int)type >= H5I_next_type) HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, (-1), "invalid ID type") - if (H5I_IS_LIB_TYPE(type)) + if(H5I_IS_LIB_TYPE(type)) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, (-1), "cannot call public function on library type") /* Do actual increment operation */ - if ((ret_value = H5I__inc_type_ref(type)) < 0) + if((ret_value = H5I__inc_type_ref(type)) < 0) HGOTO_ERROR(H5E_ATOM, H5E_CANTINC, (-1), "can't increment ID type ref count") done: @@ -1558,7 +1556,7 @@ H5I__inc_type_ref(H5I_type_t type) /* Check arguments */ type_ptr = H5I_id_type_list_g[type]; - if (!type_ptr) + if(NULL == type_ptr) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, (-1), "invalid type") /* Set return value */ @@ -1638,11 +1636,11 @@ H5I_dec_type_ref(H5I_type_t type) FUNC_ENTER_NOAPI((-1)) - if (type <= H5I_BADID || (int)type >= H5I_next_type) + if(type <= H5I_BADID || (int)type >= H5I_next_type) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, (-1), "invalid type number") type_ptr = H5I_id_type_list_g[type]; - if (type_ptr == NULL || type_ptr->init_count <= 0) + if(type_ptr == NULL || type_ptr->init_count <= 0) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, (-1), "invalid type") /* Decrement the number of users of the atomic type. If this is the @@ -1650,7 +1648,7 @@ H5I_dec_type_ref(H5I_type_t type) * free all memory it used. The free function is invoked for each atom * being freed. */ - if (1 == type_ptr->init_count) { + if(1 == type_ptr->init_count) { H5I__destroy_type(type); ret_value = 0; } @@ -1683,13 +1681,13 @@ H5Iget_type_ref(H5I_type_t type) H5TRACE1("Is", "It", type); /* Check arguments */ - if (type <= 0 || (int)type >= H5I_next_type) + if(type <= 0 || (int)type >= H5I_next_type) HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, (-1), "invalid ID type") - if (H5I_IS_LIB_TYPE(type)) + if(H5I_IS_LIB_TYPE(type)) HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, (-1), "cannot call public function on library type") /* Do actual retrieve operation */ - if ((ret_value = H5I__get_type_ref(type)) < 0) + if((ret_value = H5I__get_type_ref(type)) < 0) HGOTO_ERROR(H5E_ATOM, H5E_CANTGET, (-1), "can't get ID type ref count") done: @@ -1847,7 +1845,7 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Isearch() */ - + /*------------------------------------------------------------------------- * Function: H5I__iterate_cb * @@ -1923,12 +1921,12 @@ H5I_iterate(H5I_type_t type, H5I_search_func_t func, void *udata, hbool_t app_re FUNC_ENTER_NOAPI(FAIL) /* Check arguments */ - if (type <= H5I_BADID || (int)type >= H5I_next_type) + if(type <= H5I_BADID || (int)type >= H5I_next_type) HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number") type_ptr = H5I_id_type_list_g[type]; /* Only iterate through ID list if it is initialized and there are IDs in type */ - if (type_ptr && type_ptr->init_count > 0 && type_ptr->id_count > 0) { + if(type_ptr && type_ptr->init_count > 0 && type_ptr->id_count > 0) { H5I_iterate_ud_t iter_udata; /* User data for iteration callback */ herr_t iter_status; /* Iteration status */ @@ -1938,7 +1936,7 @@ H5I_iterate(H5I_type_t type, H5I_search_func_t func, void *udata, hbool_t app_re iter_udata.app_ref = app_ref; /* Iterate over IDs */ - if ((iter_status = H5SL_iterate(type_ptr->ids, H5I__iterate_cb, &iter_udata)) < 0) + if((iter_status = H5SL_iterate(type_ptr->ids, H5I__iterate_cb, &iter_udata)) < 0) HGOTO_ERROR(H5E_ATOM, H5E_BADITER, FAIL, "iteration failed") } @@ -1970,11 +1968,10 @@ H5I__find_id(hid_t id) /* Check arguments */ type = H5I_TYPE(id); - if (type <= H5I_BADID || (int)type >= H5I_next_type) + if(type <= H5I_BADID || (int)type >= H5I_next_type) HGOTO_DONE(NULL) - type_ptr = H5I_id_type_list_g[type]; - if (!type_ptr || type_ptr->init_count <= 0) + if(!type_ptr || type_ptr->init_count <= 0) HGOTO_DONE(NULL) /* Locate the ID node for the ID */ @@ -2064,7 +2061,7 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Iget_file_id() */ - + /*------------------------------------------------------------------------- * Function: H5I_get_file_id * @@ -2160,6 +2157,7 @@ H5I__id_dump_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata) case H5I_ERROR_CLASS: case H5I_ERROR_MSG: case H5I_ERROR_STACK: + case H5I_SPACE_SEL_ITER: case H5I_NTYPES: default: break; /* Other types of IDs are not stored in files */ @@ -2198,14 +2196,14 @@ H5I_dump_ids_for_type(H5I_type_t type) if(type_ptr) { /* Header */ - HDfprintf(stderr, " init_count = %u\n", type_ptr->init_count); - HDfprintf(stderr, " reserved = %u\n", type_ptr->cls->reserved); - HDfprintf(stderr, " id_count = %llu\n", (unsigned long long)type_ptr->id_count); - HDfprintf(stderr, " nextid = %llu\n", (unsigned long long)type_ptr->nextid); + HDfprintf(stderr, " init_count = %u\n", type_ptr->init_count); + HDfprintf(stderr, " reserved = %u\n", type_ptr->cls->reserved); + HDfprintf(stderr, " id_count = %llu\n", (unsigned long long)type_ptr->id_count); + HDfprintf(stderr, " nextid = %llu\n", (unsigned long long)type_ptr->nextid); /* List */ if(type_ptr->id_count > 0) { - HDfprintf(stderr, " List:\n"); + HDfprintf(stderr, " List:\n"); H5SL_iterate(type_ptr->ids, H5I__id_dump_cb, &type); } } diff --git a/src/H5Ipublic.h b/src/H5Ipublic.h index 7acca3a..8eb6e6f 100644 --- a/src/H5Ipublic.h +++ b/src/H5Ipublic.h @@ -49,6 +49,7 @@ typedef enum H5I_type_t { H5I_ERROR_CLASS, /* type ID for error classes */ H5I_ERROR_MSG, /* type ID for error messages */ H5I_ERROR_STACK, /* type ID for error stacks */ + H5I_SPACE_SEL_ITER, /* type ID for dataspace selection iterator */ H5I_NTYPES /* number of library types, MUST BE LAST! */ } H5I_type_t; diff --git a/src/H5O.c b/src/H5O.c index 0d7e1ea..2a4b7e1 100644 --- a/src/H5O.c +++ b/src/H5O.c @@ -73,11 +73,11 @@ /* Local Variables */ /*******************/ - + /*------------------------------------------------------------------------- * Function: H5Oopen * - * Purpose: Opens an object within an HDF5 file. + * Purpose: Opens an object within an HDF5 file. * * This function opens an object in the same way that H5Gopen2, * H5Topen2, and H5Dopen2 do. However, H5Oopen doesn't require @@ -88,11 +88,11 @@ * The opened object should be closed again with H5Oclose * or H5Gclose, H5Tclose, or H5Dclose. * - * Return: Success: An open object identifier - * Failure: Negative + * Return: Success: An open object identifier + * Failure: H5I_INVALID_HID * - * Programmer: James Laird - * July 14 2006 + * Programmer: James Laird + * July 14 2006 * *------------------------------------------------------------------------- */ @@ -100,16 +100,18 @@ hid_t H5Oopen(hid_t loc_id, const char *name, hid_t lapl_id) { H5G_loc_t loc; /* Location of group */ - hid_t ret_value = FAIL; + hid_t ret_value = H5I_INVALID_HID; - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API(H5I_INVALID_HID) H5TRACE3("i", "i*si", loc_id, name, lapl_id); /* Check args */ if(H5G_loc(loc_id, &loc) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") - if(!name || !*name) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name") + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a location") + if(!name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "name parameter cannot be NULL") + if(!*name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "name parameter cannot be an empty string") /* Verify access property list and set up collective metadata if appropriate */ if(H5CX_set_apl(&lapl_id, H5P_CLS_LACC, loc_id, FALSE) < 0) @@ -117,17 +119,17 @@ H5Oopen(hid_t loc_id, const char *name, hid_t lapl_id) /* Open the object */ if((ret_value = H5O_open_name(&loc, name, TRUE)) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object") + HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, H5I_INVALID_HID, "unable to open object") done: FUNC_LEAVE_API(ret_value) } /* end H5Oopen() */ - + /*------------------------------------------------------------------------- * Function: H5Oopen_by_idx * - * Purpose: Opens an object within an HDF5 file, according to the offset + * Purpose: Opens an object within an HDF5 file, according to the offset * within an index. * * This function opens an object in the same way that H5Gopen, @@ -139,11 +141,11 @@ done: * The opened object should be closed again with H5Oclose * or H5Gclose, H5Tclose, or H5Dclose. * - * Return: Success: An open object identifier - * Failure: Negative + * Return: Success: An open object identifier + * Failure: H5I_INVALID_HID * - * Programmer: Quincey Koziol - * November 20 2006 + * Programmer: Quincey Koziol + * November 20 2006 * *------------------------------------------------------------------------- */ @@ -152,20 +154,20 @@ H5Oopen_by_idx(hid_t loc_id, const char *group_name, H5_index_t idx_type, H5_iter_order_t order, hsize_t n, hid_t lapl_id) { H5G_loc_t loc; /* Location of group */ - hid_t ret_value = FAIL; + hid_t ret_value = H5I_INVALID_HID; - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API(H5I_INVALID_HID) H5TRACE6("i", "i*sIiIohi", loc_id, group_name, idx_type, order, n, lapl_id); /* Check args */ if(H5G_loc(loc_id, &loc) < 0) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") if(!group_name || !*group_name) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name specified") + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "no name specified") if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified") + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "invalid index type specified") if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid iteration order specified") + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "invalid iteration order specified") /* Verify access property list and set up collective metadata if appropriate */ if(H5CX_set_apl(&lapl_id, H5P_CLS_LACC, loc_id, FALSE) < 0) @@ -173,17 +175,17 @@ H5Oopen_by_idx(hid_t loc_id, const char *group_name, H5_index_t idx_type, /* Open the object */ if((ret_value = H5O__open_by_idx(&loc, group_name, idx_type, order, n)) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, FAIL, "unable to open object") + HGOTO_ERROR(H5E_OHDR, H5E_CANTOPENOBJ, H5I_INVALID_HID, "unable to open object") done: FUNC_LEAVE_API(ret_value) } /* end H5Oopen_by_idx() */ - + /*------------------------------------------------------------------------- * Function: H5Oopen_by_addr * - * Purpose: Warning! This function is EXTREMELY DANGEROUS! + * Purpose: Warning! This function is EXTREMELY DANGEROUS! * Improper use can lead to FILE CORRUPTION, INACCESSIBLE DATA, * and other VERY BAD THINGS! * @@ -207,11 +209,11 @@ done: * HDF5 file, and HDF5's file drivers will transparently * map this to an address on disk for the filesystem. * - * Return: Success: An open object identifier - * Failure: Negative + * Return: Success: An open object identifier + * Failure: H5I_INVALID_HID * - * Programmer: James Laird - * July 14 2006 + * Programmer: James Laird + * July 14 2006 * *------------------------------------------------------------------------- */ @@ -238,24 +240,24 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Oopen_by_addr() */ - + /*------------------------------------------------------------------------- * Function: H5Olink * - * Purpose: Creates a hard link from NEW_NAME to the object specified - * by OBJ_ID using properties defined in the Link Creation + * Purpose: Creates a hard link from NEW_NAME to the object specified + * by OBJ_ID using properties defined in the Link Creation * Property List LCPL. * - * This function should be used to link objects that have just + * This function should be used to link objects that have just * been created. * - * NEW_NAME is interpreted relative to - * NEW_LOC_ID, which is either a file ID or a - * group ID. + * NEW_NAME is interpreted relative to + * NEW_LOC_ID, which is either a file ID or a + * group ID. * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: James Laird + * Programmer: James Laird * Tuesday, December 13, 2005 * *------------------------------------------------------------------------- @@ -266,7 +268,7 @@ H5Olink(hid_t obj_id, hid_t new_loc_id, const char *new_name, hid_t lcpl_id, { H5G_loc_t new_loc; /* Location of group to link from */ H5G_loc_t obj_loc; /* Location of object to link to */ - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE5("e", "ii*sii", obj_id, new_loc_id, new_name, lcpl_id, lapl_id); @@ -288,7 +290,7 @@ H5Olink(hid_t obj_id, hid_t new_loc_id, const char *new_name, hid_t lcpl_id, if(lcpl_id != H5P_DEFAULT && (TRUE != H5P_isa_class(lcpl_id, H5P_LINK_CREATE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a link creation property list") - /* Check the link creation property list */ + /* Get the link creation property list */ if(H5P_DEFAULT == lcpl_id) lcpl_id = H5P_LINK_CREATE_DEFAULT; @@ -299,7 +301,7 @@ H5Olink(hid_t obj_id, hid_t new_loc_id, const char *new_name, hid_t lcpl_id, if(H5CX_set_apl(&lapl_id, H5P_CLS_LACC, obj_id, TRUE) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access property list info") - /* Link to the object */ + /* Create a link to the object */ if(H5L_link(&new_loc, new_name, &obj_loc, lcpl_id) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTCREATE, FAIL, "unable to create link") @@ -307,11 +309,11 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Olink() */ - + /*------------------------------------------------------------------------- * Function: H5Oincr_refcount * - * Purpose: Warning! This function is EXTREMELY DANGEROUS! + * Purpose: Warning! This function is EXTREMELY DANGEROUS! * Improper use can lead to FILE CORRUPTION, INACCESSIBLE DATA, * and other VERY BAD THINGS! * @@ -320,11 +322,11 @@ done: * that references an object by address is created. When the * link is deleted, H5Odecr_refcount should be used. * - * Return: Success: Non-negative - * Failure: Negative + * Return: Success: Non-negative + * Failure: Negative * - * Programmer: James Laird - * July 14 2006 + * Programmer: James Laird + * July 14 2006 * *------------------------------------------------------------------------- */ @@ -337,15 +339,15 @@ H5Oincr_refcount(hid_t object_id) FUNC_ENTER_API(FAIL) H5TRACE1("e", "i", object_id); - /* Get the object's oloc so we can adjust its link count */ + /* Get the location object */ if((oloc = H5O_get_loc(object_id)) == NULL) - HGOTO_ERROR(H5E_ATOM, H5E_BADVALUE, FAIL, "unable to get object location from ID") + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier") /* Set up collective metadata if appropriate */ if(H5CX_set_loc(object_id) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access property list info") - /* Change the object's refcount */ + /* Change the object's reference count */ if(H5O_link(oloc, 1) < 0) HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "modifying object link count failed") @@ -353,11 +355,11 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5O_incr_refcount() */ - + /*------------------------------------------------------------------------- * Function: H5Odecr_refcount * - * Purpose: Warning! This function is EXTREMELY DANGEROUS! + * Purpose: Warning! This function is EXTREMELY DANGEROUS! * Improper use can lead to FILE CORRUPTION, INACCESSIBLE DATA, * and other VERY BAD THINGS! * @@ -366,11 +368,11 @@ done: * that reference an object by address are deleted, and only * after H5Oincr_refcount has already been used. * - * Return: Success: Non-negative - * Failure: Negative + * Return: Success: Non-negative + * Failure: Negative * - * Programmer: James Laird - * July 14 2006 + * Programmer: James Laird + * July 14 2006 * *------------------------------------------------------------------------- */ @@ -378,20 +380,20 @@ herr_t H5Odecr_refcount(hid_t object_id) { H5O_loc_t *oloc; /* Object location */ - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE1("e", "i", object_id); - /* Get the object's oloc so we can adjust its link count */ + /* Get the location object */ if((oloc = H5O_get_loc(object_id)) == NULL) - HGOTO_ERROR(H5E_ATOM, H5E_BADVALUE, FAIL, "unable to get object location from ID") + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier") /* Set up collective metadata if appropriate */ if(H5CX_set_loc(object_id) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access property list info") - /* Change the object's refcount */ + /* Change the object's reference count */ if(H5O_link(oloc, -1) < 0) HGOTO_ERROR(H5E_OHDR, H5E_LINKCOUNT, FAIL, "modifying object link count failed") @@ -399,17 +401,17 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Odecr_refcount() */ - + /*------------------------------------------------------------------------- * Function: H5Oexists_by_name * - * Purpose: Determine if a linked-to object exists + * Purpose: Determine if a linked-to object exists * - * Return: Success: TRUE/FALSE - * Failure: Negative + * Return: Success: TRUE/FALSE + * Failure: Negative * - * Programmer: Quincey Koziol - * February 2 2010 + * Programmer: Quincey Koziol + * February 2 2010 * *------------------------------------------------------------------------- */ @@ -440,7 +442,7 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Oexists_by_name() */ - + /*------------------------------------------------------------------------- * Function: H5Oget_info2 * @@ -448,8 +450,8 @@ done: * * NOTE: Add a parameter "fields" to indicate selection of object info. * - * Return: Success: Non-negative - * Failure: Negative + * Return: Success: Non-negative + * Failure: Negative * * Programmer: Neil Fortner * July 7 2010 @@ -481,25 +483,24 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Oget_info2() */ - - /*------------------------------------------------------------------------- - * Function: H5Oget_info_by_name2 - * - * Purpose: Retrieve information about an object. - * - * NOTE: Add a parameter "fields" to indicate selection of object info. - * - * Return: Success: Non-negative - * Failure: Negative - * - * Programmer: Neil Fortner - * July 7 2010 - * - *------------------------------------------------------------------------- - */ + +/*------------------------------------------------------------------------- + * Function: H5Oget_info_by_name2 + * + * Purpose: Retrieve information about an object + * + * NOTE: Adds a parameter "fields" to indicate selection of object info. + * + * Return: Success: Non-negative + * Failure: Negative + * + * Programmer: Neil Fortner + * July 7 2010 + * + *------------------------------------------------------------------------- + */ herr_t -H5Oget_info_by_name2(hid_t loc_id, const char *name, H5O_info_t *oinfo, - unsigned fields, hid_t lapl_id) +H5Oget_info_by_name2(hid_t loc_id, const char *name, H5O_info_t *oinfo, unsigned fields, hid_t lapl_id) { H5G_loc_t loc; /* Location of group */ herr_t ret_value = SUCCEED; /* Return value */ @@ -529,7 +530,7 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Oget_info_by_name2() */ - + /*------------------------------------------------------------------------- * Function: H5Oget_info_by_idx2 * @@ -541,7 +542,7 @@ done: * Return: Success: Non-negative * Failure: Negative * - * Programmer: Quincey Koziol + * Programmer: Quincey Koziol * November 26 2006 * *------------------------------------------------------------------------- @@ -583,21 +584,21 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Oget_info_by_idx2() */ - + /*------------------------------------------------------------------------- * Function: H5Oset_comment * * Purpose: Gives the specified object a comment. The COMMENT string - * should be a null terminated string. An object can have only - * one comment at a time. Passing NULL for the COMMENT argument - * will remove the comment property from the object. + * should be a null terminated string. An object can have only + * one comment at a time. Passing NULL for the COMMENT argument + * will remove the comment property from the object. * - * Note: Deprecated in favor of using attributes on objects + * Note: Deprecated in favor of using attributes on objects * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * August 30 2007 + * Programmer: Quincey Koziol + * August 30 2007 * *------------------------------------------------------------------------- */ @@ -610,9 +611,9 @@ H5Oset_comment(hid_t obj_id, const char *comment) FUNC_ENTER_API(FAIL) H5TRACE2("e", "i*s", obj_id, comment); - /* Check args */ + /* Get the location object */ if(H5G_loc(obj_id, &loc) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "invalid location identifier") /* Set up collective metadata if appropriate */ if(H5CX_set_loc(obj_id) < 0) @@ -626,21 +627,21 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Oset_comment() */ - + /*------------------------------------------------------------------------- * Function: H5Oset_comment_by_name * * Purpose: Gives the specified object a comment. The COMMENT string - * should be a null terminated string. An object can have only - * one comment at a time. Passing NULL for the COMMENT argument - * will remove the comment property from the object. + * should be a null terminated string. An object can have only + * one comment at a time. Passing NULL for the COMMENT argument + * will remove the comment property from the object. * - * Note: Deprecated in favor of using attributes on objects + * Note: Deprecated in favor of using attributes on objects * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success/Negative on failure * - * Programmer: Quincey Koziol - * August 30 2007 + * Programmer: Quincey Koziol + * August 30 2007 * *------------------------------------------------------------------------- */ @@ -672,20 +673,20 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Oset_comment_by_name() */ - + /*------------------------------------------------------------------------- * Function: H5Oget_comment * - * Purpose: Retrieve comment for an object. + * Purpose: Retrieve comment for an object. * - * Return: Success: Number of bytes in the comment excluding the - * null terminator. Zero if the object has no - * comment. + * Return: Success: Number of bytes in the comment excluding the + * null terminator. Zero if the object has no + * comment. * - * Failure: Negative + * Failure: -1 * - * Programmer: Quincey Koziol - * August 30 2007 + * Programmer: Quincey Koziol + * August 30 2007 * *------------------------------------------------------------------------- */ @@ -693,37 +694,37 @@ ssize_t H5Oget_comment(hid_t obj_id, char *comment, size_t bufsize) { H5G_loc_t loc; /* Location of group */ - ssize_t ret_value; /* Return value */ + ssize_t ret_value = -1; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API((-1)) H5TRACE3("Zs", "i*sz", obj_id, comment, bufsize); /* Check args */ if(H5G_loc(obj_id, &loc) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "not a location") /* Retrieve the object's comment */ if((ret_value = H5G_loc_get_comment(&loc, ".", comment/*out*/, bufsize)) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get comment for object") + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, (-1), "can't get comment for object") done: FUNC_LEAVE_API(ret_value) } /* end H5Oget_comment() */ - + /*------------------------------------------------------------------------- * Function: H5Oget_comment_by_name * - * Purpose: Retrieve comment for an object. + * Purpose: Retrieve comment for an object. * - * Return: Success: Number of bytes in the comment excluding the - * null terminator. Zero if the object has no - * comment. + * Return: Success: Number of bytes in the comment excluding the + * null terminator. Zero if the object has no + * comment. * - * Failure: Negative + * Failure: -1 * - * Programmer: Quincey Koziol - * August 30 2007 + * Programmer: Quincey Koziol + * August 30 2007 * *------------------------------------------------------------------------- */ @@ -732,34 +733,34 @@ H5Oget_comment_by_name(hid_t loc_id, const char *name, char *comment, size_t buf hid_t lapl_id) { H5G_loc_t loc; /* Location of group */ - ssize_t ret_value; /* Return value */ + ssize_t ret_value = -1; /* Return value */ - FUNC_ENTER_API(FAIL) + FUNC_ENTER_API((-1)) H5TRACE5("Zs", "i*s*szi", loc_id, name, comment, bufsize, lapl_id); /* Check args */ if(H5G_loc(loc_id, &loc) < 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a location") + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, (-1), "not a location") if(!name || !*name) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name") + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, (-1), "no name") /* Verify access property list and set up collective metadata if appropriate */ if(H5CX_set_apl(&lapl_id, H5P_CLS_LACC, loc_id, FALSE) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access property list info") + HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, (-1), "can't set access property list info") /* Retrieve the object's comment */ if((ret_value = H5G_loc_get_comment(&loc, name, comment/*out*/, bufsize)) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, FAIL, "can't get comment for object: '%s'", name) + HGOTO_ERROR(H5E_OHDR, H5E_CANTGET, (-1), "can't get comment for object: '%s'", name) done: FUNC_LEAVE_API(ret_value) } /* end H5Oget_comment_by_name() */ - + /*------------------------------------------------------------------------- * Function: H5Ovisit2 * - * Purpose: Recursively visit an object and all the objects reachable + * Purpose: Recursively visit an object and all the objects reachable * from it. If the starting object is a group, all the objects * linked to from that group will be visited. Links within * each group are visited according to the order within the @@ -779,14 +780,14 @@ done: * object info to be retrieved to the callback "op". * * Return: Success: The return value of the first operator that - * returns non-zero, or zero if all members were - * processed with no operator returning non-zero. + * returns non-zero, or zero if all members were + * processed with no operator returning non-zero. * * Failure: Negative if something goes wrong within the - * library, or the negative value returned by one - * of the operators. + * library, or the negative value returned by one + * of the operators. * - * Programmer: Quincey Koziol + * Programmer: Quincey Koziol * November 25 2007 * *------------------------------------------------------------------------- @@ -795,7 +796,7 @@ herr_t H5Ovisit2(hid_t obj_id, H5_index_t idx_type, H5_iter_order_t order, H5O_iterate_t op, void *op_data, unsigned fields) { - herr_t ret_value; /* Return value */ + herr_t ret_value; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE6("e", "iIiIox*xIu", obj_id, idx_type, order, op, op_data, fields); @@ -810,15 +811,15 @@ H5Ovisit2(hid_t obj_id, H5_index_t idx_type, H5_iter_order_t order, if(fields & ~H5O_INFO_ALL) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid fields") - /* Call internal object visitation routine */ + /* Visit the objects */ if((ret_value = H5O__visit(obj_id, ".", idx_type, order, op, op_data, fields)) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "object visitation failed") + HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "object iteration failed") done: FUNC_LEAVE_API(ret_value) } /* end H5Ovisit2() */ - + /*------------------------------------------------------------------------- * Function: H5Ovisit_by_name2 * @@ -842,14 +843,14 @@ done: * object info to be retrieved to the callback "op". * * Return: Success: The return value of the first operator that - * returns non-zero, or zero if all members were - * processed with no operator returning non-zero. + * returns non-zero, or zero if all members were + * processed with no operator returning non-zero. * - * Failure: Negative if something goes wrong within the - * library, or the negative value returned by one - * of the operators. + * Failure: Negative if something goes wrong within the + * library, or the negative value returned by one + * of the operators. * - * Programmer: Quincey Koziol + * Programmer: Quincey Koziol * November 24 2007 * *------------------------------------------------------------------------- @@ -858,15 +859,17 @@ herr_t H5Ovisit_by_name2(hid_t loc_id, const char *obj_name, H5_index_t idx_type, H5_iter_order_t order, H5O_iterate_t op, void *op_data, unsigned fields, hid_t lapl_id) { - herr_t ret_value; /* Return value */ + herr_t ret_value; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE8("e", "i*sIiIox*xIui", loc_id, obj_name, idx_type, order, op, op_data, fields, lapl_id); /* Check args */ - if(!obj_name || !*obj_name) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "no name") + if(!obj_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "obj_name parameter cannot be NULL") + if(!*obj_name) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "obj_name parameter cannot be an empty string") if(idx_type <= H5_INDEX_UNKNOWN || idx_type >= H5_INDEX_N) HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid index type specified") if(order <= H5_ITER_UNKNOWN || order >= H5_ITER_N) @@ -880,30 +883,30 @@ H5Ovisit_by_name2(hid_t loc_id, const char *obj_name, H5_index_t idx_type, if(H5CX_set_apl(&lapl_id, H5P_CLS_LACC, loc_id, FALSE) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access property list info") - /* Call internal object visitation routine */ + /* Visit the objects */ if((ret_value = H5O__visit(loc_id, obj_name, idx_type, order, op, op_data, fields)) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "object visitation failed") + HGOTO_ERROR(H5E_OHDR, H5E_BADITER, FAIL, "object iteration failed") done: FUNC_LEAVE_API(ret_value) } /* end H5Ovisit_by_name2() */ - + /*------------------------------------------------------------------------- * Function: H5Oclose * - * Purpose: Close an open file object. + * Purpose: Close an open file object. * * This is the companion to H5Oopen. It is used to close any * open object in an HDF5 file (but not IDs are that not file * objects, such as property lists and dataspaces). It has * the same effect as calling H5Gclose, H5Dclose, or H5Tclose. * - * Return: Success: Non-negative - * Failure: Negative + * Return: Success: Non-negative + * Failure: Negative * - * Programmer: James Laird - * July 14 2006 + * Programmer: James Laird + * July 14 2006 * *------------------------------------------------------------------------- */ @@ -938,6 +941,7 @@ H5Oclose(hid_t object_id) case H5I_ERROR_CLASS: case H5I_ERROR_MSG: case H5I_ERROR_STACK: + case H5I_SPACE_SEL_ITER: case H5I_NTYPES: default: HGOTO_ERROR(H5E_ARGS, H5E_CANTRELEASE, FAIL, "not a valid file object ID (dataset, group, or datatype)") @@ -948,18 +952,18 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Oclose() */ - + /*------------------------------------------------------------------------- * Function: H5Odisable_mdc_flushes * - * Purpose: To "cork" an object: - * --keep dirty entries associated with the object in the metadata cache + * Purpose: "Cork" an object, keeping dirty entries associated with the + * object in the metadata cache. * - * Return: Success: Non-negative - * Failure: Negative + * Return: Success: Non-negative + * Failure: Negative * - * Programmer: Vailin Choi - * January 2014 + * Programmer: Vailin Choi + * January 2014 * *------------------------------------------------------------------------- */ @@ -967,7 +971,7 @@ herr_t H5Odisable_mdc_flushes(hid_t object_id) { H5O_loc_t *oloc; /* Object location */ - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE1("e", "i", object_id); @@ -976,26 +980,26 @@ H5Odisable_mdc_flushes(hid_t object_id) if(NULL == (oloc = H5O_get_loc(object_id))) HGOTO_ERROR(H5E_OHDR, H5E_BADVALUE, FAIL, "unable to get object location from ID") + /* Cork the object */ if(H5AC_cork(oloc->file, oloc->addr, H5AC__SET_CORK, NULL) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTCORK, FAIL, "unable to cork an object") + HGOTO_ERROR(H5E_OHDR, H5E_CANTCORK, FAIL, "unable to cork object") done: FUNC_LEAVE_API(ret_value) } /* H5Odisable_mdc_flushes() */ - + /*------------------------------------------------------------------------- * Function: H5Oenable_mdc_flushes * - * Purpose: To "uncork" an object - * --release keeping dirty entries associated with the object - * in the metadata cache + * Purpose: "Uncork" an object, allowing dirty entries associated with + * the object to be flushed. * - * Return: Success: Non-negative - * Failure: Negative + * Return: Success: Non-negative + * Failure: Negative * - * Programmer: Vailin Choi - * January 2014 + * Programmer: Vailin Choi + * January 2014 * *------------------------------------------------------------------------- */ @@ -1020,20 +1024,20 @@ done: FUNC_LEAVE_API(ret_value) } /* H5Oenable_mdc_flushes() */ - + /*------------------------------------------------------------------------- * Function: H5Oare_mdc_flushes_disabled * - * Purpose: Retrieve the object's "cork" status in the parameter "are_disabled": - * TRUE if mdc flushes for the object is disabled - * FALSE if mdc flushes for the object is not disabled - * Return error if the parameter "are_disabled" is not supplied + * Purpose: Retrieve the object's "cork" status in the parameter "are_disabled": + * TRUE if mdc flushes for the object is disabled + * FALSE if mdc flushes for the object is not disabled + * Return error if the parameter "are_disabled" is not supplied * - * Return: Success: Non-negative - * Failure: Negative + * Return: Success: Non-negative + * Failure: Negative * - * Programmer: Vailin Choi - * January 2014 + * Programmer: Vailin Choi + * January 2014 * *------------------------------------------------------------------------- */ @@ -1067,6 +1071,7 @@ done: #ifndef H5_NO_DEPRECATED_SYMBOLS */ + /*------------------------------------------------------------------------- * Function: H5Oget_info * @@ -1100,7 +1105,7 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Oget_info() */ - + /*------------------------------------------------------------------------- * Function: H5Oget_info_by_name * @@ -1140,7 +1145,7 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Oget_info_by_name() */ - + /*------------------------------------------------------------------------- * Function: H5Oget_info_by_idx * @@ -1198,7 +1203,7 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Oget_info_by_idx() */ - + /*------------------------------------------------------------------------- * Function: H5Ovisit * @@ -1256,7 +1261,7 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Ovisit() */ - + /*------------------------------------------------------------------------- * Function: H5Ovisit_by_name * @@ -1277,14 +1282,14 @@ done: * the callback about the object. * * Return: Success: The return value of the first operator that - * returns non-zero, or zero if all members were - * processed with no operator returning non-zero. + * returns non-zero, or zero if all members were + * processed with no operator returning non-zero. * * Failure: Negative if something goes wrong within the - * library, or the negative value returned by one - * of the operators. + * library, or the negative value returned by one + * of the operators. * - * Programmer: Quincey Koziol + * Programmer: Quincey Koziol * November 24 2007 * *------------------------------------------------------------------------- diff --git a/src/H5Oflush.c b/src/H5Oflush.c index eeb3040..a7e2fd8 100644 --- a/src/H5Oflush.c +++ b/src/H5Oflush.c @@ -58,11 +58,11 @@ static herr_t H5O__refresh_metadata_close(hid_t oid, H5O_loc_t oloc, /*------------------------------------------------------------------------- - * Function: H5Oflush + * Function: H5Oflush * - * Purpose: Flushes all buffers associated with an object to disk. + * Purpose: Flushes all buffers associated with an object to disk. * - * Return: Non-negative on success, negative on failure + * Return: Non-negative on success, negative on failure * * Programmer: Mike McGreevy * May 19, 2010 @@ -72,7 +72,7 @@ static herr_t H5O__refresh_metadata_close(hid_t oid, H5O_loc_t oloc, herr_t H5Oflush(hid_t obj_id) { - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_API(FAIL) H5TRACE1("e", "i", obj_id); @@ -81,7 +81,7 @@ H5Oflush(hid_t obj_id) if(H5CX_set_loc(obj_id) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access property list info") - /* Call internal routine */ + /* Flush the object */ if(H5O__flush(obj_id) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTFLUSH, FAIL, "unable to flush object") @@ -245,7 +245,7 @@ H5Orefresh(hid_t oid) if(H5CX_set_loc(oid) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTSET, FAIL, "can't set access property list info") - /* Call internal routine */ + /* Refresh the object */ if(H5O_refresh_metadata(oid, *oloc) < 0) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, FAIL, "unable to refresh object") @@ -450,6 +450,7 @@ H5O_refresh_metadata_reopen(hid_t oid, H5G_loc_t *obj_loc, hbool_t start_swmr) case H5I_ERROR_CLASS: case H5I_ERROR_MSG: case H5I_ERROR_STACK: + case H5I_SPACE_SEL_ITER: case H5I_NTYPES: default: HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, FAIL, "not a valid file object ID (dataset, group, or datatype)") @@ -458,7 +459,7 @@ H5O_refresh_metadata_reopen(hid_t oid, H5G_loc_t *obj_loc, hbool_t start_swmr) /* Re-register ID for the object */ if((H5I_register_using_existing_id(type, object, TRUE, oid)) < 0) - HGOTO_ERROR(H5E_OHDR, H5E_CANTREGISTER, FAIL, "unable to re-register object atom") + HGOTO_ERROR(H5E_OHDR, H5E_CANTREGISTER, FAIL, "unable to re-register object ID after refresh") done: FUNC_LEAVE_NOAPI(ret_value); diff --git a/src/H5Oint.c b/src/H5Oint.c index ed4ef19..dd86fa9 100644 --- a/src/H5Oint.c +++ b/src/H5Oint.c @@ -270,7 +270,6 @@ done: * Failure: Negative * * Programmer: Robb Matzke - * matzke@llnl.gov * Aug 5 1997 * *------------------------------------------------------------------------- @@ -703,8 +702,8 @@ done: * * Purpose: Internal routine to open an object by its address * - * Return: Success: Non-negative - * Failure: Negative + * Return: Success: Valid object identifier + * Failure: H5I_INVALID_HID * * Programmer: Quincey Koziol * December 28, 2017 @@ -1854,6 +1853,7 @@ H5O_get_loc(hid_t object_id) case H5I_ERROR_CLASS: case H5I_ERROR_MSG: case H5I_ERROR_STACK: + case H5I_SPACE_SEL_ITER: case H5I_NTYPES: default: HGOTO_ERROR(H5E_OHDR, H5E_BADTYPE, NULL, "invalid object type") @@ -1892,7 +1892,7 @@ H5O_loc_reset(H5O_loc_t *loc) FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O_loc_reset() */ - + /*------------------------------------------------------------------------- * Function: H5O_loc_copy * @@ -1925,7 +1925,7 @@ H5O_loc_copy(H5O_loc_t *dst, H5O_loc_t *src, H5_copy_depth_t depth) FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O_loc_copy() */ - + /*------------------------------------------------------------------------- * Function: H5O_loc_copy_shallow * @@ -1960,7 +1960,7 @@ H5O_loc_copy_shallow(H5O_loc_t *dst, H5O_loc_t *src) FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O_loc_copy_shallow() */ - + /*------------------------------------------------------------------------- * Function: H5O_loc_copy_deep * @@ -1997,7 +1997,7 @@ H5O_loc_copy_deep(H5O_loc_t *dst, const H5O_loc_t *src) FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5O_loc_copy_deep() */ - + /*------------------------------------------------------------------------- * Function: H5O_loc_hold_file * diff --git a/src/H5Sall.c b/src/H5Sall.c index a6ebc8f..9026e7c 100644 --- a/src/H5Sall.c +++ b/src/H5Sall.c @@ -51,9 +51,6 @@ /* Selection callbacks */ static herr_t H5S__all_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection); -static herr_t H5S__all_get_seq_list(const H5S_t *space, unsigned flags, - H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes, - size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); static herr_t H5S__all_release(H5S_t *space); static htri_t H5S__all_is_valid(const H5S_t *space); static hssize_t H5S__all_serial_size(const H5S_t *space); @@ -65,7 +62,11 @@ static int H5S__all_unlim_dim(const H5S_t *space); static htri_t H5S__all_is_contiguous(const H5S_t *space); static htri_t H5S__all_is_single(const H5S_t *space); static htri_t H5S__all_is_regular(const H5S_t *space); +static htri_t H5S__all_shape_same(const H5S_t *space1, const H5S_t *space2); +static htri_t H5S__all_intersect_block(const H5S_t *space, const hsize_t *start, + const hsize_t *end); static herr_t H5S__all_adjust_u(H5S_t *space, const hsize_t *offset); +static herr_t H5S__all_adjust_s(H5S_t *space, const hssize_t *offset); static herr_t H5S__all_project_scalar(const H5S_t *space, hsize_t *offset); static herr_t H5S__all_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset); static herr_t H5S__all_iter_init(const H5S_t *space, H5S_sel_iter_t *iter); @@ -77,6 +78,8 @@ static hsize_t H5S__all_iter_nelmts(const H5S_sel_iter_t *iter); static htri_t H5S__all_iter_has_next_block(const H5S_sel_iter_t *iter); static herr_t H5S__all_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem); static herr_t H5S__all_iter_next_block(H5S_sel_iter_t *sel_iter); +static herr_t H5S__all_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq, + size_t maxbytes, size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); static herr_t H5S__all_iter_release(H5S_sel_iter_t *sel_iter); @@ -95,7 +98,6 @@ const H5S_select_class_t H5S_sel_all[1] = {{ /* Methods on selection */ H5S__all_copy, - H5S__all_get_seq_list, H5S__all_release, H5S__all_is_valid, H5S__all_serial_size, @@ -108,7 +110,10 @@ const H5S_select_class_t H5S_sel_all[1] = {{ H5S__all_is_contiguous, H5S__all_is_single, H5S__all_is_regular, + H5S__all_shape_same, + H5S__all_intersect_block, H5S__all_adjust_u, + H5S__all_adjust_s, H5S__all_project_scalar, H5S__all_project_simple, H5S__all_iter_init, @@ -130,6 +135,7 @@ static const H5S_sel_iter_class_t H5S_sel_iter_all[1] = {{ H5S__all_iter_has_next_block, H5S__all_iter_next, H5S__all_iter_next_block, + H5S__all_iter_get_seq_list, H5S__all_iter_release, }}; @@ -148,7 +154,7 @@ static const H5S_sel_iter_class_t H5S_sel_iter_all[1] = {{ *------------------------------------------------------------------------- */ static herr_t -H5S__all_iter_init(const H5S_t *space, H5S_sel_iter_t *iter) +H5S__all_iter_init(const H5S_t H5_ATTR_UNUSED *space, H5S_sel_iter_t *iter) { FUNC_ENTER_STATIC_NOERR @@ -156,9 +162,6 @@ H5S__all_iter_init(const H5S_t *space, H5S_sel_iter_t *iter) HDassert(space && H5S_SEL_ALL == H5S_GET_SELECT_TYPE(space)); HDassert(iter); - /* Initialize the number of elements to iterate over */ - iter->elmt_left = H5S_GET_SELECT_NPOINTS(space); - /* Start at the upper left location */ iter->u.all.elmt_offset = 0; iter->u.all.byte_offset = 0; @@ -361,6 +364,76 @@ H5S__all_iter_next_block(H5S_sel_iter_t H5_ATTR_UNUSED *iter) /*-------------------------------------------------------------------------- NAME + H5S__all_iter_get_seq_list + PURPOSE + Create a list of offsets & lengths for a selection + USAGE + herr_t H5S__all_iter_get_seq_list(iter,maxseq,maxelem,nseq,nelem,off,len) + H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last + position of interest in selection. + size_t maxseq; IN: Maximum number of sequences to generate + size_t maxelem; IN: Maximum number of elements to include in the + generated sequences + size_t *nseq; OUT: Actual number of sequences generated + size_t *nelem; OUT: Actual number of elements in sequences generated + hsize_t *off; OUT: Array of offsets + size_t *len; OUT: Array of lengths + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + Use the selection in the dataspace to generate a list of byte offsets and + lengths for the region(s) selected. Start/Restart from the position in the + ITER parameter. The number of sequences generated is limited by the MAXSEQ + parameter and the number of sequences actually generated is stored in the + NSEQ parameter. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__all_iter_get_seq_list(H5S_sel_iter_t *iter, size_t H5_ATTR_UNUSED maxseq, + size_t maxelem, size_t *nseq, size_t *nelem, hsize_t *off, size_t *len) +{ + size_t elem_used; /* The number of elements used */ + + FUNC_ENTER_STATIC_NOERR + + /* Check args */ + HDassert(iter); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); + + /* Determine the actual number of elements to use */ + H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t); + elem_used = MIN(maxelem, (size_t)iter->elmt_left); + HDassert(elem_used > 0); + + /* Compute the offset in the dataset */ + off[0] = iter->u.all.byte_offset; + len[0] = elem_used * iter->elmt_size; + + /* Should only need one sequence for 'all' selections */ + *nseq = 1; + + /* Set the number of elements used */ + *nelem = elem_used; + + /* Update the iterator */ + iter->elmt_left -= elem_used; + iter->u.all.elmt_offset += elem_used; + iter->u.all.byte_offset += len[0]; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__all_iter_get_seq_list() */ + + +/*-------------------------------------------------------------------------- + NAME H5S__all_iter_release PURPOSE Release "all" selection iterator information for a dataspace @@ -847,6 +920,105 @@ H5S__all_is_regular(const H5S_t H5_ATTR_UNUSED *space) /*-------------------------------------------------------------------------- NAME + H5S__all_shape_same + PURPOSE + Check if a two "all" selections are the same shape + USAGE + htri_t H5S__all_shape_same(space1, space2) + const H5S_t *space1; IN: First dataspace to check + const H5S_t *space2; IN: Second dataspace to check + RETURNS + TRUE / FALSE / FAIL + DESCRIPTION + Checks to see if the current selection in each dataspace are the same + shape. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static htri_t +H5S__all_shape_same(const H5S_t *space1, const H5S_t *space2) +{ + int space1_dim; /* Current dimension in first dataspace */ + int space2_dim; /* Current dimension in second dataspace */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check args */ + HDassert(space1); + HDassert(space2); + + /* Initialize dataspace dims */ + space1_dim = (int)space1->extent.rank - 1; + space2_dim = (int)space2->extent.rank - 1; + + /* Recall that space1_rank >= space2_rank. + * + * In the following while loop, we test to see if space1 and space2 + * have identical size in all dimensions they have in common. + */ + while(space2_dim >= 0) { + if(space1->extent.size[space1_dim] != space2->extent.size[space2_dim]) + HGOTO_DONE(FALSE) + + space1_dim--; + space2_dim--; + } /* end while */ + + /* Since we are selecting the entire space, we must also verify that space1 + * has size 1 in all dimensions that it does not share with space2. + */ + while(space1_dim >= 0) { + if(space1->extent.size[space1_dim] != 1) + HGOTO_DONE(FALSE) + + space1_dim--; + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__all_shape_same() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__all_intersect_block + PURPOSE + Detect intersections of selection with block + USAGE + htri_t H5S__all_intersect_block(space, start, end) + const H5S_t *space; IN: Dataspace with selection to use + const hsize_t *start; IN: Starting coordinate for block + const hsize_t *end; IN: Ending coordinate for block + RETURNS + Non-negative TRUE / FALSE on success, negative on failure + DESCRIPTION + Quickly detect intersections with a block + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5S__all_intersect_block(const H5S_t H5_ATTR_UNUSED *space, + const hsize_t H5_ATTR_UNUSED *start, const hsize_t H5_ATTR_UNUSED *end) +{ + FUNC_ENTER_STATIC_NOERR + + /* Sanity check */ + HDassert(space); + HDassert(H5S_SEL_ALL == H5S_GET_SELECT_TYPE(space)); + HDassert(start); + HDassert(end); + + FUNC_LEAVE_NOAPI(TRUE) +} /* end H5S__all_intersect_block() */ + + +/*-------------------------------------------------------------------------- + NAME H5S__all_adjust_u PURPOSE Adjust an "all" selection by subtracting an offset @@ -876,6 +1048,37 @@ H5S__all_adjust_u(H5S_t H5_ATTR_UNUSED *space, const hsize_t H5_ATTR_UNUSED *off } /* end H5S__all_adjust_u() */ +/*-------------------------------------------------------------------------- + NAME + H5S__all_adjust_s + PURPOSE + Adjust an "all" selection by subtracting an offset + USAGE + herr_t H5S__all_adjust_u(space, offset) + H5S_t *space; IN/OUT: Pointer to dataspace to adjust + const hssize_t *offset; IN: Offset to subtract + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Moves selection by subtracting an offset from it. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__all_adjust_s(H5S_t H5_ATTR_UNUSED *space, const hssize_t H5_ATTR_UNUSED *offset) +{ + FUNC_ENTER_STATIC_NOERR + + /* Check args */ + HDassert(space); + HDassert(offset); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__all_adjust_s() */ + + /*------------------------------------------------------------------------- * Function: H5S__all_project_scalar * @@ -1022,77 +1225,3 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Sselect_all() */ - -/*-------------------------------------------------------------------------- - NAME - H5S__all_get_seq_list - PURPOSE - Create a list of offsets & lengths for a selection - USAGE - herr_t H5S__all_get_seq_list(space,flags,iter,maxseq,maxelem,nseq,nelem,off,len) - H5S_t *space; IN: Dataspace containing selection to use. - unsigned flags; IN: Flags for extra information about operation - H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last - position of interest in selection. - size_t maxseq; IN: Maximum number of sequences to generate - size_t maxelem; IN: Maximum number of elements to include in the - generated sequences - size_t *nseq; OUT: Actual number of sequences generated - size_t *nelem; OUT: Actual number of elements in sequences generated - hsize_t *off; OUT: Array of offsets - size_t *len; OUT: Array of lengths - RETURNS - Non-negative on success/Negative on failure. - DESCRIPTION - Use the selection in the dataspace to generate a list of byte offsets and - lengths for the region(s) selected. Start/Restart from the position in the - ITER parameter. The number of sequences generated is limited by the MAXSEQ - parameter and the number of sequences actually generated is stored in the - NSEQ parameter. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5S__all_get_seq_list(const H5S_t H5_ATTR_UNUSED *space, unsigned H5_ATTR_UNUSED flags, H5S_sel_iter_t *iter, - size_t H5_ATTR_UNUSED maxseq, size_t maxelem, size_t *nseq, size_t *nelem, - hsize_t *off, size_t *len) -{ - size_t elem_used; /* The number of elements used */ - - FUNC_ENTER_STATIC_NOERR - - /* Check args */ - HDassert(space); - HDassert(iter); - HDassert(maxseq > 0); - HDassert(maxelem > 0); - HDassert(nseq); - HDassert(nelem); - HDassert(off); - HDassert(len); - - /* Determine the actual number of elements to use */ - H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t); - elem_used = MIN(maxelem, (size_t)iter->elmt_left); - HDassert(elem_used > 0); - - /* Compute the offset in the dataset */ - off[0] = iter->u.all.byte_offset; - len[0] = elem_used * iter->elmt_size; - - /* Should only need one sequence for 'all' selections */ - *nseq = 1; - - /* Set the number of elements used */ - *nelem = elem_used; - - /* Update the iterator */ - iter->elmt_left -= elem_used; - iter->u.all.elmt_offset += elem_used; - iter->u.all.byte_offset += len[0]; - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__all_get_seq_list() */ - diff --git a/src/H5Shyper.c b/src/H5Shyper.c index af9e3bc..42b9acd 100644 --- a/src/H5Shyper.c +++ b/src/H5Shyper.c @@ -12,7 +12,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* - * Programmer: Quincey Koziol + * Programmer: Quincey Koziol * Thursday, June 18, 1998 * * Purpose: Hyperslab selection dataspace I/O functions. @@ -37,56 +37,138 @@ #include "H5Spkg.h" /* Dataspace functions */ #include "H5VMprivate.h" /* Vector functions */ -/* Format version bounds for dataspace hyperslab selection */ -const unsigned H5O_sds_hyper_ver_bounds[] = { - H5S_HYPER_VERSION_1, /* H5F_LIBVER_EARLIEST */ - H5S_HYPER_VERSION_1, /* H5F_LIBVER_V18 */ - H5S_HYPER_VERSION_2 /* H5F_LIBVER_LATEST */ -}; /****************/ /* Local Macros */ /****************/ +/* Flags for which hyperslab fragments to compute */ +#define H5S_HYPER_COMPUTE_B_NOT_A 0x01 +#define H5S_HYPER_COMPUTE_A_AND_B 0x02 +#define H5S_HYPER_COMPUTE_A_NOT_B 0x04 + +/* Macro to advance a span, possibly recycling it first */ +#define H5S_HYPER_ADVANCE_SPAN(recover, curr_span, next_span) \ + do { \ + H5S_hyper_span_t *saved_next_span = (next_span); \ + \ + /* Check if the span should be recovered */ \ + if(recover) { \ + H5S__hyper_free_span(curr_span); \ + (recover) = FALSE; \ + } /* end if */ \ + \ + /* Set the current span to saved next span */ \ + (curr_span) = saved_next_span; \ + } while(0) + +/* Macro to add "skipped" elements to projection during the execution of + * H5S__hyper_project_intersect() */ +#define H5S_HYPER_PROJ_INT_ADD_SKIP(UDATA, ADD, ERR) \ + do { \ + /* If there are any elements to add, we must add them \ + * to the projection first before adding skip */ \ + if((UDATA)->nelem > 0) \ + if(H5S__hyper_proj_int_build_proj(UDATA) < 0) \ + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, ERR, "can't add elements to projected selection") \ + (UDATA)->skip += (ADD); \ + } while(0) /* end H5S_HYPER_PROJ_INT_ADD_SKIP() */ + /******************/ /* Local Typedefs */ /******************/ +/* Define alias for hsize_t, for allocating H5S_hyper_span_info_t + bounds objects */ +/* (Makes it easier to understand the alloc / free calls) */ +typedef hsize_t hbounds_t; + +/* Struct for holding persistent information during iteration for + * H5S__hyper_project_intersect() */ +typedef struct { + const H5S_hyper_span_t *ds_span[H5S_MAX_RANK]; /* Array of the current spans in the destination space in each dimension */ + hsize_t ds_low[H5S_MAX_RANK]; /* Array of current low bounds (of iteration) for each element in ds_span */ + H5S_hyper_span_info_t *ps_span_info[H5S_MAX_RANK]; /* Array of span info structs for projected space during iteration */ + uint32_t ps_clean_bitmap; /* Bitmap of whether the nth rank has a clean projected space since the last time it was set to 1 */ + unsigned ss_rank; /* Rank of source space */ + unsigned ds_rank; /* Rank of destination space */ + unsigned depth; /* Current depth of iterator in destination space */ + hsize_t skip; /* Number of elements to skip in projected space */ + hsize_t nelem; /* Number of elements to add to projected space (after skip) */ + uint64_t op_gen; /* Operation generation for counting elements */ + hbool_t share_selection; /* Whether span trees in dst_space can be shared with proj_space */ +} H5S_hyper_project_intersect_ud_t; + +/* Assert that H5S_MAX_RANK is <= 32 so our trick with using a 32 bit bitmap + * (ps_clean_bitmap) works. If H5S_MAX_RANK increases either increase the size + * of ps_clean_bitmap or change the algorithm to use an array. */ +#if H5S_MAX_RANK > 32 +#error H5S_MAX_RANK too large for ps_clean_bitmap field in H5S_hyper_project_intersect_ud_t struct +#endif + + /********************/ /* Local Prototypes */ /********************/ static H5S_hyper_span_t *H5S__hyper_new_span(hsize_t low, hsize_t high, H5S_hyper_span_info_t *down, H5S_hyper_span_t *next); -static herr_t H5S__hyper_span_precompute(H5S_hyper_span_info_t *spans, size_t elmt_size); -static void H5S__hyper_span_scratch(H5S_hyper_span_info_t *spans); -static H5S_hyper_span_info_t *H5S__hyper_copy_span(H5S_hyper_span_info_t *spans); +static H5S_hyper_span_info_t *H5S__hyper_new_span_info(unsigned rank); +static H5S_hyper_span_info_t *H5S__hyper_copy_span_helper( + H5S_hyper_span_info_t *spans, unsigned rank, unsigned op_info_i, + uint64_t op_gen); +static H5S_hyper_span_info_t *H5S__hyper_copy_span(H5S_hyper_span_info_t *spans, + unsigned rank); static hbool_t H5S__hyper_cmp_spans(const H5S_hyper_span_info_t *span_info1, const H5S_hyper_span_info_t *span_info2); -static herr_t H5S__hyper_free_span_info(H5S_hyper_span_info_t *span_info); -static herr_t H5S__hyper_free_span(H5S_hyper_span_t *span); -static hbool_t H5S__hyper_is_valid_helper(const H5S_hyper_span_info_t *spans, - const hssize_t *offset, const hsize_t *size); -static herr_t H5S__hyper_recover_span(hbool_t *recover, - H5S_hyper_span_t **curr_span, H5S_hyper_span_t *next_span); -static H5S_hyper_span_t *H5S__hyper_coord_to_span(unsigned rank, - const hsize_t *coords); -static herr_t H5S__hyper_append_span(H5S_hyper_span_t **prev_span, - H5S_hyper_span_info_t **span_tree, hsize_t low, hsize_t high, - H5S_hyper_span_info_t *down, H5S_hyper_span_t *next); +static void H5S__hyper_free_span_info(H5S_hyper_span_info_t *span_info); +static void H5S__hyper_free_span(H5S_hyper_span_t *span); +static herr_t H5S__hyper_span_blocklist(const H5S_hyper_span_info_t *spans, + hsize_t start[], hsize_t end[], hsize_t rank, hsize_t *startblock, hsize_t *numblocks, + hsize_t **buf); +static herr_t H5S__get_select_hyper_blocklist(H5S_t *space, hsize_t startblock, + hsize_t numblocks, hsize_t *buf); +static H5S_hyper_span_t *H5S__hyper_coord_to_span(unsigned rank, const hsize_t *coords); +static herr_t H5S__hyper_append_span(H5S_hyper_span_info_t **span_tree, + unsigned ndims, hsize_t low, hsize_t high, H5S_hyper_span_info_t *down); static herr_t H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, - H5S_hyper_span_info_t *b_spans, H5S_hyper_span_info_t **a_not_b, + H5S_hyper_span_info_t *b_spans, unsigned selector, + unsigned ndims, H5S_hyper_span_info_t **a_not_b, H5S_hyper_span_info_t **a_and_b, H5S_hyper_span_info_t **b_not_a); -static herr_t H5S__hyper_merge_spans(H5S_t *space, - H5S_hyper_span_info_t *new_spans, hbool_t can_own); -static hsize_t H5S__hyper_spans_nelem(const H5S_hyper_span_info_t *spans); +static herr_t H5S__hyper_merge_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans); +static hsize_t H5S__hyper_spans_nelem_helper(H5S_hyper_span_info_t *spans, + unsigned op_info_i, uint64_t op_gen); +static hsize_t H5S__hyper_spans_nelem(H5S_hyper_span_info_t *spans); +static herr_t H5S__hyper_add_disjoint_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans); static H5S_hyper_span_info_t *H5S__hyper_make_spans(unsigned rank, - const hsize_t *start, const hsize_t *stride, const hsize_t *count, - const hsize_t *block); + const hsize_t *start, const hsize_t *stride, + const hsize_t *count, const hsize_t *block); +static herr_t H5S__hyper_update_diminfo(H5S_t *space, H5S_seloper_t op, + const H5S_hyper_dim_t *new_hyper_diminfo); static herr_t H5S__hyper_generate_spans(H5S_t *space); +static hbool_t H5S__check_spans_overlap(const H5S_hyper_span_info_t *spans1, + const H5S_hyper_span_info_t *spans2); +static herr_t H5S__fill_in_new_space(H5S_t *space1, H5S_seloper_t op, + H5S_hyper_span_info_t *space2_span_lst, hbool_t can_own_span2, + hbool_t *span2_owned, hbool_t *updated_spans, H5S_t **result); static herr_t H5S__generate_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[], const hsize_t stride[], const hsize_t count[], const hsize_t block[]); +static herr_t H5S__set_regular_hyperslab(H5S_t *space, const hsize_t start[], + const hsize_t *app_stride, const hsize_t app_count[], const hsize_t *app_block, + const hsize_t *opt_stride, const hsize_t opt_count[], const hsize_t *opt_block); +static herr_t H5S__fill_in_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2, + H5S_t **result); +static H5S_t *H5S__combine_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2); +static herr_t H5S__hyper_iter_get_seq_list_gen(H5S_sel_iter_t *iter, size_t maxseq, + size_t maxelem, size_t *nseq, size_t *nelem, hsize_t *off, size_t *len); +static herr_t H5S__hyper_iter_get_seq_list_opt(H5S_sel_iter_t *iter, size_t maxseq, + size_t maxelem, size_t *nseq, size_t *nelem, hsize_t *off, size_t *len); +static herr_t H5S__hyper_iter_get_seq_list_single(H5S_sel_iter_t *iter, size_t maxseq, + size_t maxelem, size_t *nseq, size_t *nelem, hsize_t *off, size_t *len); +static herr_t H5S__hyper_proj_int_build_proj(H5S_hyper_project_intersect_ud_t *udata); +static herr_t H5S__hyper_proj_int_iterate(const H5S_hyper_span_info_t *ss_span_info, + const H5S_hyper_span_info_t *sis_span_info, hsize_t count, unsigned depth, + H5S_hyper_project_intersect_ud_t *udata); static void H5S__hyper_get_clip_diminfo(hsize_t start, hsize_t stride, hsize_t *count, hsize_t *block, hsize_t clip_size); static hsize_t H5S__hyper_get_clip_extent_real(const H5S_t *clip_space, @@ -94,11 +176,9 @@ static hsize_t H5S__hyper_get_clip_extent_real(const H5S_t *clip_space, /* Selection callbacks */ static herr_t H5S__hyper_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection); -static herr_t H5S__hyper_get_seq_list(const H5S_t *space, unsigned flags, - H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes, - size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); static herr_t H5S__hyper_release(H5S_t *space); static htri_t H5S__hyper_is_valid(const H5S_t *space); +static hsize_t H5S__hyper_span_nblocks(H5S_hyper_span_info_t *spans); static hssize_t H5S__hyper_serial_size(const H5S_t *space); static herr_t H5S__hyper_serialize(const H5S_t *space, uint8_t **p); static herr_t H5S__hyper_deserialize(H5S_t **space, const uint8_t **p); @@ -110,7 +190,11 @@ static herr_t H5S__hyper_num_elem_non_unlim(const H5S_t *space, static htri_t H5S__hyper_is_contiguous(const H5S_t *space); static htri_t H5S__hyper_is_single(const H5S_t *space); static htri_t H5S__hyper_is_regular(const H5S_t *space); +static htri_t H5S__hyper_shape_same(const H5S_t *space1, const H5S_t *space2); +static htri_t H5S__hyper_intersect_block(const H5S_t *space, const hsize_t *start, + const hsize_t *end); static herr_t H5S__hyper_adjust_u(H5S_t *space, const hsize_t *offset); +static herr_t H5S__hyper_adjust_s(H5S_t *space, const hssize_t *offset); static herr_t H5S__hyper_project_scalar(const H5S_t *space, hsize_t *offset); static herr_t H5S__hyper_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset); static herr_t H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter); @@ -122,11 +206,9 @@ static hsize_t H5S__hyper_iter_nelmts(const H5S_sel_iter_t *iter); static htri_t H5S__hyper_iter_has_next_block(const H5S_sel_iter_t *sel_iter); static herr_t H5S__hyper_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem); static herr_t H5S__hyper_iter_next_block(H5S_sel_iter_t *sel_iter); +static herr_t H5S__hyper_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq, + size_t maxbytes, size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); static herr_t H5S__hyper_iter_release(H5S_sel_iter_t *sel_iter); -/* Static function for optimizing hyperslab */ -static hbool_t H5S__hyper_rebuild_helper(const H5S_hyper_span_t *span, - H5S_hyper_dim_t span_slab_info[], unsigned rank); -static hbool_t H5S__hyper_rebuild(H5S_t *space); /*****************************/ @@ -144,7 +226,6 @@ const H5S_select_class_t H5S_sel_hyper[1] = {{ /* Methods on selection */ H5S__hyper_copy, - H5S__hyper_get_seq_list, H5S__hyper_release, H5S__hyper_is_valid, H5S__hyper_serial_size, @@ -157,12 +238,26 @@ const H5S_select_class_t H5S_sel_hyper[1] = {{ H5S__hyper_is_contiguous, H5S__hyper_is_single, H5S__hyper_is_regular, + H5S__hyper_shape_same, + H5S__hyper_intersect_block, H5S__hyper_adjust_u, + H5S__hyper_adjust_s, H5S__hyper_project_scalar, H5S__hyper_project_simple, H5S__hyper_iter_init, }}; +/* Format version bounds for dataspace hyperslab selection */ +const unsigned H5O_sds_hyper_ver_bounds[] = { + H5S_HYPER_VERSION_1, /* H5F_LIBVER_EARLIEST */ + H5S_HYPER_VERSION_1, /* H5F_LIBVER_V18 */ + H5S_HYPER_VERSION_2 /* H5F_LIBVER_LATEST */ +}; + +/*******************/ +/* Local Variables */ +/*******************/ + /* Iteration properties for hyperslab selections */ static const H5S_sel_iter_class_t H5S_sel_iter_hyper[1] = {{ H5S_SEL_HYPERSLABS, @@ -174,6 +269,7 @@ static const H5S_sel_iter_class_t H5S_sel_iter_hyper[1] = {{ H5S__hyper_iter_has_next_block, H5S__hyper_iter_next, H5S__hyper_iter_next_block, + H5S__hyper_iter_get_seq_list, H5S__hyper_iter_release, }}; @@ -195,12 +291,17 @@ H5FL_DEFINE_STATIC(H5S_hyper_sel_t); /* Declare a free list to manage the H5S_hyper_span_t struct */ H5FL_DEFINE_STATIC(H5S_hyper_span_t); -/* Declare a free list to manage the H5S_hyper_span_info_t struct */ -H5FL_DEFINE_STATIC(H5S_hyper_span_info_t); +/* Declare a free list to manage the H5S_hyper_span_info_t + hsize_t array struct */ +H5FL_BARR_DEFINE_STATIC(H5S_hyper_span_info_t, hbounds_t, H5S_MAX_RANK * 2); /* Declare extern free list to manage the H5S_sel_iter_t struct */ H5FL_EXTERN(H5S_sel_iter_t); +/* Current operation generation */ +/* (Start with '1' to avoid clashing with '0' value in newly allocated structs) */ +static uint64_t H5S_hyper_op_gen_g = 1; + + /* Uncomment this to provide the debugging routines for printing selection info */ /* #define H5S_HYPER_DEBUG */ #ifdef H5S_HYPER_DEBUG @@ -210,9 +311,9 @@ H5S__hyper_print_spans_helper(FILE *f, const H5S_hyper_span_t *span, unsigned de FUNC_ENTER_STATIC_NOERR while(span) { - HDfprintf(f,"%s: depth=%u, span=%p, (%Hu, %Hu), nelem=%Hu, pstride=%Hu\n", FUNC, depth, span, span->low, span->high, span->nelem, span->pstride); - if(span->down && span->down->head) { - HDfprintf(f,"%s: spans=%p, count=%u, scratch=%p, head=%p\n", FUNC, span->down, span->down->count, span->down->scratch, span->down->head); + HDfprintf(f,"%s: %*sdepth=%u, span=%p, (%Hu, %Hu), next=%p\n", FUNC, depth * 2, "", depth, span, span->low, span->high, span->next); + if(span->down) { + HDfprintf(f,"%s: %*sspans=%p, count=%u, bounds[0]={%Hu, %Hu}, head=%p\n", FUNC, (depth + 1) * 2, "", span->down, span->down->count, span->down->low_bounds[0], span->down->high_bounds[0], span->down->head); H5S__hyper_print_spans_helper(f, span->down->head, depth + 1); } /* end if */ span = span->next; @@ -227,7 +328,7 @@ H5S__hyper_print_spans(FILE *f, const H5S_hyper_span_info_t *span_lst) FUNC_ENTER_STATIC_NOERR if(span_lst != NULL) { - HDfprintf(f, "%s: spans=%p, count=%u, scratch=%p, head=%p\n", FUNC, span_lst, span_lst->count, span_lst->scratch, span_lst->head); + HDfprintf(f, "%s: spans=%p, count=%u, bounds[0]={%Hu, %Hu}, head=%p\n", FUNC, span_lst, span_lst->count, span_lst->low_bounds[0], span_lst->high_bounds[0], span_lst->head); H5S__hyper_print_spans_helper(f, span_lst->head, 0); } /* end if */ @@ -281,10 +382,179 @@ H5S__hyper_print_diminfo(FILE *f, const H5S_t *space) FUNC_LEAVE_NOAPI(SUCCEED) } + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_print_spans_dfs + PURPOSE + Output the span elements for one span list in depth-first order + USAGE + herr_t H5S__hyper_print_spans_dfs(f, span_lst, depth) + FILE *f; IN: the file to output + const H5S_hyper_span_info_t *span_lst; IN: the span list to output + unsigned depth; IN: the level of this span list + RETURNS + non-negative on success, negative on failure + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_print_spans_dfs(FILE *f, const H5S_hyper_span_info_t *span_lst, + unsigned depth, unsigned dims) +{ + H5S_hyper_span_t *actual_tail = NULL; + H5S_hyper_span_t *cur_elem; + unsigned num_elems = 0; + unsigned u, elem_idx; + + FUNC_ENTER_STATIC_NOERR + + /* get the actual tail from head */ + cur_elem = span_lst->head; + HDassert(cur_elem); /* at least 1 element */ + while(cur_elem) { + actual_tail = cur_elem; + cur_elem = cur_elem->next; + num_elems++; + } /* end while */ + + for(u = 0; u < depth; u++) + HDfprintf(f, "\t"); + HDfprintf(f, "DIM[%u]: ref_count=%u, #elems=%u, head=%p, tail=%p, actual_tail=%p, matched=%t\n", depth, + span_lst->count, num_elems, span_lst->head, + span_lst->tail, actual_tail, (span_lst->tail == actual_tail)); + + for(u = 0; u < depth; u++) + HDfprintf(f, "\t"); + HDfprintf(f, "low_bounds=["); + for(u = 0; u < dims - 1; u++) + HDfprintf(f, "%llu,", span_lst->low_bounds[u]); + HDfprintf(f, "%llu]\n", span_lst->low_bounds[dims - 1]); + + for(u = 0; u < depth; u++) + HDfprintf(f, "\t"); + HDfprintf(f, "high_bounds=["); + for(u = 0; u < dims - 1; u++) + HDfprintf(f, "%llu,", span_lst->high_bounds[u]); + HDfprintf(f, "%llu]\n", span_lst->high_bounds[dims - 1]); + + cur_elem = span_lst->head; + elem_idx = 0; + while(cur_elem) { + for(u = 0; u < depth; u++) + HDfprintf(f, "\t"); + HDfprintf(f, "ELEM[%u]: ptr=%p, low=%Hu, high=%Hu, down=%p\n", + elem_idx++, cur_elem, cur_elem->low, cur_elem->high, cur_elem->down); + if(cur_elem->down) + H5S__hyper_print_spans_dfs(f, cur_elem->down, depth + 1, dims); + cur_elem = cur_elem->next; + } /* end while */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_print_spans_dfs() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_print_space_dfs + PURPOSE + Output the span elements for one hyperslab selection space in depth-first order + USAGE + herr_t H5S__hyper_print_space_dfs(f, space) + FILE *f; IN: the file to output + const H5S_t *space; IN: the selection space to output + RETURNS + non-negative on success, negative on failure + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_print_space_dfs(FILE *f, const H5S_t *space) +{ + const H5S_hyper_sel_t *hslab = space->select.sel_info.hslab; + const unsigned dims = space->extent.rank; + unsigned u; + + FUNC_ENTER_STATIC_NOERR + + HDassert(hslab); + + HDfprintf(f, "=======================\n"); + HDfprintf(f, "SPACE: span_lst=%p, #dims=%u, offset_changed=%d\n", hslab->span_lst, dims, space->select.offset_changed); + + HDfprintf(f, " offset=["); + for(u = 0; u < dims - 1; u++) + HDfprintf(f, "%lld,", space->select.offset[u]); + HDfprintf(f, "%lld]\n", space->select.offset[dims - 1]); + + HDfprintf(f, " low_bounds=["); + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + for(u = 0; u < dims - 1; u++) + HDfprintf(f, "%llu,", space->select.sel_info.hslab->diminfo.low_bounds[u]); + HDfprintf(f, "%llu]\n", space->select.sel_info.hslab->diminfo.low_bounds[dims - 1]); + } /* end if */ + else { + for(u = 0; u < dims - 1; u++) + HDfprintf(f, "%llu,", space->select.sel_info.hslab->span_lst->low_bounds[u]); + HDfprintf(f, "%llu]\n", space->select.sel_info.hslab->span_lst->low_bounds[dims - 1]); + } /* end else */ + + HDfprintf(f, " high_bounds=["); + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + for(u = 0; u < dims - 1; u++) + HDfprintf(f, "%llu,", space->select.sel_info.hslab->diminfo.high_bounds[u]); + HDfprintf(f, "%llu]\n", space->select.sel_info.hslab->diminfo.high_bounds[dims - 1]); + } /* end if */ + else { + for(u = 0; u < dims - 1; u++) + HDfprintf(f, "%llu,", space->select.sel_info.hslab->span_lst->high_bounds[u]); + HDfprintf(f, "%llu]\n", space->select.sel_info.hslab->span_lst->high_bounds[dims - 1]); + } /* end else */ + + /* Print out diminfo, if it's valid */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) + H5S__hyper_print_diminfo(f, space); + + /* Start print out the highest-order of dimension */ + if(hslab->span_lst) + H5S__hyper_print_spans_dfs(f, hslab->span_lst, 0, dims); + HDfprintf(f, "=======================\n\n"); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_print_space_dfs() */ #endif /* H5S_HYPER_DEBUG */ /*------------------------------------------------------------------------- + * Function: H5S__hyper_get_op_gen + * + * Purpose: Acquire a unique operation generation value + * + * Return: Operation generation value (can't fail) + * + * Programmer: Quincey Koziol + * Saturday, January 19, 2019 + * + * Notes: Assumes that a 64-bit value will not wrap around during + * the lifespan of the process. + * + *------------------------------------------------------------------------- + */ +uint64_t +H5S__hyper_get_op_gen(void) +{ + FUNC_ENTER_PACKAGE_NOERR + + FUNC_LEAVE_NOAPI(H5S_hyper_op_gen_g++); +} /* end H5S__hyper_op_gen() */ + + +/*------------------------------------------------------------------------- * Function: H5S__hyper_iter_init * * Purpose: Initializes iteration information for hyperslab selection. @@ -304,38 +574,45 @@ H5S__hyper_print_diminfo(FILE *f, const H5S_t *space) static herr_t H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter) { - const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ - H5S_hyper_span_info_t *spans; /* Pointer to hyperslab span info node */ + hsize_t *slab_size; /* Pointer to the dataspace dimensions to use for calc. slab */ + hsize_t acc; /* Accumulator for computing cumulative sizes */ + unsigned slab_dim; /* Rank of the fastest changing dimension for calc. slab */ unsigned rank; /* Dataspace's dimension rank */ unsigned u; /* Index variable */ int i; /* Index variable */ + herr_t ret_value = SUCCEED; /* return value */ - FUNC_ENTER_STATIC_NOERR + FUNC_ENTER_STATIC /* Check args */ HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space)); HDassert(iter); HDassert(space->select.sel_info.hslab->unlim_dim < 0); - /* Initialize the number of points to iterate over */ - iter->elmt_left = space->select.num_elem; + /* Initialize the hyperslab iterator's rank */ iter->u.hyp.iter_rank = 0; /* Get the rank of the dataspace */ - rank = space->extent.rank; + rank = iter->rank; - /* Set the temporary pointer to the dimension information */ - tdiminfo = space->select.sel_info.hslab->diminfo.opt; + /* Attempt to rebuild diminfo if it is invalid and has not been confirmed + * to be impossible. + */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO) + H5S__hyper_rebuild((H5S_t *)space); /* Casting away const OK -NAF */ /* Check for the special case of just one H5Sselect_hyperslab call made */ if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { - /* Initialize the information needed for regular hyperslab I/O */ +/* Initialize the information needed for regular hyperslab I/O */ + const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ const hsize_t *mem_size; /* Temporary pointer to dataspace extent's dimension sizes */ - hsize_t acc; /* Accumulator for "flattened" dimension's sizes */ unsigned cont_dim = 0; /* # of contiguous dimensions */ + /* Set the temporary pointer to the dimension information */ + tdiminfo = space->select.sel_info.hslab->diminfo.opt; + /* Set the temporary pointer to the dataspace extent's dimension sizes */ - mem_size = space->extent.size; + mem_size = iter->dims; /* * For a regular hyperslab to be contiguous up to some dimension, it @@ -393,7 +670,7 @@ H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter) iter->u.hyp.diminfo[curr_dim].count = tdiminfo[i].count; iter->u.hyp.diminfo[curr_dim].block = tdiminfo[i].block * acc; iter->u.hyp.size[curr_dim] = mem_size[i] * acc; - iter->u.hyp.sel_off[curr_dim] = space->select.offset[i] * (hssize_t)acc; + iter->u.hyp.sel_off[curr_dim] = iter->sel_off[i] * (hssize_t)acc; /* Reset the "last dim flattened" flag to avoid flattened any further dimensions */ last_dim_flattened = FALSE; @@ -408,7 +685,7 @@ H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter) iter->u.hyp.diminfo[curr_dim].count = tdiminfo[i].count; iter->u.hyp.diminfo[curr_dim].block = tdiminfo[i].block; iter->u.hyp.size[curr_dim] = mem_size[i]; - iter->u.hyp.sel_off[curr_dim] = space->select.offset[i]; + iter->u.hyp.sel_off[curr_dim] = iter->sel_off[i]; } /* end else */ /* Decrement "current" flattened dimension */ @@ -419,20 +696,23 @@ H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter) /* Initialize "flattened" iterator offset to initial location and dataspace extent and selection information to correct values */ for(u = 0; u < flat_rank; u++) iter->u.hyp.off[u] = iter->u.hyp.diminfo[u].start; + + /* Set up information for computing slab sizes */ + slab_dim = iter->u.hyp.iter_rank - 1; + slab_size = iter->u.hyp.size; } /* end if */ else { + /* Make local copy of the regular selection information */ + HDcompile_assert(sizeof(iter->u.hyp.diminfo) == sizeof(space->select.sel_info.hslab->diminfo.opt)); + H5MM_memcpy(iter->u.hyp.diminfo, tdiminfo, sizeof(iter->u.hyp.diminfo)); + /* Initialize position to initial location */ - /* Also make local copy of the regular selection information */ - for(u = 0; u < rank; u++) { - /* Regular selection information */ - iter->u.hyp.diminfo[u].start = tdiminfo[u].start; - iter->u.hyp.diminfo[u].stride = tdiminfo[u].stride; - iter->u.hyp.diminfo[u].count = tdiminfo[u].count; - iter->u.hyp.diminfo[u].block = tdiminfo[u].block; - - /* Position information */ + for(u = 0; u < rank; u++) iter->u.hyp.off[u] = tdiminfo[u].start; - } /* end if */ + + /* Set up information for computing slab sizes */ + slab_dim = iter->rank - 1; + slab_size = iter->dims; } /* end else */ /* Flag the diminfo information as valid in the iterator */ @@ -441,14 +721,30 @@ H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter) /* Initialize irregular region information also (for release) */ iter->u.hyp.spans = NULL; } /* end if */ - else { -/* Initialize the information needed for non-regular hyperslab I/O */ - HDassert(space->select.sel_info.hslab->span_lst); - /* Make a copy of the span tree to iterate over */ - iter->u.hyp.spans = H5S__hyper_copy_span(space->select.sel_info.hslab->span_lst); + else { /* Initialize the information needed for non-regular hyperslab I/O */ + H5S_hyper_span_info_t *spans; /* Pointer to hyperslab span info node */ - /* Set the nelem & pstride values according to the element size */ - H5S__hyper_span_precompute(iter->u.hyp.spans, iter->elmt_size); + /* If this iterator is created from an API call, by default we clone the + * selection now, as the dataspace could be modified or go out of scope. + * + * However, if the H5S_SEL_ITER_SHARE_WITH_DATASPACE flag is given, + * the selection is shared between the selection iterator and the + * dataspace. In this case, the application _must_not_ modify or + * close the dataspace that the iterator is operating on, or undefined + * behavior will occur. + */ + if((iter->flags & H5S_SEL_ITER_API_CALL) && + !(iter->flags & H5S_SEL_ITER_SHARE_WITH_DATASPACE)) { + /* Copy the span tree */ + if(NULL == (iter->u.hyp.spans = H5S__hyper_copy_span(space->select.sel_info.hslab->span_lst, space->extent.rank))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy span tree") + } /* end if */ + else { + /* Share the source dataspace's span tree by incrementing the reference count on it */ + HDassert(space->select.sel_info.hslab->span_lst); + iter->u.hyp.spans = space->select.sel_info.hslab->span_lst; + iter->u.hyp.spans->count++; + } /* end else */ /* Initialize the starting span_info's and spans */ spans = iter->u.hyp.spans; @@ -467,14 +763,33 @@ H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter) spans = spans->head->down; } /* end for */ + /* Set up information for computing slab sizes */ + slab_dim = iter->rank - 1; + slab_size = iter->dims; + /* Flag the diminfo information as not valid in the iterator */ iter->u.hyp.diminfo_valid = FALSE; } /* end else */ + /* Compute the cumulative size of dataspace dimensions */ + for(i = (int)slab_dim, acc = iter->elmt_size; i >= 0; i--) { + iter->u.hyp.slab[i] = acc; + acc *= slab_size[i]; + } /* end for */ + + /* Initialize more information for irregular hyperslab selections */ + if(!iter->u.hyp.diminfo_valid) { + /* Set the offset of the first element iterated on, in each dimension */ + for(u = 0; u < rank; u++) + /* Compute the sequential element offset */ + iter->u.hyp.loc_off[u] = ((hsize_t)((hssize_t)iter->u.hyp.off[u] + iter->sel_off[u])) * iter->u.hyp.slab[u]; + } /* end if */ + /* Initialize type of selection iterator */ iter->type = H5S_sel_iter_hyper; - FUNC_LEAVE_NOAPI(SUCCEED) +done: + FUNC_LEAVE_NOAPI(ret_value) } /* end H5S__hyper_iter_init() */ @@ -1077,8239 +1392,9885 @@ H5S__hyper_iter_next_block(H5S_sel_iter_t *iter) /*-------------------------------------------------------------------------- NAME - H5S__hyper_iter_release + H5S__hyper_iter_get_seq_list_gen PURPOSE - Release hyperslab selection iterator information for a dataspace + Create a list of offsets & lengths for a selection USAGE - herr_t H5S__hyper_iter_release(iter) - H5S_sel_iter_t *iter; IN: Pointer to selection iterator + herr_t H5S__hyper_iter_get_seq_list_gen(iter,maxseq,maxelem,nseq,nelem,off,len) + H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last + position of interest in selection. + size_t maxseq; IN: Maximum number of sequences to generate + size_t maxelem; IN: Maximum number of elements to include in the + generated sequences + size_t *nseq; OUT: Actual number of sequences generated + size_t *nelem; OUT: Actual number of elements in sequences generated + hsize_t *off; OUT: Array of offsets + size_t *len; OUT: Array of lengths RETURNS Non-negative on success/Negative on failure DESCRIPTION - Releases all information for a dataspace hyperslab selection iterator + Use the selection in the dataspace to generate a list of byte offsets and + lengths for the region(s) selected. Start/Restart from the position in the + ITER parameter. The number of sequences generated is limited by the MAXSEQ + parameter and the number of sequences actually generated is stored in the + NSEQ parameter. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ static herr_t -H5S__hyper_iter_release(H5S_sel_iter_t *iter) +H5S__hyper_iter_get_seq_list_gen(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem, + size_t *nseq, size_t *nelem, hsize_t *off, size_t *len) { + H5S_hyper_span_t *curr_span; /* Current hyperslab span node */ + H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */ + hsize_t *slab; /* Cumulative size of each dimension in bytes */ + hsize_t loc_off; /* Byte offset in the dataspace */ + hsize_t last_span_end = 0; /* The offset of the end of the last span */ + hsize_t *abs_arr; /* Absolute hyperslab span position, in elements */ + hsize_t *loc_arr; /* Byte offset of hyperslab span position within buffer */ + const hssize_t *sel_off; /* Offset within the dataspace extent */ + size_t span_elmts = 0; /* Number of elements to actually use for this span */ + size_t span_size = 0; /* Number of bytes in current span to actually process */ + size_t io_left; /* Initial number of elements to process */ + size_t io_elmts_left; /* Number of elements left to process */ + size_t io_used; /* Number of elements processed */ + size_t curr_seq = 0; /* Number of sequence/offsets stored in the arrays */ + size_t elem_size; /* Size of each element iterating over */ + unsigned ndims; /* Number of dimensions of dataset */ + unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + int curr_dim; /* Current dimension being operated on */ + unsigned u; /* Index variable */ + FUNC_ENTER_STATIC_NOERR /* Check args */ HDassert(iter); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); -/* Release the information needed for non-regular hyperslab I/O */ - /* Free the copy of the selections span tree */ - if(iter->u.hyp.spans != NULL) - H5S__hyper_free_span_info(iter->u.hyp.spans); - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_iter_release() */ + /* Set the rank of the fastest changing dimension */ + ndims = iter->rank; + fast_dim = (ndims - 1); - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_new_span - PURPOSE - Make a new hyperslab span node - USAGE - H5S_hyper_span_t *H5S__hyper_new_span(low, high, down, next) - hsize_t low, high; IN: Low and high bounds for new span node - H5S_hyper_span_info_t *down; IN: Down span tree for new node - H5S_hyper_span_t *next; IN: Next span for new node - RETURNS - Pointer to next span node on success, NULL on failure - DESCRIPTION - Allocate and initialize a new hyperslab span node, filling in the low & - high bounds, the down span and next span pointers also. Increment the - reference count of the 'down span' if applicable. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static H5S_hyper_span_t * -H5S__hyper_new_span(hsize_t low, hsize_t high, H5S_hyper_span_info_t *down, H5S_hyper_span_t *next) -{ - H5S_hyper_span_t *ret_value = NULL; /* Return value */ + /* Get the pointers to the current span info and span nodes */ + curr_span = iter->u.hyp.span[fast_dim]; + abs_arr = iter->u.hyp.off; + loc_arr = iter->u.hyp.loc_off; + slab = iter->u.hyp.slab; + sel_off = iter->sel_off; + ispan = iter->u.hyp.span; + elem_size = iter->elmt_size; - FUNC_ENTER_STATIC + /* Set the amount of elements to perform I/O on, etc. */ + H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t); + io_elmts_left = io_left = MIN(maxelem, (size_t)iter->elmt_left); - /* Allocate a new span node */ - if(NULL == (ret_value = H5FL_MALLOC(H5S_hyper_span_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") + /* Set the offset of the first element iterated on */ + for(u = 0, loc_off = 0; u < ndims; u++) + loc_off += loc_arr[u]; - /* Copy the span's basic information */ - ret_value->low = low; - ret_value->high = high; - ret_value->nelem = (high - low) + 1; - ret_value->pstride = 0; - ret_value->down = down; - ret_value->next = next; + /* Take care of any partial spans leftover from previous I/Os */ + if(abs_arr[fast_dim] != curr_span->low) { + /* Finish the span in the fastest changing dimension */ - /* Increment the reference count of the 'down span' if there is one */ - if(ret_value->down) - ret_value->down->count++; + /* Compute the number of elements to attempt in this span */ + H5_CHECKED_ASSIGN(span_elmts, size_t, ((curr_span->high - abs_arr[fast_dim]) + 1), hsize_t); -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_new_span() */ + /* Check number of elements against upper bounds allowed */ + if(span_elmts > io_elmts_left) + span_elmts = io_elmts_left; - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_span_precompute_helper - PURPOSE - Helper routine to precompute the nelem and pstrides in bytes. - USAGE - void H5S__hyper_span_precompute_helper(span_info, elmt_size) - H5S_hyper_span_info_t *span_info; IN/OUT: Span tree to work on - size_t elmt_size; IN: element size to work with - RETURNS - None - DESCRIPTION - Change the nelem and pstride values in the span tree from elements to - bytes using the elmt_size parameter. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static void -H5S__hyper_span_precompute_helper(H5S_hyper_span_info_t *spans, size_t elmt_size) -{ - FUNC_ENTER_STATIC_NOERR + /* Set the span_size, in bytes */ + span_size = span_elmts * elem_size; - /* Sanity checks */ - HDassert(spans); - HDassert(spans->scratch == (H5S_hyper_span_info_t *)~((size_t)NULL) || - spans->scratch == NULL); + /* Add the partial span to the list of sequences */ + off[curr_seq] = loc_off; + len[curr_seq] = span_size; - /* Check if we've already set this down span tree */ - if(spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)) { - H5S_hyper_span_t *span; /* Hyperslab span */ + /* Increment sequence count */ + curr_seq++; - /* Set the tree's scratch pointer */ - spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL); + /* Set the location of the last span's end */ + last_span_end = loc_off + span_size; - /* Set the scratch pointers in all the nodes */ - span = spans->head; + /* Decrement I/O left to perform */ + io_elmts_left -= span_elmts; - /* Loop over all the spans for this down span tree */ - while(span != NULL) { - /* If there are down spans, precompute their values also */ - if(span->down != NULL) - H5S__hyper_span_precompute_helper(span->down, elmt_size); + /* Check if we are done */ + if(io_elmts_left > 0) { + /* Move to next span in fastest changing dimension */ + curr_span = curr_span->next; - /* Change the nelem & pstride values into bytes */ - span->nelem *= elmt_size; - span->pstride *= elmt_size; + if(NULL != curr_span) { + /* Move location offset of destination */ + loc_off += (curr_span->low - abs_arr[fast_dim]) * elem_size; - /* Advance to next span */ - span = span->next; - } /* end while */ - } /* end if */ + /* Move iterator for fastest changing dimension */ + abs_arr[fast_dim] = curr_span->low; + loc_arr[fast_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[fast_dim])) * slab[fast_dim]; + ispan[fast_dim] = curr_span; + } /* end if */ + } /* end if */ + else { + /* Advance the hyperslab iterator */ + abs_arr[fast_dim] += span_elmts; - FUNC_LEAVE_NOAPI_VOID -} /* end H5S__hyper_span_precompute_helper() */ + /* Check if we are still within the span */ + if(abs_arr[fast_dim] <= curr_span->high) { + /* Sanity check */ + HDassert(ispan[fast_dim] == curr_span); - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_span_precompute - PURPOSE - Precompute the nelem and pstrides in bytes. - USAGE - herr_t H5S__hyper_span_precompute(span_info, elmt_size) - H5S_hyper_span_info_t *span_info; IN/OUT: Span tree to work on - size_t elmt_size; IN: element size to work with - RETURNS - Non-negative on success, negative on failure - DESCRIPTION - Change the nelem and pstride values in the span tree from elements to - bytes using the elmt_size parameter. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_span_precompute(H5S_hyper_span_info_t *spans, size_t elmt_size) -{ - FUNC_ENTER_STATIC_NOERR + /* Update byte offset */ + loc_arr[fast_dim] += span_size; + } /* end if */ + /* If we walked off that span, advance to the next span */ + else { + /* Advance span in this dimension */ + curr_span = curr_span->next; - HDassert(spans); + /* Check if we have a valid span in this dimension still */ + if(NULL != curr_span) { + /* Reset absolute position */ + abs_arr[fast_dim] = curr_span->low; - /* Call the helper routine to actually do the work */ - H5S__hyper_span_precompute_helper(spans, elmt_size); + /* Update location offset */ + loc_arr[fast_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[fast_dim])) * slab[fast_dim]; - /* Reset the scratch pointers for the next routine which needs them */ - H5S__hyper_span_scratch(spans); + /* Reset the span in the current dimension */ + ispan[fast_dim] = curr_span; + } /* end if */ + } /* end else */ + } /* end else */ - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_span_precompute() */ + /* Adjust iterator pointers */ - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_span_scratch - PURPOSE - Reset the scratch pointers on hyperslab span trees - USAGE - void H5S__hyper_span_scratch(span_info) - H5S_hyper_span_info_t *span_info; IN: Span tree to reset - RETURNS - - DESCRIPTION - Reset the scratch pointers on a hyperslab span tree to NULL. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static void -H5S__hyper_span_scratch(H5S_hyper_span_info_t *spans) -{ - FUNC_ENTER_STATIC_NOERR + if(NULL == curr_span) { +/* Same as code in main loop */ + /* Start at the next fastest dim */ + curr_dim = (int)(fast_dim - 1); - HDassert(spans); + /* Work back up through the dimensions */ + while(curr_dim >= 0) { + /* Reset the current span */ + curr_span = ispan[curr_dim]; - /* Check if we've already set this down span tree */ - if(spans->scratch != NULL) { - H5S_hyper_span_t *span; /* Hyperslab span */ + /* Increment absolute position */ + abs_arr[curr_dim]++; - /* Reset the tree's scratch pointer */ - spans->scratch = NULL; + /* Check if we are still within the span */ + if(abs_arr[curr_dim] <= curr_span->high) { + /* Update location offset */ + loc_arr[curr_dim] += slab[curr_dim]; - /* Set the scratch pointers in all the nodes */ - span = spans->head; - while(span != NULL) { - /* If there are down spans, set their scratch value also */ - if(span->down != NULL) - H5S__hyper_span_scratch(span->down); + break; + } /* end if */ + /* If we walked off that span, advance to the next span */ + else { + /* Advance span in this dimension */ + curr_span = curr_span->next; - /* Advance to next span */ - span = span->next; - } /* end while */ - } /* end if */ + /* Check if we have a valid span in this dimension still */ + if(NULL != curr_span) { + /* Reset the span in the current dimension */ + ispan[curr_dim] = curr_span; - FUNC_LEAVE_NOAPI_VOID -} /* end H5S__hyper_span_scratch() */ + /* Reset absolute position */ + abs_arr[curr_dim] = curr_span->low; - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_copy_span_helper - PURPOSE - Helper routine to copy a hyperslab span tree - USAGE - H5S_hyper_span_info_t * H5S__hyper_copy_span_helper(spans) - H5S_hyper_span_info_t *spans; IN: Span tree to copy - RETURNS - Pointer to the copied span tree on success, NULL on failure - DESCRIPTION - Copy a hyperslab span tree, using reference counting as appropriate. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static H5S_hyper_span_info_t * -H5S__hyper_copy_span_helper(H5S_hyper_span_info_t *spans) -{ - H5S_hyper_span_t *span; /* Hyperslab span */ - H5S_hyper_span_t *new_span; /* Temporary hyperslab span */ - H5S_hyper_span_t *prev_span; /* Previous hyperslab span */ - H5S_hyper_span_info_t *new_down; /* New down span tree */ - H5S_hyper_span_info_t *ret_value = NULL; /* Return value */ + /* Update byte location */ + loc_arr[curr_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[curr_dim])) * slab[curr_dim]; - FUNC_ENTER_STATIC + break; + } /* end if */ + else + /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */ + curr_dim--; + } /* end else */ + } /* end while */ - /* Sanity checks */ - HDassert(spans); - HDassert(spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)); + /* Check if we have more spans in the tree */ + if(curr_dim >= 0) { + /* Walk back down the iterator positions, resetting them */ + while((unsigned)curr_dim < fast_dim) { + HDassert(curr_span); + HDassert(curr_span->down); + HDassert(curr_span->down->head); - /* Check if the span tree was already copied */ - if(spans->scratch != NULL) { - /* Just return the value of the already copied span tree */ - ret_value = spans->scratch; + /* Increment current dimension */ + curr_dim++; - /* Increment the reference count of the span tree */ - ret_value->count++; - } /* end if */ - else { - /* Allocate a new span_info node */ - if(NULL == (ret_value = H5FL_CALLOC(H5S_hyper_span_info_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span info") + /* Set the new span_info & span for this dimension */ + ispan[curr_dim] = curr_span->down->head; - /* Copy the span_info information */ - ret_value->count = 1; + /* Advance span down the tree */ + curr_span = curr_span->down->head; - /* Set the scratch pointer in the node being copied to the newly allocated node */ - spans->scratch = ret_value; + /* Reset the absolute offset for the dim */ + abs_arr[curr_dim] = curr_span->low; - /* Copy over the nodes in the span list */ - span = spans->head; - prev_span = NULL; - while(span != NULL) { - /* Allocate a new node */ - if(NULL == (new_span = H5S__hyper_new_span(span->low, span->high, NULL, NULL))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") + /* Update the location offset */ + loc_arr[curr_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[curr_dim])) * slab[curr_dim]; + } /* end while */ - /* Append to list of spans */ - if(NULL == prev_span) - ret_value->head = new_span; - else - prev_span->next = new_span; + /* Verify that the curr_span points to the fastest dim */ + HDassert(curr_span == ispan[fast_dim]); - /* Copy the pstride */ - new_span->pstride = span->pstride; + /* Reset the buffer offset */ + for(u = 0, loc_off = 0; u < ndims; u++) + loc_off += loc_arr[u]; + } /* end else */ + else + /* We had better be done with I/O or bad things are going to happen... */ + HDassert(io_elmts_left == 0); + } /* end if */ + } /* end if */ - /* Recurse to copy the 'down' spans, if there are any */ - if(span->down != NULL) { - if(NULL == (new_down = H5S__hyper_copy_span_helper(span->down))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy hyperslab spans") - new_span->down = new_down; - } /* end if */ + /* Perform the I/O on the elements, based on the position of the iterator */ + while(io_elmts_left > 0 && curr_seq < maxseq) { + H5S_hyper_span_t *prev_span; /* Previous hyperslab span node */ - /* Update the previous (new) span */ - prev_span = new_span; + /* Sanity check */ + HDassert(curr_span); - /* Advance to next span */ - span = span->next; - } /* end while */ - } /* end else */ + /* Set to current span, so the first adjustment to loc_off is 0 */ + prev_span = curr_span; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_copy_span_helper() */ + /* Loop over all the spans in the fastest changing dimension */ + while(curr_span != NULL) { + hsize_t nelmts; /* # of elements covered by current span */ - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_copy_span - PURPOSE - Copy a hyperslab span tree - USAGE - H5S_hyper_span_info_t * H5S__hyper_copy_span(span_info) - H5S_hyper_span_info_t *span_info; IN: Span tree to copy - RETURNS - Pointer to the copied span tree on success, NULL on failure - DESCRIPTION - Copy a hyperslab span tree, using reference counting as appropriate. - (Which means that just the nodes in the top span tree are duplicated and - the reference counts of their 'down spans' are just incremented) - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static H5S_hyper_span_info_t * -H5S__hyper_copy_span(H5S_hyper_span_info_t *spans) -{ - H5S_hyper_span_info_t *ret_value = NULL; /* Return value */ + /* Move location offset of current span */ + loc_off += (curr_span->low - prev_span->low) * elem_size; - FUNC_ENTER_STATIC + /* Compute the number of elements to attempt in this span */ + nelmts = (curr_span->high - curr_span->low) + 1; + H5_CHECKED_ASSIGN(span_elmts, size_t, nelmts, hsize_t); - HDassert(spans); + /* Check number of elements against upper bounds allowed */ + if(span_elmts >= io_elmts_left) { + /* Trim the number of elements to output */ + span_elmts = io_elmts_left; + span_size = span_elmts * elem_size; + io_elmts_left = 0; - /* Copy the hyperslab span tree */ - if(NULL == (ret_value = H5S__hyper_copy_span_helper(spans))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree") +/* COMMON */ + /* Store the I/O information for the span */ - /* Reset the scratch pointers for the next routine which needs them */ - H5S__hyper_span_scratch(spans); + /* Check if this is appending onto previous sequence */ + if(curr_seq > 0 && last_span_end == loc_off) + len[curr_seq - 1] += span_size; + else { + off[curr_seq] = loc_off; + len[curr_seq] = span_size; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_copy_span() */ + /* Increment the number of sequences in arrays */ + curr_seq++; + } /* end else */ +/* end COMMON */ - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_cmp_spans - PURPOSE - Check if two hyperslab span trees are the same - USAGE - hbool_t H5S__hyper_cmp_spans(span1, span2) - H5S_hyper_span_info_t *span_info1; IN: First span tree to compare - H5S_hyper_span_info_t *span_info2; IN: Second span tree to compare - RETURNS - TRUE (1) or FALSE (0) on success, can't fail - DESCRIPTION - Compare two hyperslab span trees to determine if they refer to the same - selection. If span1 & span2 are both NULL, that counts as equal. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static H5_ATTR_PURE hbool_t -H5S__hyper_cmp_spans(const H5S_hyper_span_info_t *span_info1, const H5S_hyper_span_info_t *span_info2) -{ - hbool_t ret_value = FALSE; /* Return value */ + /* Break out now, we are finished with I/O */ + break; + } /* end if */ + else { + /* Decrement I/O left to perform */ + span_size = span_elmts * elem_size; + io_elmts_left -= span_elmts; - FUNC_ENTER_STATIC_NOERR +/* COMMON */ + /* Store the I/O information for the span */ - /* Check for redundant comparison */ - if(span_info1 == span_info2) - ret_value = TRUE; - else { - const H5S_hyper_span_t *span1; - const H5S_hyper_span_t *span2; + /* Check if this is appending onto previous sequence */ + if(curr_seq > 0 && last_span_end == loc_off) + len[curr_seq - 1] += span_size; + else { + off[curr_seq] = loc_off; + len[curr_seq] = span_size; - /* Check for both spans being NULL */ - if(span_info1 == NULL && span_info2 == NULL) - ret_value = TRUE; - else { - /* Check for one span being NULL */ - if(span_info1 == NULL || span_info2 == NULL) - ret_value = FALSE; - else { - /* Get the pointers to the actual lists of spans */ - span1 = span_info1->head; - span2 = span_info2->head; + /* Increment the number of sequences in arrays */ + curr_seq++; + } /* end else */ +/* end COMMON */ - /* Sanity checking */ - HDassert(span1); - HDassert(span2); + /* If the sequence & offset arrays are full, do what? */ + if(curr_seq >= maxseq) + /* Break out now, we are finished with sequences */ + break; + } /* end else */ - /* infinite loop which must be broken out of */ - while(1) { - /* Check for both spans being NULL */ - if(span1 == NULL && span2 == NULL) { - ret_value = TRUE; - break; - } /* end if */ - else { - /* Check for one span being NULL */ - if(span1 == NULL || span2 == NULL) { - ret_value = FALSE; - break; - } /* end if */ - else { - /* Check if the actual low & high span information is the same */ - if(span1->low != span2->low || span1->high != span2->high) { - ret_value = FALSE; - break; - } /* end if */ - else { - if(span1->down != NULL || span2 != NULL) { - if(!H5S__hyper_cmp_spans(span1->down, span2->down)) { - ret_value = FALSE; - break; - } /* end if */ - else { - /* Keep going... */ - } /* end else */ - } /* end if */ - else { - /* Keep going... */ - } /* end else */ - } /* end else */ - } /* end else */ - } /* end else */ + /* Set the location of the last span's end */ + last_span_end = loc_off + span_size; - /* Advance to the next nodes in the span list */ - span1 = span1->next; - span2 = span2->next; - } /* end while */ + /* Move to next span in fastest changing dimension */ + prev_span = curr_span; + curr_span = curr_span->next; + } /* end while */ + + /* Check if we are done */ + if(io_elmts_left == 0 || curr_seq >= maxseq) { + /* Sanity checks */ + HDassert(curr_span); + + /* Update absolute position */ + abs_arr[fast_dim] = curr_span->low + span_elmts; + + /* Check if we are still within the span */ + if(abs_arr[fast_dim] <= curr_span->high) { + /* Reset the span for the fast dimension */ + ispan[fast_dim] = curr_span; + + /* Update location offset */ + loc_arr[fast_dim] = ((hsize_t)((hssize_t)curr_span->low + (hssize_t)span_elmts + sel_off[fast_dim])) * slab[fast_dim]; + + break; + } /* end if */ + /* If we walked off that span, advance to the next span */ + else { + /* Advance span in this dimension */ + curr_span = curr_span->next; + + /* Check if we have a valid span in this dimension still */ + if(curr_span != NULL) { + /* Reset absolute position */ + abs_arr[fast_dim] = curr_span->low; + loc_arr[fast_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[fast_dim])) * slab[fast_dim]; + ispan[fast_dim] = curr_span; + + break; + } /* end if */ } /* end else */ - } /* end else */ - } /* end else */ + } /* end if */ - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_cmp_spans() */ + /* Adjust iterator pointers */ - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_free_span_info - PURPOSE - Free a hyperslab span info node - USAGE - herr_t H5S__hyper_free_span_info(span_info) - H5S_hyper_span_info_t *span_info; IN: Span info node to free - RETURNS - Non-negative on success, negative on failure - DESCRIPTION - Free a hyperslab span info node, along with all the span nodes and the - 'down spans' from the nodes, if reducing their reference count to zero - indicates it is appropriate to do so. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_free_span_info(H5S_hyper_span_info_t *span_info) -{ - H5S_hyper_span_t *span, *next_span; - herr_t ret_value = SUCCEED; /* Return value */ + /* Start at the next fastest dim */ + curr_dim = (int)(fast_dim - 1); - FUNC_ENTER_STATIC + /* Work back up through the dimensions */ + while(curr_dim >= 0) { + /* Reset the current span */ + curr_span = ispan[curr_dim]; - /* Sanity check */ - HDassert(span_info); + /* Increment absolute position */ + abs_arr[curr_dim]++; - /* Decrement the span tree's reference count */ - span_info->count--; + /* Check if we are still within the span */ + if(abs_arr[curr_dim] <= curr_span->high) { + /* Update location offset */ + loc_arr[curr_dim] += slab[curr_dim]; - /* Free the span tree if the reference count drops to zero */ - if(span_info->count == 0) { + break; + } /* end if */ + /* If we walked off that span, advance to the next span */ + else { + /* Advance span in this dimension */ + curr_span = curr_span->next; - /* Work through the list of spans pointed to by this 'info' node */ - span = span_info->head; - while(span != NULL) { - next_span = span->next; - if(H5S__hyper_free_span(span) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab span") - span = next_span; + /* Check if we have a valid span in this dimension still */ + if(curr_span != NULL) { + /* Reset the span in the current dimension */ + ispan[curr_dim] = curr_span; + + /* Reset absolute position */ + abs_arr[curr_dim] = curr_span->low; + + /* Update location offset */ + loc_arr[curr_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[curr_dim])) * slab[curr_dim]; + + break; + } /* end if */ + else + /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */ + curr_dim--; + } /* end else */ } /* end while */ - /* Free this span info */ - span_info = H5FL_FREE(H5S_hyper_span_info_t, span_info); - } /* end if */ + /* Check if we are finished with the spans in the tree */ + if(curr_dim < 0) { + /* We had better be done with I/O or bad things are going to happen... */ + HDassert(io_elmts_left == 0); + break; + } /* end if */ + else { + /* Walk back down the iterator positions, resetting them */ + while((unsigned)curr_dim < fast_dim) { + HDassert(curr_span); + HDassert(curr_span->down); + HDassert(curr_span->down->head); -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_free_span_info() */ + /* Increment current dimension to the next dimension down */ + curr_dim++; + + /* Set the new span for the next dimension down */ + ispan[curr_dim] = curr_span->down->head; + + /* Advance span down the tree */ + curr_span = curr_span->down->head; + + /* Reset the absolute offset for the dim */ + abs_arr[curr_dim] = curr_span->low; + + /* Update location offset */ + loc_arr[curr_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[curr_dim])) * slab[curr_dim]; + } /* end while */ + + /* Verify that the curr_span points to the fastest dim */ + HDassert(curr_span == ispan[fast_dim]); + } /* end else */ + + /* Reset the buffer offset */ + for(u = 0, loc_off = 0; u < ndims; u++) + loc_off += loc_arr[u]; + } /* end while */ + + /* Decrement number of elements left in iterator */ + io_used = io_left - io_elmts_left; + iter->elmt_left -= io_used; + + /* Set the number of sequences generated */ + *nseq = curr_seq; + + /* Set the number of elements used */ + *nelem = io_used; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_iter_get_seq_list_gen() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_free_span + H5S__hyper_iter_get_seq_list_opt PURPOSE - Free a hyperslab span node + Create a list of offsets & lengths for a selection USAGE - herr_t H5S__hyper_free_span(span) - H5S_hyper_span_t *span; IN: Span node to free + herr_t H5S__hyper_iter_get_seq_list_opt(iter,maxseq,maxelem,nseq,nelem,off,len) + H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last + position of interest in selection. + size_t maxseq; IN: Maximum number of sequences to generate + size_t maxelem; IN: Maximum number of elements to include in the + generated sequences + size_t *nseq; OUT: Actual number of sequences generated + size_t *nelem; OUT: Actual number of elements in sequences generated + hsize_t *off; OUT: Array of offsets + size_t *len; OUT: Array of lengths RETURNS - Non-negative on success, negative on failure + Non-negative on success/Negative on failure. DESCRIPTION - Free a hyperslab span node, along with the 'down spans' from the node, - if reducing their reference count to zero indicates it is appropriate to - do so. + Use the selection in the dataspace to generate a list of byte offsets and + lengths for the region(s) selected. Start/Restart from the position in the + ITER parameter. The number of sequences generated is limited by the MAXSEQ + parameter and the number of sequences actually generated is stored in the + NSEQ parameter. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ static herr_t -H5S__hyper_free_span(H5S_hyper_span_t *span) +H5S__hyper_iter_get_seq_list_opt(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem, + size_t *nseq, size_t *nelem, hsize_t *off, size_t *len) { - herr_t ret_value = SUCCEED; - - FUNC_ENTER_STATIC + hsize_t *mem_size; /* Size of the source buffer */ + hsize_t *slab; /* Hyperslab size */ + const hssize_t *sel_off; /* Selection offset in dataspace */ + hsize_t offset[H5S_MAX_RANK]; /* Coordinate offset in dataspace */ + hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary block count */ + hsize_t tmp_block[H5S_MAX_RANK]; /* Temporary block offset */ + hsize_t wrap[H5S_MAX_RANK]; /* Bytes to wrap around at the end of a row */ + hsize_t skip[H5S_MAX_RANK]; /* Bytes to skip between blocks */ + const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ + hsize_t fast_dim_start, /* Local copies of fastest changing dimension info */ + fast_dim_stride, + fast_dim_block, + fast_dim_offset; + size_t fast_dim_buf_off; /* Local copy of amount to move fastest dimension buffer offset */ + size_t fast_dim_count; /* Number of blocks left in fastest changing dimension */ + size_t tot_blk_count; /* Total number of blocks left to output */ + size_t act_blk_count; /* Actual number of blocks to output */ + size_t total_rows; /* Total number of entire rows to output */ + size_t curr_rows; /* Current number of entire rows to output */ + unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + unsigned ndims; /* Number of dimensions of dataset */ + int temp_dim; /* Temporary rank holder */ + hsize_t loc; /* Coordinate offset */ + size_t curr_seq = 0; /* Current sequence being operated on */ + size_t actual_elem; /* The actual number of elements to count */ + size_t actual_bytes;/* The actual number of bytes to copy */ + size_t io_left; /* The number of elements left in I/O operation */ + size_t start_io_left; /* The initial number of elements left in I/O operation */ + size_t elem_size; /* Size of each element iterating over */ + unsigned u; /* Local index variable */ - /* Sanity check */ - HDassert(span); + FUNC_ENTER_STATIC_NOERR - /* Decrement the reference count of the 'down spans', freeing them if appropriate */ - if(span->down != NULL) - if(H5S__hyper_free_span_info(span->down) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab span tree") + /* Check args */ + HDassert(iter); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); - /* Free this span */ - span = H5FL_FREE(H5S_hyper_span_t, span); + /* Set the local copy of the diminfo pointer */ + tdiminfo = iter->u.hyp.diminfo; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_free_span() */ + /* Check if this is a "flattened" regular hyperslab selection */ + if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank) { + /* Set the aliases for a few important dimension ranks */ + ndims = iter->u.hyp.iter_rank; - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_copy - PURPOSE - Copy a selection from one dataspace to another - USAGE - herr_t H5S__hyper_copy(dst, src, share_selection) - H5S_t *dst; OUT: Pointer to the destination dataspace - H5S_t *src; IN: Pointer to the source dataspace - hbool_t; IN: Whether to share the selection between the dataspaces - RETURNS - Non-negative on success, negative on failure - DESCRIPTION - Copies all the hyperslab selection information from the source - dataspace to the destination dataspace. + /* Set the local copy of the selection offset */ + sel_off = iter->u.hyp.sel_off; - If the SHARE_SELECTION flag is set, then the selection can be shared - between the source and destination dataspaces. (This should only occur in - situations where the destination dataspace will immediately change to a new - selection) - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection) -{ - H5S_hyper_sel_t *dst_hslab; /* Pointer to destination hyperslab info */ - const H5S_hyper_sel_t *src_hslab; /* Pointer to source hyperslab info */ - herr_t ret_value = SUCCEED; /* Return value */ + /* Set up the pointer to the size of the memory dataspace */ + mem_size = iter->u.hyp.size; + } /* end if */ + else { + /* Set the aliases for a few important dimension ranks */ + ndims = iter->rank; - FUNC_ENTER_STATIC + /* Set the local copy of the selection offset */ + sel_off = iter->sel_off; - /* Sanity check */ - HDassert(src); - HDassert(dst); + /* Set up the pointer to the size of the memory dataspace */ + mem_size = iter->dims; + } /* end else */ - /* Allocate space for the hyperslab selection information */ - if(NULL == (dst->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info") + /* Set up some local variables */ + fast_dim = ndims - 1; + elem_size = iter->elmt_size; + slab = iter->u.hyp.slab; - /* Set temporary pointers */ - dst_hslab = dst->select.sel_info.hslab; - src_hslab = src->select.sel_info.hslab; + /* Calculate the number of elements to sequence through */ + H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t); + io_left = MIN((size_t)iter->elmt_left, maxelem); - /* Copy the hyperslab information */ - dst_hslab->diminfo_valid = src_hslab->diminfo_valid; - if(src_hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { - size_t u; /* Local index variable */ + /* Sanity check that there aren't any "remainder" sequences in process */ + HDassert(!((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride != 0 || + ((iter->u.hyp.off[fast_dim] != tdiminfo[fast_dim].start) && tdiminfo[fast_dim].count == 1))); - for(u=0; uextent.rank; u++) { - dst_hslab->diminfo.opt[u]=src_hslab->diminfo.opt[u]; - dst_hslab->diminfo.app[u]=src_hslab->diminfo.app[u]; - } /* end for */ - } /* end if */ - dst->select.sel_info.hslab->span_lst = src->select.sel_info.hslab->span_lst; + /* We've cleared the "remainder" of the previous fastest dimension + * sequence before calling this routine, so we must be at the beginning of + * a sequence. Use the fancy algorithm to compute the offsets and run + * through as many as possible, until the buffer fills up. + */ - /* Check if there is hyperslab span information to copy */ - /* (Regular hyperslab information is copied with the selection structure) */ - if(src->select.sel_info.hslab->span_lst != NULL) { - if(share_selection) { - /* Share the source's span tree by incrementing the reference count on it */ - dst->select.sel_info.hslab->span_lst = src->select.sel_info.hslab->span_lst; - dst->select.sel_info.hslab->span_lst->count++; + /* Keep the number of elements we started with */ + start_io_left = io_left; + + /* Compute the arrays to perform I/O on */ + + /* Copy the location of the point to get */ + /* (Add in the selection offset) */ + for(u = 0; u < ndims; u++) + offset[u] = (hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u]); + + /* Compute the current "counts" for this location */ + for(u = 0; u < ndims; u++) { + if(tdiminfo[u].count == 1) { + tmp_count[u] = 0; + tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start; } /* end if */ - else - /* Copy the hyperslab span information */ - dst->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(src->select.sel_info.hslab->span_lst); - } /* end if */ - else - dst->select.sel_info.hslab->span_lst = NULL; + else { + tmp_count[u] = (iter->u.hyp.off[u] - tdiminfo[u].start) / tdiminfo[u].stride; + tmp_block[u] = (iter->u.hyp.off[u] - tdiminfo[u].start) % tdiminfo[u].stride; + } /* end else */ + } /* end for */ - /* Copy the unlimited dimension info */ - dst_hslab->unlim_dim = src_hslab->unlim_dim; - dst_hslab->num_elem_non_unlim = src_hslab->num_elem_non_unlim; + /* Compute the initial buffer offset */ + for(u = 0, loc = 0; u < ndims; u++) + loc += offset[u] * slab[u]; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_copy() */ + /* Set the number of elements to write each time */ + H5_CHECKED_ASSIGN(actual_elem, size_t, tdiminfo[fast_dim].block, hsize_t); - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_is_valid_helper - PURPOSE - Check whether the selection fits within the extent, with the current - offset defined. - USAGE - hbool_t H5S__hyper_is_valid_helper(spans, offset, rank); - const H5S_hyper_span_info_t *spans; IN: Pointer to current hyperslab span tree - const hssize_t *offset; IN: Pointer to offset array - const hsize_t *size; IN: Pointer to size array - hsize_t rank; IN: Current rank looking at - RETURNS - TRUE if the selection fits within the extent, FALSE if it does not - DESCRIPTION - Determines if the current selection at the current offset fits within the - extent for the dataspace. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static hbool_t -H5S__hyper_is_valid_helper(const H5S_hyper_span_info_t *spans, const hssize_t *offset, - const hsize_t *size) -{ - H5S_hyper_span_t *curr; /* Hyperslab information nodes */ - hbool_t ret_value = TRUE; /* Return value */ + /* Set the number of actual bytes */ + actual_bytes = actual_elem * elem_size; - FUNC_ENTER_STATIC_NOERR + /* Set local copies of information for the fastest changing dimension */ + fast_dim_start = tdiminfo[fast_dim].start; + fast_dim_stride = tdiminfo[fast_dim].stride; + fast_dim_block = tdiminfo[fast_dim].block; + H5_CHECKED_ASSIGN(fast_dim_buf_off, size_t, slab[fast_dim] * fast_dim_stride, hsize_t); + fast_dim_offset = (hsize_t)((hssize_t)fast_dim_start + sel_off[fast_dim]); - HDassert(spans); - HDassert(offset); - HDassert(size); + /* Compute the number of blocks which would fit into the buffer */ + H5_CHECK_OVERFLOW(io_left / fast_dim_block, hsize_t, size_t); + tot_blk_count = (size_t)(io_left / fast_dim_block); - /* Check each point to determine whether selection + offset is within extent */ - curr = spans->head; - while(curr != NULL) { - /* Check if an offset has been defined */ - /* Bounds check the selected point + offset against the extent */ - if((((hssize_t)curr->low + *offset) >= (hssize_t)*size) - || (((hssize_t)curr->low + *offset) < 0) - || (((hssize_t)curr->high + *offset) >= (hssize_t)*size) - || (((hssize_t)curr->high + *offset) < 0)) - HGOTO_DONE(FALSE) + /* Don't go over the maximum number of sequences allowed */ + tot_blk_count = MIN(tot_blk_count, (maxseq - curr_seq)); - /* Recurse if this node has down spans */ - if(curr->down != NULL) - if(!H5S__hyper_is_valid_helper(curr->down, offset + 1, size + 1)) - HGOTO_DONE(FALSE) + /* Compute the amount to wrap at the end of each row */ + for(u = 0; u < ndims; u++) + wrap[u] = (mem_size[u] - (tdiminfo[u].stride * tdiminfo[u].count)) * slab[u]; - /* Advance to next node */ - curr = curr->next; - } /* end while */ + /* Compute the amount to skip between blocks */ + for(u = 0; u < ndims; u++) + skip[u] = (tdiminfo[u].stride - tdiminfo[u].block) * slab[u]; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_is_valid_helper() */ + /* Check if there is a partial row left (with full blocks) */ + if(tmp_count[fast_dim] > 0) { + /* Get number of blocks in fastest dimension */ + H5_CHECKED_ASSIGN(fast_dim_count, size_t, tdiminfo[fast_dim].count - tmp_count[fast_dim], hsize_t); - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_is_valid - PURPOSE - Check whether the selection fits within the extent, with the current - offset defined. - USAGE - htri_t H5S__hyper_is_valid(space); - H5S_t *space; IN: Dataspace pointer to query - RETURNS - TRUE if the selection fits within the extent, FALSE if it does not and - Negative on an error. - DESCRIPTION - Determines if the current selection at the current offset fits within the - extent for the dataspace. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static htri_t -H5S__hyper_is_valid(const H5S_t *space) -{ - htri_t ret_value = TRUE; /* return value */ + /* Make certain this entire row will fit into buffer */ + fast_dim_count = MIN(fast_dim_count, tot_blk_count); - FUNC_ENTER_STATIC_NOERR + /* Number of blocks to sequence over */ + act_blk_count = fast_dim_count; - HDassert(space); + /* Loop over all the blocks in the fastest changing dimension */ + while(fast_dim_count > 0) { + /* Store the sequence information */ + off[curr_seq] = loc; + len[curr_seq] = actual_bytes; - /* Check for unlimited selection */ - if(space->select.sel_info.hslab->unlim_dim >= 0) - HGOTO_DONE(FALSE) + /* Increment sequence count */ + curr_seq++; - /* Check for a "regular" hyperslab selection */ - if(H5S_DIMINFO_VALID_YES == space->select.sel_info.hslab->diminfo_valid) { - const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->diminfo.opt; /* local alias for diminfo */ - hssize_t end; /* The high bound of a region in a dimension */ - unsigned u; /* Counter */ + /* Increment information to reflect block just processed */ + loc += fast_dim_buf_off; - /* Check each dimension */ - for(u = 0; u < space->extent.rank; u++) { - /* if block or count is zero, then can skip the test since */ - /* no data point is chosen */ - if(diminfo[u].count && diminfo[u].block) { - /* Bounds check the start point in this dimension */ - if(((hssize_t)diminfo[u].start + space->select.offset[u]) < 0 || - ((hssize_t)diminfo[u].start + space->select.offset[u]) >= (hssize_t)space->extent.size[u]) - HGOTO_DONE(FALSE) + /* Decrement number of blocks */ + fast_dim_count--; + } /* end while */ - /* Compute the largest location in this dimension */ - end = (hssize_t)(diminfo[u].start + diminfo[u].stride * (diminfo[u].count - 1) + (diminfo[u].block - 1)) + space->select.offset[u]; + /* Decrement number of elements left */ + io_left -= actual_elem * act_blk_count; - /* Bounds check the end point in this dimension */ - if(end < 0 || end >= (hssize_t)space->extent.size[u]) - HGOTO_DONE(FALSE) - } /* end if */ - } /* end for */ - } /* end if */ - else - /* Call the recursive routine to validate the span tree */ - ret_value = H5S__hyper_is_valid_helper(space->select.sel_info.hslab->span_lst, space->select.offset, space->extent.size); + /* Decrement number of blocks left */ + tot_blk_count -= act_blk_count; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_is_valid() */ + /* Increment information to reflect block just processed */ + tmp_count[fast_dim] += act_blk_count; - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_span_nblocks - PURPOSE - Count the number of blocks in a span tree - USAGE - hsize_t H5S__hyper_span_nblocks(spans) - const H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to count elements of + /* Check if we finished the entire row of blocks */ + if(tmp_count[fast_dim] >= tdiminfo[fast_dim].count) { + /* Increment offset in destination buffer */ + loc += wrap[fast_dim]; + + /* Increment information to reflect block just processed */ + offset[fast_dim] = fast_dim_offset; /* reset the offset in the fastest dimension */ + tmp_count[fast_dim] = 0; + + /* Increment the offset and count for the other dimensions */ + temp_dim = (int)fast_dim - 1; + while(temp_dim >= 0) { + /* Move to the next row in the curent dimension */ + offset[temp_dim]++; + tmp_block[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_block[temp_dim] < tdiminfo[temp_dim].block) + break; + else { + /* Move to the next block in the current dimension */ + offset[temp_dim] += (tdiminfo[temp_dim].stride - tdiminfo[temp_dim].block); + loc += skip[temp_dim]; + tmp_block[temp_dim] = 0; + tmp_count[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_count[temp_dim] < tdiminfo[temp_dim].count) + break; + else { + offset[temp_dim] = (hsize_t)((hssize_t)tdiminfo[temp_dim].start + sel_off[temp_dim]); + loc += wrap[temp_dim]; + tmp_count[temp_dim] = 0; /* reset back to the beginning of the line */ + tmp_block[temp_dim] = 0; + } /* end else */ + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + } /* end if */ + else { + /* Update the offset in the fastest dimension */ + offset[fast_dim] += (fast_dim_stride * act_blk_count); + } /* end else */ + } /* end if */ + + /* Compute the number of entire rows to read in */ + H5_CHECK_OVERFLOW(tot_blk_count / tdiminfo[fast_dim].count, hsize_t, size_t); + curr_rows = total_rows = (size_t)(tot_blk_count / tdiminfo[fast_dim].count); + + /* Reset copy of number of blocks in fastest dimension */ + H5_CHECKED_ASSIGN(fast_dim_count, size_t, tdiminfo[fast_dim].count, hsize_t); + + /* Read in data until an entire sequence can't be written out any longer */ + while(curr_rows > 0) { + +#define DUFF_GUTS \ +/* Store the sequence information */ \ +off[curr_seq] = loc; \ +len[curr_seq] = actual_bytes; \ + \ +/* Increment sequence count */ \ +curr_seq++; \ + \ +/* Increment information to reflect block just processed */ \ +loc += fast_dim_buf_off; + +#ifdef NO_DUFFS_DEVICE + /* Loop over all the blocks in the fastest changing dimension */ + while(fast_dim_count > 0) { + DUFF_GUTS + + /* Decrement number of blocks */ + fast_dim_count--; + } /* end while */ +#else /* NO_DUFFS_DEVICE */ + { + size_t duffs_index; /* Counting index for Duff's device */ + + duffs_index = (fast_dim_count + 7) / 8; + switch (fast_dim_count % 8) { + default: + HDassert(0 && "This Should never be executed!"); + break; + case 0: + do + { + DUFF_GUTS + H5_ATTR_FALLTHROUGH + case 7: + DUFF_GUTS + H5_ATTR_FALLTHROUGH + case 6: + DUFF_GUTS + H5_ATTR_FALLTHROUGH + case 5: + DUFF_GUTS + H5_ATTR_FALLTHROUGH + case 4: + DUFF_GUTS + H5_ATTR_FALLTHROUGH + case 3: + DUFF_GUTS + H5_ATTR_FALLTHROUGH + case 2: + DUFF_GUTS + H5_ATTR_FALLTHROUGH + case 1: + DUFF_GUTS + } while (--duffs_index > 0); + } /* end switch */ + } +#endif /* NO_DUFFS_DEVICE */ +#undef DUFF_GUTS + + /* Increment offset in destination buffer */ + loc += wrap[fast_dim]; + + /* Increment the offset and count for the other dimensions */ + temp_dim = (int)fast_dim - 1; + while(temp_dim >= 0) { + /* Move to the next row in the curent dimension */ + offset[temp_dim]++; + tmp_block[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_block[temp_dim] < tdiminfo[temp_dim].block) + break; + else { + /* Move to the next block in the current dimension */ + offset[temp_dim] += (tdiminfo[temp_dim].stride - tdiminfo[temp_dim].block); + loc += skip[temp_dim]; + tmp_block[temp_dim] = 0; + tmp_count[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_count[temp_dim] < tdiminfo[temp_dim].count) + break; + else { + offset[temp_dim] = (hsize_t)((hssize_t)tdiminfo[temp_dim].start + sel_off[temp_dim]); + loc += wrap[temp_dim]; + tmp_count[temp_dim] = 0; /* reset back to the beginning of the line */ + tmp_block[temp_dim] = 0; + } /* end else */ + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + + /* Decrement the number of rows left */ + curr_rows--; + } /* end while */ + + /* Adjust the number of blocks & elements left to transfer */ + + /* Decrement number of elements left */ + H5_CHECK_OVERFLOW(actual_elem * (total_rows * tdiminfo[fast_dim].count), hsize_t, size_t); + io_left -= (size_t)(actual_elem * (total_rows * tdiminfo[fast_dim].count)); + + /* Decrement number of blocks left */ + H5_CHECK_OVERFLOW((total_rows * tdiminfo[fast_dim].count), hsize_t, size_t); + tot_blk_count -= (size_t)(total_rows * tdiminfo[fast_dim].count); + + /* Read in partial row of blocks */ + if(io_left > 0 && curr_seq < maxseq) { + /* Get remaining number of blocks left to output */ + fast_dim_count = tot_blk_count; + + /* Loop over all the blocks in the fastest changing dimension */ + while(fast_dim_count > 0) { + /* Store the sequence information */ + off[curr_seq] = loc; + len[curr_seq] = actual_bytes; + + /* Increment sequence count */ + curr_seq++; + + /* Increment information to reflect block just processed */ + loc += fast_dim_buf_off; + + /* Decrement number of blocks */ + fast_dim_count--; + } /* end while */ + + /* Decrement number of elements left */ + io_left -= actual_elem * tot_blk_count; + + /* Increment information to reflect block just processed */ + offset[fast_dim] += (fast_dim_stride * tot_blk_count); /* move the offset in the fastest dimension */ + + /* Handle any leftover, partial blocks in this row */ + if(io_left > 0 && curr_seq < maxseq) { + actual_elem = io_left; + actual_bytes = actual_elem * elem_size; + + /* Store the sequence information */ + off[curr_seq] = loc; + len[curr_seq] = actual_bytes; + + /* Increment sequence count */ + curr_seq++; + + /* Decrement the number of elements left */ + io_left -= actual_elem; + + /* Increment buffer correctly */ + offset[fast_dim] += actual_elem; + } /* end if */ + + /* don't bother checking slower dimensions */ + HDassert(io_left == 0 || curr_seq == maxseq); + } /* end if */ + + /* Update the iterator */ + + /* Update the iterator with the location we stopped */ + /* (Subtract out the selection offset) */ + for(u = 0; u < ndims; u++) + iter->u.hyp.off[u] = (hsize_t)((hssize_t)offset[u] - sel_off[u]); + + /* Decrement the number of elements left in selection */ + iter->elmt_left -= (start_io_left - io_left); + + /* Increment the number of sequences generated */ + *nseq += curr_seq; + + /* Increment the number of elements used */ + *nelem += start_io_left - io_left; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_iter_get_seq_list_opt() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_iter_get_seq_list_single + PURPOSE + Create a list of offsets & lengths for a selection + USAGE + herr_t H5S__hyper_iter_get_seq_list_single(flags, iter, maxseq, maxelem, nseq, nelem, off, len) + unsigned flags; IN: Flags for extra information about operation + H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last + position of interest in selection. + size_t maxseq; IN: Maximum number of sequences to generate + size_t maxelem; IN: Maximum number of elements to include in the + generated sequences + size_t *nseq; OUT: Actual number of sequences generated + size_t *nelem; OUT: Actual number of elements in sequences generated + hsize_t *off; OUT: Array of offsets + size_t *len; OUT: Array of lengths + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + Use the selection in the dataspace to generate a list of byte offsets and + lengths for the region(s) selected. Start/Restart from the position in the + ITER parameter. The number of sequences generated is limited by the MAXSEQ + parameter and the number of sequences actually generated is stored in the + NSEQ parameter. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_iter_get_seq_list_single(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem, + size_t *nseq, size_t *nelem, hsize_t *off, size_t *len) +{ + const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ + const hssize_t *sel_off; /* Selection offset in dataspace */ + hsize_t *mem_size; /* Size of the source buffer */ + hsize_t base_offset[H5S_MAX_RANK]; /* Base coordinate offset in dataspace */ + hsize_t offset[H5S_MAX_RANK]; /* Coordinate offset in dataspace */ + hsize_t *slab; /* Hyperslab size */ + hsize_t fast_dim_block; /* Local copies of fastest changing dimension info */ + hsize_t loc; /* Coordinate offset */ + size_t tot_blk_count; /* Total number of blocks left to output */ + size_t elem_size; /* Size of each element iterating over */ + size_t io_left; /* The number of elements left in I/O operation */ + size_t actual_elem; /* The actual number of elements to count */ + unsigned ndims; /* Number of dimensions of dataset */ + unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + unsigned skip_dim; /* Rank of the dimension to skip along */ + unsigned u; /* Local index variable */ + + FUNC_ENTER_STATIC_NOERR + + /* Check args */ + HDassert(iter); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); + + /* Set a local copy of the diminfo pointer */ + tdiminfo = iter->u.hyp.diminfo; + + /* Check if this is a "flattened" regular hyperslab selection */ + if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank) { + /* Set the aliases for a few important dimension ranks */ + ndims = iter->u.hyp.iter_rank; + + /* Set the local copy of the selection offset */ + sel_off = iter->u.hyp.sel_off; + + /* Set up the pointer to the size of the memory dataspace */ + mem_size = iter->u.hyp.size; + } /* end if */ + else { + /* Set the aliases for a few important dimension ranks */ + ndims = iter->rank; + + /* Set the local copy of the selection offset */ + sel_off = iter->sel_off; + + /* Set up the pointer to the size of the memory dataspace */ + mem_size = iter->dims; + } /* end else */ + + /* Set up some local variables */ + fast_dim = ndims - 1; + elem_size = iter->elmt_size; + slab = iter->u.hyp.slab; + + /* Copy the base location of the block */ + /* (Add in the selection offset) */ + for(u = 0; u < ndims; u++) + base_offset[u] = (hsize_t)((hssize_t)tdiminfo[u].start + sel_off[u]); + + /* Copy the location of the point to get */ + /* (Add in the selection offset) */ + for(u = 0; u < ndims; u++) + offset[u] = (hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u]); + + /* Compute the initial buffer offset */ + for(u = 0, loc = 0; u < ndims; u++) + loc += offset[u] * slab[u]; + + /* Set local copies of information for the fastest changing dimension */ + fast_dim_block = tdiminfo[fast_dim].block; + + /* Calculate the number of elements to sequence through */ + H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t); + io_left = MIN((size_t)iter->elmt_left, maxelem); + + /* Compute the number of blocks which would fit into the buffer */ + H5_CHECK_OVERFLOW(io_left / fast_dim_block, hsize_t, size_t); + tot_blk_count = (size_t)(io_left / fast_dim_block); + + /* Don't go over the maximum number of sequences allowed */ + tot_blk_count = MIN(tot_blk_count, maxseq); + + /* Set the number of elements to write each time */ + H5_CHECKED_ASSIGN(actual_elem, size_t, fast_dim_block, hsize_t); + + /* Check for blocks to operate on */ + if(tot_blk_count > 0) { + size_t actual_bytes; /* The actual number of bytes to copy */ + + /* Set the number of actual bytes */ + actual_bytes = actual_elem * elem_size; + + /* Check for 1-dim selection */ + if(0 == fast_dim) { + /* Sanity checks */ + HDassert(1 == tot_blk_count); + HDassert(io_left == actual_elem); + + /* Store the sequence information */ + *off++ = loc; + *len++ = actual_bytes; + } /* end if */ + else { + hsize_t skip_slab; /* Temporary copy of slab[fast_dim - 1] */ + size_t blk_count; /* Total number of blocks left to output */ + int i; /* Local index variable */ + + /* Find first dimension w/block >1 */ + skip_dim = fast_dim; + for(i = (int)(fast_dim - 1); i >= 0; i--) + if(tdiminfo[i].block > 1) { + skip_dim = (unsigned)i; + break; + } /* end if */ + skip_slab = slab[skip_dim]; + + /* Check for being able to use fast algorithm for 1-D */ + if(0 == skip_dim) { + /* Create sequences until an entire row can't be used */ + blk_count = tot_blk_count; + while(blk_count > 0) { + /* Store the sequence information */ + *off++ = loc; + *len++ = actual_bytes; + + /* Increment offset in destination buffer */ + loc += skip_slab; + + /* Decrement block count */ + blk_count--; + } /* end while */ + + /* Move to the next location */ + offset[skip_dim] += tot_blk_count; + } /* end if */ + else { + hsize_t tmp_block[H5S_MAX_RANK]; /* Temporary block offset */ + hsize_t skip[H5S_MAX_RANK]; /* Bytes to skip between blocks */ + int temp_dim; /* Temporary rank holder */ + + /* Set the starting block location */ + for(u = 0; u < ndims; u++) + tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start; + + /* Compute the amount to skip between sequences */ + for(u = 0; u < ndims; u++) + skip[u] = (mem_size[u] - tdiminfo[u].block) * slab[u]; + + /* Create sequences until an entire row can't be used */ + blk_count = tot_blk_count; + while(blk_count > 0) { + /* Store the sequence information */ + *off++ = loc; + *len++ = actual_bytes; + + /* Set temporary dimension for advancing offsets */ + temp_dim = (int)skip_dim; + + /* Increment offset in destination buffer */ + loc += skip_slab; + + /* Increment the offset and count for the other dimensions */ + while(temp_dim >= 0) { + /* Move to the next row in the curent dimension */ + offset[temp_dim]++; + tmp_block[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_block[temp_dim] < tdiminfo[temp_dim].block) + break; + else { + offset[temp_dim] = base_offset[temp_dim]; + loc += skip[temp_dim]; + tmp_block[temp_dim] = 0; + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + + /* Decrement block count */ + blk_count--; + } /* end while */ + } /* end else */ + } /* end else */ + + /* Update the iterator, if there were any blocks used */ + + /* Decrement the number of elements left in selection */ + iter->elmt_left -= tot_blk_count * actual_elem; + + /* Check if there are elements left in iterator */ + if(iter->elmt_left > 0) { + /* Update the iterator with the location we stopped */ + /* (Subtract out the selection offset) */ + for(u = 0; u < ndims; u++) + iter->u.hyp.off[u] = (hsize_t)((hssize_t)offset[u] - sel_off[u]); + } /* end if */ + + /* Increment the number of sequences generated */ + *nseq += tot_blk_count; + + /* Increment the number of elements used */ + *nelem += tot_blk_count * actual_elem; + } /* end if */ + + /* Check for partial block, with room for another sequence */ + if(io_left > (tot_blk_count * actual_elem) && tot_blk_count < maxseq) { + size_t elmt_remainder; /* Elements remaining */ + + /* Compute elements left */ + elmt_remainder = io_left - (tot_blk_count * actual_elem); + HDassert(elmt_remainder < fast_dim_block); + HDassert(elmt_remainder > 0); + + /* Store the sequence information */ + *off++ = loc; + *len++ = elmt_remainder * elem_size; + + /* Update the iterator with the location we stopped */ + iter->u.hyp.off[fast_dim] += (hsize_t)elmt_remainder; + + /* Decrement the number of elements left in selection */ + iter->elmt_left -= elmt_remainder; + + /* Increment the number of sequences generated */ + (*nseq)++; + + /* Increment the number of elements used */ + *nelem += elmt_remainder; + } /* end if */ + + /* Sanity check */ + HDassert(*nseq > 0); + HDassert(*nelem > 0); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_iter_get_seq_list_single() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_iter_get_seq_list + PURPOSE + Create a list of offsets & lengths for a selection + USAGE + herr_t H5S__hyper_iter_get_seq_list(iter,maxseq,maxelem,nseq,nelem,off,len) + H5S_t *space; IN: Dataspace containing selection to use. + H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last + position of interest in selection. + size_t maxseq; IN: Maximum number of sequences to generate + size_t maxelem; IN: Maximum number of elements to include in the + generated sequences + size_t *nseq; OUT: Actual number of sequences generated + size_t *nelem; OUT: Actual number of elements in sequences generated + hsize_t *off; OUT: Array of offsets (in bytes) + size_t *len; OUT: Array of lengths (in bytes) + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + Use the selection in the dataspace to generate a list of byte offsets and + lengths for the region(s) selected. Start/Restart from the position in the + ITER parameter. The number of sequences generated is limited by the MAXSEQ + parameter and the number of sequences actually generated is stored in the + NSEQ parameter. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq, + size_t maxelem, size_t *nseq, size_t *nelem, hsize_t *off, size_t *len) +{ + herr_t ret_value = FAIL; /* return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check args */ + HDassert(iter); + HDassert(iter->elmt_left > 0); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); + + /* Check for the special case of just one H5Sselect_hyperslab call made */ + if(iter->u.hyp.diminfo_valid) { + const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ + const hssize_t *sel_off; /* Selection offset in dataspace */ + unsigned ndims; /* Number of dimensions of dataset */ + unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + hbool_t single_block; /* Whether the selection is a single block */ + unsigned u; /* Local index variable */ + + /* Set a local copy of the diminfo pointer */ + tdiminfo = iter->u.hyp.diminfo; + + /* Check if this is a "flattened" regular hyperslab selection */ + if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank) { + /* Set the aliases for a few important dimension ranks */ + ndims = iter->u.hyp.iter_rank; + + /* Set the local copy of the selection offset */ + sel_off = iter->u.hyp.sel_off; + } /* end if */ + else { + /* Set the aliases for a few important dimension ranks */ + ndims = iter->rank; + + /* Set the local copy of the selection offset */ + sel_off = iter->sel_off; + } /* end else */ + fast_dim = ndims - 1; + + /* Check if we stopped in the middle of a sequence of elements */ + if((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride != 0 || + ((iter->u.hyp.off[fast_dim] != tdiminfo[fast_dim].start) && tdiminfo[fast_dim].count == 1)) { + hsize_t *slab; /* Hyperslab size */ + hsize_t loc; /* Coordinate offset */ + size_t leftover; /* The number of elements left over from the last sequence */ + size_t actual_elem; /* The actual number of elements to count */ + size_t elem_size; /* Size of each element iterating over */ + + /* Calculate the number of elements left in the sequence */ + if(tdiminfo[fast_dim].count == 1) { + H5_CHECKED_ASSIGN(leftover, size_t, tdiminfo[fast_dim].block - (iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start), hsize_t); + } /* end if */ + else { + H5_CHECKED_ASSIGN(leftover, size_t, tdiminfo[fast_dim].block - ((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride), hsize_t); + } /* end else */ + + /* Make certain that we don't write too many */ + actual_elem = MIN3(leftover, (size_t)iter->elmt_left, maxelem); + + /* Set up some local variables */ + elem_size = iter->elmt_size; + slab = iter->u.hyp.slab; + + /* Compute the initial buffer offset */ + for(u = 0, loc = 0; u < ndims; u++) + loc += ((hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u])) * slab[u]; + + /* Add a new sequence */ + off[0] = loc; + H5_CHECKED_ASSIGN(len[0], size_t, actual_elem * elem_size, hsize_t); + + /* Increment sequence array locations */ + off++; + len++; + + /* Advance the hyperslab iterator */ + H5S__hyper_iter_next(iter, actual_elem); + + /* Decrement the number of elements left in selection */ + iter->elmt_left -= actual_elem; + + /* Decrement element/sequence limits */ + maxelem -= actual_elem; + maxseq--; + + /* Set the number of sequences generated and elements used */ + *nseq = 1; + *nelem = actual_elem; + + /* Check for using up all the sequences/elements */ + if(0 == iter->elmt_left || 0 == maxelem || 0 == maxseq) + return(SUCCEED); + } /* end if */ + else { + /* Reset the number of sequences generated and elements used */ + *nseq = 0; + *nelem = 0; + } /* end else */ + + /* Check for a single block selected */ + single_block = TRUE; + for(u = 0; u < ndims; u++) + if(1 != tdiminfo[u].count) { + single_block = FALSE; + break; + } /* end if */ + + /* Check for single block selection */ + if(single_block) + /* Use single-block optimized call to generate sequence list */ + ret_value = H5S__hyper_iter_get_seq_list_single(iter, maxseq, maxelem, nseq, nelem, off, len); + else + /* Use optimized call to generate sequence list */ + ret_value = H5S__hyper_iter_get_seq_list_opt(iter, maxseq, maxelem, nseq, nelem, off, len); + } /* end if */ + else + /* Call the general sequence generator routine */ + ret_value = H5S__hyper_iter_get_seq_list_gen(iter, maxseq, maxelem, nseq, nelem, off, len); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_iter_get_seq_list() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_iter_release + PURPOSE + Release hyperslab selection iterator information for a dataspace + USAGE + herr_t H5S__hyper_iter_release(iter) + H5S_sel_iter_t *iter; IN: Pointer to selection iterator + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Releases all information for a dataspace hyperslab selection iterator + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_iter_release(H5S_sel_iter_t *iter) +{ + FUNC_ENTER_STATIC_NOERR + + /* Check args */ + HDassert(iter); + + /* Free the copy of the hyperslab selection span tree */ + if(iter->u.hyp.spans != NULL) + H5S__hyper_free_span_info(iter->u.hyp.spans); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_iter_release() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_new_span + PURPOSE + Make a new hyperslab span node + USAGE + H5S_hyper_span_t *H5S__hyper_new_span(low, high, down, next) + hsize_t low, high; IN: Low and high bounds for new span node + H5S_hyper_span_info_t *down; IN: Down span tree for new node + H5S_hyper_span_t *next; IN: Next span for new node RETURNS - Number of blocks in span tree on success; negative on failure + Pointer to new span node on success, NULL on failure DESCRIPTION - Counts the number of blocks described by the spans in a span tree. + Allocate and initialize a new hyperslab span node, filling in the low & + high bounds, the down span and next span pointers also. Increment the + reference count of the 'down span' if applicable. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static hsize_t -H5S__hyper_span_nblocks(const H5S_hyper_span_info_t *spans) +static H5S_hyper_span_t * +H5S__hyper_new_span(hsize_t low, hsize_t high, H5S_hyper_span_info_t *down, + H5S_hyper_span_t *next) { - hsize_t ret_value = 0; /* Return value */ + H5S_hyper_span_t *ret_value = NULL; /* Return value */ - FUNC_ENTER_STATIC_NOERR + FUNC_ENTER_STATIC - /* Count the number of elements in the span tree */ - if(spans != NULL) { - H5S_hyper_span_t *span; /* Hyperslab span */ + /* Allocate a new span node */ + if(NULL == (ret_value = H5FL_MALLOC(H5S_hyper_span_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") + + /* Copy the span's basic information */ + ret_value->low = low; + ret_value->high = high; + ret_value->down = down; + ret_value->next = next; + + /* Increment the reference count of the 'down span' if there is one */ + if(ret_value->down) + ret_value->down->count++; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_new_span() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_new_span_info + PURPOSE + Make a new hyperslab span info node + USAGE + H5S_hyper_span_info_t *H5S__hyper_new_span_info(rank) + unsigned rank; IN: Rank of span info, in selection + RETURNS + Pointer to new span node info on success, NULL on failure + DESCRIPTION + Allocate and initialize a new hyperslab span info node of a given rank, + setting up the low & high bound array pointers. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Note that this uses the C99 "flexible array member" feature. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static H5S_hyper_span_info_t * +H5S__hyper_new_span_info(unsigned rank) +{ + H5S_hyper_span_info_t *ret_value = NULL; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity check */ + HDassert(rank > 0); + HDassert(rank <= H5S_MAX_RANK); + + /* Allocate a new span info node */ + if(NULL == (ret_value = (H5S_hyper_span_info_t *)H5FL_ARR_CALLOC(hbounds_t, rank * 2))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span info") + + /* Set low & high bound pointers into the 'bounds' array */ + ret_value->low_bounds = ret_value->bounds; + ret_value->high_bounds = &ret_value->bounds[rank]; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_new_span_info() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_copy_span_helper + PURPOSE + Helper routine to copy a hyperslab span tree + USAGE + H5S_hyper_span_info_t * H5S__hyper_copy_span_helper(spans, rank, op_info_i, op_gen) + H5S_hyper_span_info_t *spans; IN: Span tree to copy + unsigned rank; IN: Rank of span tree + unsigned op_info_i; IN: Index of op info to use + uint64_t op_gen; IN: Operation generation + RETURNS + Pointer to the copied span tree on success, NULL on failure + DESCRIPTION + Copy a hyperslab span tree, using reference counting as appropriate. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static H5S_hyper_span_info_t * +H5S__hyper_copy_span_helper(H5S_hyper_span_info_t *spans, unsigned rank, + unsigned op_info_i, uint64_t op_gen) +{ + H5S_hyper_span_t *span; /* Hyperslab span */ + H5S_hyper_span_t *new_span; /* Temporary hyperslab span */ + H5S_hyper_span_t *prev_span; /* Previous hyperslab span */ + H5S_hyper_span_info_t *new_down; /* New down span tree */ + H5S_hyper_span_info_t *ret_value = NULL; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(spans); + + /* Check if the span tree was already copied */ + if(spans->op_info[op_info_i].op_gen == op_gen) { + /* Just return the value of the already copied span tree */ + ret_value = spans->op_info[op_info_i].u.copied; + + /* Increment the reference count of the span tree */ + ret_value->count++; + } /* end if */ + else { + /* Allocate a new span_info node */ + if(NULL == (ret_value = H5S__hyper_new_span_info(rank))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span info") + + /* Set the non-zero span_info information */ + H5MM_memcpy(ret_value->low_bounds, spans->low_bounds, rank * sizeof(hsize_t)); + H5MM_memcpy(ret_value->high_bounds, spans->high_bounds, rank * sizeof(hsize_t)); + ret_value->count = 1; + + /* Set the operation generation for the span info, to avoid future copies */ + spans->op_info[op_info_i].op_gen = op_gen; + /* Set the 'copied' pointer in the node being copied to the newly allocated node */ + spans->op_info[op_info_i].u.copied = ret_value; + + /* Copy over the nodes in the span list */ span = spans->head; + prev_span = NULL; while(span != NULL) { - /* If there are down spans, add the total down span blocks */ - if(span->down != NULL) - ret_value += H5S__hyper_span_nblocks(span->down); - /* If there are no down spans, just count the block in this span */ + /* Allocate a new node */ + if(NULL == (new_span = H5S__hyper_new_span(span->low, span->high, NULL, NULL))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") + + /* Append to list of spans */ + if(NULL == prev_span) + ret_value->head = new_span; else - ret_value++; + prev_span->next = new_span; + + /* Recurse to copy the 'down' spans, if there are any */ + if(span->down != NULL) { + if(NULL == (new_down = H5S__hyper_copy_span_helper(span->down, rank - 1, op_info_i, op_gen))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy hyperslab spans") + new_span->down = new_down; + } /* end if */ + + /* Update the previous (new) span */ + prev_span = new_span; /* Advance to next span */ span = span->next; } /* end while */ + + /* Retain a pointer to the last span */ + ret_value->tail = prev_span; } /* end else */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_copy_span_helper() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_copy_span + PURPOSE + Copy a hyperslab span tree + USAGE + H5S_hyper_span_info_t * H5S__hyper_copy_span(span_info, rank) + H5S_hyper_span_info_t *span_info; IN: Span tree to copy + unsigned rank; IN: Rank of span tree + RETURNS + Pointer to the copied span tree on success, NULL on failure + DESCRIPTION + Copy a hyperslab span tree, using reference counting as appropriate. + (Which means that just the nodes in the top span tree are duplicated and + the reference counts of their 'down spans' are just incremented) + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static H5S_hyper_span_info_t * +H5S__hyper_copy_span(H5S_hyper_span_info_t *spans, unsigned rank) +{ + uint64_t op_gen; /* Operation generation value */ + H5S_hyper_span_info_t *ret_value = NULL; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity check */ + HDassert(spans); + + /* Acquire an operation generation value for this operation */ + op_gen = H5S__hyper_get_op_gen(); + + /* Copy the hyperslab span tree */ + /* Always use op_info[0] since we own this op_info, so there can be no + * simultaneous operations */ + if(NULL == (ret_value = H5S__hyper_copy_span_helper(spans, rank, 0, op_gen))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_copy_span() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_cmp_spans + PURPOSE + Check if two hyperslab span trees are the same + USAGE + hbool_t H5S__hyper_cmp_spans(span1, span2) + H5S_hyper_span_info_t *span_info1; IN: First span tree to compare + H5S_hyper_span_info_t *span_info2; IN: Second span tree to compare + RETURNS + TRUE (1) or FALSE (0) on success, can't fail + DESCRIPTION + Compare two hyperslab span trees to determine if they refer to the same + selection. If span1 & span2 are both NULL, that counts as equal. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static H5_ATTR_PURE hbool_t +H5S__hyper_cmp_spans(const H5S_hyper_span_info_t *span_info1, const H5S_hyper_span_info_t *span_info2) +{ + hbool_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check for redundant comparison (or both spans being NULL) */ + if(span_info1 != span_info2) { + /* Check for one span being NULL */ + if(span_info1 == NULL || span_info2 == NULL) + HGOTO_DONE(FALSE) + else { + /* Compare low & high bounds for this span list */ + /* (Could compare lower dimensions also, but not certain if + * that's worth it. - QAK, 2019/01/23) + */ + if(span_info1->low_bounds[0] != span_info2->low_bounds[0]) + HGOTO_DONE(FALSE) + else if(span_info1->high_bounds[0] != span_info2->high_bounds[0]) + HGOTO_DONE(FALSE) + else { + const H5S_hyper_span_t *span1; + const H5S_hyper_span_t *span2; + + /* Get the pointers to the actual lists of spans */ + span1 = span_info1->head; + span2 = span_info2->head; + + /* Sanity checking */ + HDassert(span1); + HDassert(span2); + + /* infinite loop which must be broken out of */ + while(1) { + /* Check for both spans being NULL */ + if(span1 == NULL && span2 == NULL) + HGOTO_DONE(TRUE) + else { + /* Check for one span being NULL */ + if(span1 == NULL || span2 == NULL) + HGOTO_DONE(FALSE) + else { + /* Check if the actual low & high span information is the same */ + if(span1->low != span2->low || span1->high != span2->high) + HGOTO_DONE(FALSE) + else { + if(span1->down != NULL || span2->down != NULL) { + if(!H5S__hyper_cmp_spans(span1->down, span2->down)) + HGOTO_DONE(FALSE) + else { + /* Keep going... */ + } /* end else */ + } /* end if */ + else { + /* Keep going... */ + } /* end else */ + } /* end else */ + } /* end else */ + } /* end else */ + + /* Advance to the next nodes in the span list */ + span1 = span1->next; + span2 = span2->next; + } /* end while */ + } /* end else */ + } /* end else */ + } /* end if */ + + /* Fall through, with default return value of 'TRUE' if spans were already visited */ + +done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_span_nblocks() */ +} /* end H5S__hyper_cmp_spans() */ /*-------------------------------------------------------------------------- NAME - H5S__get_select_hyper_nblocks + H5S__hyper_free_span_info PURPOSE - Get the number of hyperslab blocks in current hyperslab selection + Free a hyperslab span info node USAGE - hsize_t H5S__get_select_hyper_nblocks(space, app_ref) - H5S_t *space; IN: Dataspace ptr of selection to query - hbool_t app_ref; IN: Whether this is an appl. ref. call + void H5S__hyper_free_span_info(span_info) + H5S_hyper_span_info_t *span_info; IN: Span info node to free RETURNS - The number of hyperslab blocks in selection on success, negative on failure + None DESCRIPTION - Returns the number of hyperslab blocks in current selection for dataspace. + Free a hyperslab span info node, along with all the span nodes and the + 'down spans' from the nodes, if reducing their reference count to zero + indicates it is appropriate to do so. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static hsize_t -H5S__get_select_hyper_nblocks(const H5S_t *space, hbool_t app_ref) +static void +H5S__hyper_free_span_info(H5S_hyper_span_info_t *span_info) { - hsize_t ret_value = 0; /* Return value */ - FUNC_ENTER_STATIC_NOERR - HDassert(space); - HDassert(space->select.sel_info.hslab->unlim_dim < 0); + /* Sanity check */ + HDassert(span_info); - /* Check for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { - unsigned u; /* Local index variable */ + /* Decrement the span tree's reference count */ + span_info->count--; - /* Check each dimension */ - for(ret_value = 1, u = 0; u < space->extent.rank; u++) - ret_value *= (app_ref ? space->select.sel_info.hslab->diminfo.app[u].count : - space->select.sel_info.hslab->diminfo.opt[u].count); + /* Free the span tree if the reference count drops to zero */ + if(span_info->count == 0) { + H5S_hyper_span_t *span; /* Pointer to spans to iterate over */ + + /* Work through the list of spans pointed to by this 'info' node */ + span = span_info->head; + while(span != NULL) { + H5S_hyper_span_t *next_span; /* Pointer to next span to iterate over */ + + /* Keep a pointer to the next span */ + next_span = span->next; + + /* Free the current span */ + H5S__hyper_free_span(span); + + /* Advance to next span */ + span = next_span; + } /* end while */ + + /* Free this span info */ + span_info = (H5S_hyper_span_info_t *)H5FL_ARR_FREE(hbounds_t, span_info); } /* end if */ - else - ret_value = H5S__hyper_span_nblocks(space->select.sel_info.hslab->span_lst); - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__get_select_hyper_nblocks() */ + FUNC_LEAVE_NOAPI_VOID +} /* end H5S__hyper_free_span_info() */ /*-------------------------------------------------------------------------- NAME - H5Sget_select_hyper_nblocks + H5S__hyper_free_span PURPOSE - Get the number of hyperslab blocks in current hyperslab selection + Free a hyperslab span node USAGE - hssize_t H5Sget_select_hyper_nblocks(dsid) - hid_t dsid; IN: Dataspace ID of selection to query + void H5S__hyper_free_span(span) + H5S_hyper_span_t *span; IN: Span node to free RETURNS - The number of hyperslab blocks in selection on success, negative on failure + None DESCRIPTION - Returns the number of hyperslab blocks in current selection for dataspace. + Free a hyperslab span node, along with the 'down spans' from the node, + if reducing their reference count to zero indicates it is appropriate to + do so. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -hssize_t -H5Sget_select_hyper_nblocks(hid_t spaceid) +static void +H5S__hyper_free_span(H5S_hyper_span_t *span) { - H5S_t *space; /* Dataspace to modify selection of */ - hssize_t ret_value; /* return value */ + FUNC_ENTER_STATIC_NOERR - FUNC_ENTER_API(FAIL) - H5TRACE1("Hs", "i", spaceid); + /* Sanity check */ + HDassert(span); - /* Check args */ - if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") - if(H5S_GET_SELECT_TYPE(space) != H5S_SEL_HYPERSLABS) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection") - if(space->select.sel_info.hslab->unlim_dim >= 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot get number of blocks for unlimited selection") + /* Decrement the reference count of the 'down spans', freeing them if appropriate */ + if(span->down != NULL) + H5S__hyper_free_span_info(span->down); - ret_value = (hssize_t)H5S__get_select_hyper_nblocks(space, TRUE); + /* Free this span */ + span = H5FL_FREE(H5S_hyper_span_t, span); -done: - FUNC_LEAVE_API(ret_value) -} /* end H5Sget_select_hyper_nblocks() */ + FUNC_LEAVE_NOAPI_VOID +} /* end H5S__hyper_free_span() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_get_version_enc_size + H5S__hyper_copy PURPOSE - Determine the version and encoded size to use for encoding hyperslab selection info - See tables 2 & 3 in the RFC: H5Sencode/H5Sdecode Format Change + Copy a selection from one dataspace to another USAGE - hssize_t H5S__hyper_get_version_enc_size(space, block_count, version, enc_size) - const H5S_t *space: IN: The dataspace - hsize_t block_count: IN: The number of blocks in the selection - uint32_t *version: OUT: The version to use for encoding - uint8_t *enc_size: OUT: The encoded size to use - + herr_t H5S__hyper_copy(dst, src, share_selection) + H5S_t *dst; OUT: Pointer to the destination dataspace + H5S_t *src; IN: Pointer to the source dataspace + hbool_t; IN: Whether to share the selection between the dataspaces RETURNS - The version and the size to encode hyperslab selection info + Non-negative on success, negative on failure DESCRIPTION - Determine the version to use for encoding hyperslab selection info based - on whether the number of blocks or the selection high bounds exceeds (2^32 - 1). - Then determine the encoded size based on version. + Copies all the hyperslab selection information from the source + dataspace to the destination dataspace. + + If the SHARE_SELECTION flag is set, then the selection can be shared + between the source and destination dataspaces. (This should only occur in + situations where the destination dataspace will immediately change to a new + selection) GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ static herr_t -H5S__hyper_get_version_enc_size(const H5S_t *space, hsize_t block_count, uint32_t *version, uint8_t *enc_size) +H5S__hyper_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection) { - hsize_t bounds_start[H5S_MAX_RANK]; /* Starting coordinate of bounding box */ - hsize_t bounds_end[H5S_MAX_RANK]; /* Opposite coordinate of bounding box */ - hbool_t count_up_version = FALSE; /* Whether number of blocks exceed (2^32 - 1) */ - hbool_t bound_up_version = FALSE; /* Whether high bounds exceed (2^32 - 1) */ - H5F_libver_t low_bound; /* The 'low' bound of library format versions */ - H5F_libver_t high_bound; /* The 'high' bound of library format versions */ - unsigned u; /* Local index veriable */ - uint32_t tmp_version; /* Temporay version */ - herr_t ret_value = SUCCEED; /* return value */ + H5S_hyper_sel_t *dst_hslab; /* Pointer to destination hyperslab info */ + const H5S_hyper_sel_t *src_hslab; /* Pointer to source hyperslab info */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC - /* Get bounding box for the selection */ - HDmemset(bounds_end, 0, sizeof(bounds_end)); - - if(space->select.sel_info.hslab->unlim_dim < 0) /* ! H5S_UNLIMITED */ - /* Get bounding box for the selection */ - if(H5S__hyper_bounds(space, bounds_start, bounds_end) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds") + /* Sanity check */ + HDassert(src); + HDassert(dst); - /* Determine whether the number of blocks or the high bounds in the selection exceed (2^32 - 1) */ - if(block_count > H5S_UINT32_MAX) - count_up_version = TRUE; - else { - for(u = 0; u < space->extent.rank; u++) - if(bounds_end[u] > H5S_UINT32_MAX) - bound_up_version = TRUE; - } + /* Allocate space for the hyperslab selection information */ + if(NULL == (dst->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info") - /* Get the file's low_bound and high_bound */ - if(H5CX_get_libver_bounds(&low_bound, &high_bound) < 0) - HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get low/high bounds from API context") + /* Set temporary pointers */ + dst_hslab = dst->select.sel_info.hslab; + src_hslab = src->select.sel_info.hslab; - /* Use version 2 for unlimited selection */ - if(space->select.sel_info.hslab->unlim_dim >= 0) - tmp_version = H5S_HYPER_VERSION_2; - else if(H5S__hyper_is_regular(space)) { + /* Copy the hyperslab information */ + dst_hslab->diminfo_valid = src_hslab->diminfo_valid; + if(src_hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) + H5MM_memcpy(&dst_hslab->diminfo, &src_hslab->diminfo, sizeof(H5S_hyper_diminfo_t)); - /* If exceed (2^32 -1) */ - if(count_up_version || bound_up_version) - tmp_version = H5S_HYPER_VERSION_2; + /* Check if there is hyperslab span information to copy */ + /* (Regular hyperslab information is copied with the selection structure) */ + if(src->select.sel_info.hslab->span_lst != NULL) { + if(share_selection) { + /* Share the source's span tree by incrementing the reference count on it */ + dst->select.sel_info.hslab->span_lst = src->select.sel_info.hslab->span_lst; + dst->select.sel_info.hslab->span_lst->count++; + } /* end if */ else - /* block_count < 4: version 1 */ - /* block_count >= 4: determined by low bound */ - tmp_version = (block_count < 4) ? H5S_HYPER_VERSION_1 : H5O_sds_hyper_ver_bounds[low_bound]; - - } else { - /* Fail for irregular hyperslab if exceeds 32 bits */ - if(count_up_version) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "The number of blocks in hyperslab selection exceeds 2^32") - else if(bound_up_version) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "The end of bounding box in hyperslab selection exceeds 2^32") - tmp_version = H5S_HYPER_VERSION_1; - } - - /* Version bounds check */ - if(tmp_version > H5O_sds_hyper_ver_bounds[high_bound]) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "Dataspace hyperslab selection version out of bounds") - - *version = tmp_version; - - /* Determine the encoded size based on version */ - switch(tmp_version) { - case H5S_HYPER_VERSION_1: - *enc_size = H5S_SELECT_INFO_ENC_SIZE_4; - break; - - case H5S_HYPER_VERSION_2: - *enc_size = H5S_SELECT_INFO_ENC_SIZE_8; - break; + /* Copy the hyperslab span information */ + dst->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(src->select.sel_info.hslab->span_lst, src->extent.rank); + } /* end if */ + else + dst->select.sel_info.hslab->span_lst = NULL; - default: - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown hyperslab selection version") - break; - } + /* Copy the unlimited dimension info */ + dst_hslab->unlim_dim = src_hslab->unlim_dim; + dst_hslab->num_elem_non_unlim = src_hslab->num_elem_non_unlim; done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5S__hyper_get_version_enc_size() */ +} /* end H5S__hyper_copy() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_serial_size + H5S__hyper_is_valid PURPOSE - Determine the number of bytes needed to store the serialized hyperslab - selection information. + Check whether the selection fits within the extent, with the current + offset defined. USAGE - hssize_t H5S__hyper_serial_size(space) + htri_t H5S__hyper_is_valid(space); H5S_t *space; IN: Dataspace pointer to query RETURNS - The number of bytes required on success, negative on an error. + TRUE if the selection fits within the extent, FALSE if it does not and + Negative on an error. DESCRIPTION - Determines the number of bytes required to serialize the current hyperslab - selection information for storage on disk. + Determines if the current selection at the current offset fits within the + extent for the dataspace. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static hssize_t -H5S__hyper_serial_size(const H5S_t *space) +static htri_t +H5S__hyper_is_valid(const H5S_t *space) { - hsize_t block_count = 0; /* block counter for regular hyperslabs */ - uint32_t version; /* Version number */ - uint8_t enc_size; /* Encoded size of hyperslab selection info */ - hssize_t ret_value = -1; /* return value */ + const hsize_t *low_bounds, *high_bounds; /* Pointers to the correct pair of low & high bounds */ + unsigned u; /* Counter */ + htri_t ret_value = TRUE; /* return value */ - FUNC_ENTER_STATIC + FUNC_ENTER_STATIC_NOERR HDassert(space); - /* Determine the number of blocks */ - if(space->select.sel_info.hslab->unlim_dim < 0) /* ! H5S_UNLIMITED */ - block_count = H5S__get_select_hyper_nblocks(space, FALSE); - - /* Determine the version and the encoded size */ - if(H5S__hyper_get_version_enc_size(space, block_count, &version, &enc_size) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't determine hyper version & enc_size") + /* Check for unlimited selection */ + if(space->select.sel_info.hslab->unlim_dim >= 0) + HGOTO_DONE(FALSE) - if(version == H5S_HYPER_VERSION_2) { - /* Version 2 */ - /* Size required is always: - * + + + - * + + - * (4 (start/stride/count/block) * * ) = - * 17 + (4 * 8 * rank) bytes - */ - HDassert(enc_size == 8); - ret_value = (hssize_t)17 + ((hssize_t)4 * (hssize_t)8 * (hssize_t)space->extent.rank); - } + /* Check which set of low & high bounds we should be using */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + low_bounds = space->select.sel_info.hslab->diminfo.low_bounds; + high_bounds = space->select.sel_info.hslab->diminfo.high_bounds; + } /* end if */ else { - HDassert(version == H5S_HYPER_VERSION_1); - HDassert(enc_size == 4); - /* Version 1 */ - /* Basic number of bytes required to serialize hyperslab selection: - * + + + - * + + <# of blocks (4 bytes)> + - * (2 (starting/ending offset) * * * <# of blocks) = - * = 24 bytes + (2 * 4 * rank * block_count) - */ - ret_value = 24; - H5_CHECK_OVERFLOW((8 * space->extent.rank * block_count), hsize_t, hssize_t); - ret_value += (hssize_t)(8 * space->extent.rank * block_count); + low_bounds = space->select.sel_info.hslab->span_lst->low_bounds; + high_bounds = space->select.sel_info.hslab->span_lst->high_bounds; } /* end else */ + /* Check each dimension */ + for(u = 0; u < space->extent.rank; u++) { + /* Bounds check the selected point + offset against the extent */ + if(((hssize_t)low_bounds[u] + space->select.offset[u]) < 0) + HGOTO_DONE(FALSE) + if((high_bounds[u] + (hsize_t)space->select.offset[u]) >= space->extent.size[u]) + HGOTO_DONE(FALSE) + } /* end for */ + done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_serial_size() */ +} /* end H5S__hyper_is_valid() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_serialize_helper + H5S__hyper_span_nblocks_helper PURPOSE - Serialize the current selection into a user-provided buffer. + Helper routine to count the number of blocks in a span tree USAGE - void H5S__hyper_serialize_helper(spans, start, end, rank, buf) - H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to serialize - hssize_t start[]; IN/OUT: Accumulated start points - hssize_t end[]; IN/OUT: Accumulated end points - hsize_t rank; IN: Current rank looking at - uint8 *buf; OUT: Buffer to put serialized selection into + hsize_t H5S__hyper_span_nblocks_helper(spans, op_info_i, op_gen) + H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to count blocks of + unsigned op_info_i; IN: Index of op info to use + uint64_t op_gen; IN: Operation generation RETURNS - None + Number of blocks in span tree on success; negative on failure DESCRIPTION - Serializes the current element selection into a buffer. (Primarily for - storing on disk). + Counts the number of blocks described by the spans in a span tree. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static void -H5S__hyper_serialize_helper(const H5S_hyper_span_info_t *spans, - hsize_t *start, hsize_t *end, hsize_t rank, uint8_t **p) +static hsize_t +H5S__hyper_span_nblocks_helper(H5S_hyper_span_info_t *spans, unsigned op_info_i, + uint64_t op_gen) { - H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */ - uint8_t *pp = (*p); /* Local pointer for decoding */ + hsize_t ret_value = 0; /* Return value */ FUNC_ENTER_STATIC_NOERR - /* Sanity checks */ + /* Sanity check */ HDassert(spans); - HDassert(start); - HDassert(end); - HDassert(rank < H5S_MAX_RANK); - HDassert(p && pp); - /* Walk through the list of spans, recursing or outputting them */ - curr = spans->head; - while(curr != NULL) { - /* Recurse if this node has down spans */ - if(curr->down != NULL) { - /* Add the starting and ending points for this span to the list */ - start[rank] = curr->low; - end[rank] = curr->high; + /* Check if the span tree was already counted */ + if(spans->op_info[op_info_i].op_gen == op_gen) + /* Just return the # of blocks in the already counted span tree */ + ret_value = spans->op_info[op_info_i].u.nblocks; + else { /* Count the number of elements in the span tree */ + H5S_hyper_span_t *span; /* Hyperslab span */ - /* Recurse down to the next dimension */ - H5S__hyper_serialize_helper(curr->down, start, end, rank + 1, &pp); + span = spans->head; + if(span->down) { + while(span) { + /* If there are down spans, add the total down span blocks */ + ret_value += H5S__hyper_span_nblocks_helper(span->down, op_info_i, op_gen); + + /* Advance to next span */ + span = span->next; + } /* end while */ } /* end if */ else { - hsize_t u; /* Index variable */ - - /* Encode all the previous dimensions starting & ending points */ - - /* Encode previous starting points */ - for(u = 0; u < rank; u++) - UINT32ENCODE(pp, (uint32_t)start[u]); - - /* Encode starting point for this span */ - UINT32ENCODE(pp, (uint32_t)curr->low); - - /* Encode previous ending points */ - for(u = 0; u < rank; u++) - UINT32ENCODE(pp, (uint32_t)end[u]); + while(span) { + /* If there are no down spans, just count the block in this span */ + ret_value++; - /* Encode starting point for this span */ - UINT32ENCODE(pp, (uint32_t)curr->high); + /* Advance to next span */ + span = span->next; + } /* end while */ } /* end else */ - /* Advance to next node */ - curr = curr->next; - } /* end while */ + /* Set the operation generation for this span tree, to avoid re-computing */ + spans->op_info[op_info_i].op_gen = op_gen; - /* Update encoding pointer */ - *p = pp; + /* Hold a copy of the # of blocks */ + spans->op_info[op_info_i].u.nblocks = ret_value; + } /* end else */ - FUNC_LEAVE_NOAPI_VOID -} /* end H5S__hyper_serialize_helper() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_span_nblocks_helper() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_serialize + H5S__hyper_span_nblocks PURPOSE - Serialize the current selection into a user-provided buffer. + Count the number of blocks in a span tree USAGE - herr_t H5S__hyper_serialize(space, p) - const H5S_t *space; IN: Dataspace with selection to serialize - uint8_t **p; OUT: Pointer to buffer to put serialized - selection. Will be advanced to end of - serialized selection. + hsize_t H5S__hyper_span_nblocks(spans) + H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to count blocks of RETURNS - Non-negative on success/Negative on failure + Number of blocks in span tree on success; negative on failure DESCRIPTION - Serializes the current element selection into a buffer. (Primarily for - storing on disk). + Counts the number of blocks described by the spans in a span tree. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_serialize(const H5S_t *space, uint8_t **p) +static hsize_t +H5S__hyper_span_nblocks(H5S_hyper_span_info_t *spans) { - const H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */ - hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary hyperslab counts */ - hsize_t offset[H5S_MAX_RANK]; /* Offset of element in dataspace */ - hsize_t start[H5S_MAX_RANK]; /* Location of start of hyperslab */ - hsize_t end[H5S_MAX_RANK]; /* Location of end of hyperslab */ - uint8_t *pp; /* Local pointer for encoding */ - uint8_t *lenp = NULL; /* pointer to length location for later storage */ - uint32_t len = 0; /* number of bytes used */ - uint32_t version; /* Version number */ - uint8_t flags = 0; /* Flags for message */ - hsize_t block_count = 0; /* block counter for regular hyperslabs */ - unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ - unsigned ndims; /* Rank of the dataspace */ - unsigned i, u; /* Local counting variable */ - int done; /* Whether we are done with the iteration */ - hbool_t is_regular; /* Whether selection is regular */ - uint8_t enc_size; /* Encoded size */ - herr_t ret_value = SUCCEED; /* return value */ - - FUNC_ENTER_STATIC - - /* Sanity checks */ - HDassert(space); - HDassert(p); - pp = (*p); - HDassert(pp); - - /* Set some convienence values */ - ndims = space->extent.rank; - diminfo = space->select.sel_info.hslab->diminfo.opt; - - /* Calculate the # of blocks */ - if(space->select.sel_info.hslab->unlim_dim < 0) /* ! H5S_UNLIMITED */ - block_count = H5S__get_select_hyper_nblocks(space, FALSE); - - /* Determine the version and the encoded size */ - if(H5S__hyper_get_version_enc_size(space, block_count, &version, &enc_size) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't determine hyper version & enc_size") - - is_regular = H5S__hyper_is_regular(space); - if(is_regular && version == H5S_HYPER_VERSION_2) - flags |= H5S_HYPER_REGULAR; - - /* Store the preamble information */ - UINT32ENCODE(pp, (uint32_t)H5S_GET_SELECT_TYPE(space)); /* Store the type of selection */ - UINT32ENCODE(pp, version); /* Store the version number */ - - if(version == H5S_HYPER_VERSION_2) - *(pp)++ = flags; /* Store the flags */ - else - UINT32ENCODE(pp, (uint32_t)0); /* Store the un-used padding */ - lenp = pp; /* keep the pointer to the length location for later */ - pp += 4; /* skip over space for length */ - - len += 4; /* ndims */ - - /* Encode number of dimensions */ - UINT32ENCODE(pp, (uint32_t)ndims); - - /* Check for a "regular" hyperslab selection */ - if(is_regular) { - - /* If flags indicates a regular hyperslab or unlimited dimension, encode diminfo.opt */ - if(version == H5S_HYPER_VERSION_2) { - - HDassert(H5S_UNLIMITED == HSIZE_UNDEF); - HDassert(enc_size == H5S_SELECT_INFO_ENC_SIZE_8); - - /* Iterate over dimensions */ - /* Encode start/stride/block/count */ - for(i = 0; i < space->extent.rank; i++) { - UINT64ENCODE(pp, diminfo[i].start); - UINT64ENCODE(pp, diminfo[i].stride); - UINT64ENCODE(pp, diminfo[i].count); - UINT64ENCODE(pp, diminfo[i].block); - } /* end for */ - len += (4 * space->extent.rank * 8); - } else { - HDassert(version == H5S_HYPER_VERSION_1); - HDassert(enc_size == H5S_SELECT_INFO_ENC_SIZE_4); - - /* Set some convienence values */ - fast_dim = ndims - 1; - - /* Encode number of hyperslabs */ - H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t); - UINT32ENCODE(pp, (uint32_t)block_count); - len += 4; - - /* Now serialize the information for the regular hyperslab */ - - /* Build the tables of count sizes as well as the initial offset */ - for(u = 0; u < ndims; u++) { - tmp_count[u] = diminfo[u].count; - offset[u] = diminfo[u].start; - } /* end for */ - - /* We're not done with the iteration */ - done = FALSE; - - /* Go iterate over the hyperslabs */ - while(done == FALSE) { - /* Iterate over the blocks in the fastest dimension */ - while(tmp_count[fast_dim] > 0) { - /* Add 8 bytes times the rank for each hyperslab selected */ - len += 8 * ndims; - - /* Encode hyperslab starting location */ - for(u = 0; u < ndims; u++) - UINT32ENCODE(pp, (uint32_t)offset[u]); - - /* Encode hyperslab ending location */ - for(u = 0; u < ndims; u++) - UINT32ENCODE(pp, (uint32_t)(offset[u] + (diminfo[u].block - 1))); - - /* Move the offset to the next sequence to start */ - offset[fast_dim]+=diminfo[fast_dim].stride; - - /* Decrement the block count */ - tmp_count[fast_dim]--; - } /* end while */ - - /* Work on other dimensions if necessary */ - if(fast_dim > 0) { - int temp_dim; /* Temporary rank holder */ - - /* Reset the block counts */ - tmp_count[fast_dim] = diminfo[fast_dim].count; - - /* Bubble up the decrement to the slower changing dimensions */ - temp_dim = (int)fast_dim - 1; - while(temp_dim >= 0 && done == FALSE) { - /* Decrement the block count */ - tmp_count[temp_dim]--; - - /* Check if we have more blocks left */ - if(tmp_count[temp_dim] > 0) - break; - - /* Check for getting out of iterator */ - if(temp_dim == 0) - done = TRUE; - - /* Reset the block count in this dimension */ - tmp_count[temp_dim] = diminfo[temp_dim].count; - - /* Wrapped a dimension, go up to next dimension */ - temp_dim--; - } /* end while */ - } /* end if */ - else - break; /* Break out now, for 1-D selections */ - - /* Re-compute offset array */ - for(u = 0; u < ndims; u++) - offset[u] = diminfo[u].start + diminfo[u].stride * (diminfo[u].count - tmp_count[u]); - } /* end while */ - } /* end if */ - } - else { /* irregular */ - HDassert(version == H5S_HYPER_VERSION_1); - HDassert(enc_size == H5S_SELECT_INFO_ENC_SIZE_4); - - /* Encode number of hyperslabs */ - H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t); - UINT32ENCODE(pp, (uint32_t)block_count); - - len+=4; /* block_count */ + hsize_t ret_value = 0; /* Return value */ - /* Add 8 bytes times the rank for each hyperslab selected */ - H5_CHECK_OVERFLOW((8 * ndims * block_count), hsize_t, size_t); - len += (uint32_t)(8 * ndims * block_count); + FUNC_ENTER_STATIC_NOERR - /* Encode each hyperslab in selection */ - H5S__hyper_serialize_helper(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, &pp); - } /* end else */ + /* Count the number of elements in the span tree */ + if(spans != NULL) { + uint64_t op_gen; /* Operation generation value */ - /* Encode length */ - UINT32ENCODE(lenp, (uint32_t)len); /* Store the length of the extra information */ + /* Acquire an operation generation value for this operation */ + op_gen = H5S__hyper_get_op_gen(); - /* Update encoding pointer */ - *p = pp; + /* Count the blocks */ + /* Always use op_info[0] since we own this op_info, so there can be no + * simultaneous operations */ + ret_value = H5S__hyper_span_nblocks_helper(spans, 0, op_gen); + } /* end if */ -done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_serialize() */ +} /* end H5S__hyper_span_nblocks() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_deserialize + H5S__get_select_hyper_nblocks PURPOSE - Deserialize the current selection from a user-provided buffer. + Get the number of hyperslab blocks in current hyperslab selection USAGE - herr_t H5S__hyper_deserialize(space, p) - H5S_t **space; IN/OUT: Dataspace pointer to place - selection into - uint8 **p; OUT: Pointer to buffer holding serialized - selection. Will be advanced to end of - serialized selection. + hsize_t H5S__get_select_hyper_nblocks(space, app_ref) + H5S_t *space; IN: Dataspace ptr of selection to query + hbool_t app_ref; IN: Whether this is an appl. ref. call RETURNS - Non-negative on success/Negative on failure + The number of hyperslab blocks in selection on success, negative on failure DESCRIPTION - Deserializes the current selection into a buffer. (Primarily for retrieving - from disk). + Returns the number of hyperslab blocks in current selection for dataspace. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_deserialize(H5S_t **space, const uint8_t **p) +static hsize_t +H5S__get_select_hyper_nblocks(const H5S_t *space, hbool_t app_ref) { - H5S_t *tmp_space = NULL; /* Pointer to actual dataspace to use, - either *space or a newly allocated one */ - hsize_t dims[H5S_MAX_RANK]; /* Dimenion sizes */ - hsize_t start[H5S_MAX_RANK]; /* Hyperslab start information */ - hsize_t block[H5S_MAX_RANK]; /* Hyperslab block information */ - uint32_t version; /* Version number */ /* Encoded size */ - uint8_t flags = 0; /* Flags */ - unsigned rank; /* Rank of points */ - const uint8_t *pp; /* Local pointer for decoding */ - unsigned u; /* Local counting variable */ - herr_t ret_value = FAIL; /* Return value */ - - FUNC_ENTER_STATIC - - /* Check args */ - HDassert(p); - pp = (*p); - HDassert(pp); - - /* As part of the efforts to push all selection-type specific coding - to the callbacks, the coding for the allocation of a null dataspace - is moved from H5S_select_deserialize() in H5Sselect.c to here. - This is needed for decoding virtual layout in H5O__layout_decode() */ - /* Allocate space if not provided */ - if(!*space) { - if(NULL == (tmp_space = H5S_create(H5S_SIMPLE))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create dataspace") - } /* end if */ - else - tmp_space = *space; - - /* Decode version */ - UINT32DECODE(pp, version); - - if(version < H5S_HYPER_VERSION_1 || version > H5S_HYPER_VERSION_LATEST) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "bad version number for hyperslab selection") + hsize_t ret_value = 0; /* Return value */ - if(version >= (uint32_t)H5S_HYPER_VERSION_2) { - /* Decode flags */ - flags = *(pp)++; + FUNC_ENTER_STATIC_NOERR - /* Skip over the remainder of the header */ - pp += 4; - } - else - /* Skip over the remainder of the header */ - pp += 8; + HDassert(space); + HDassert(space->select.sel_info.hslab->unlim_dim < 0); - /* Decode the rank of the point selection */ - UINT32DECODE(pp,rank); + /* Check for a "regular" hyperslab selection */ + /* (No need to rebuild the dimension info yet -QAK) */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + unsigned u; /* Local index variable */ - if(!*space) { - /* Patch the rank of the allocated dataspace */ - HDmemset(dims, 0, (size_t)rank * sizeof(dims[0])); - if(H5S_set_extent_simple(tmp_space, rank, dims, NULL) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't set dimensions") + /* Check each dimension */ + for(ret_value = 1, u = 0; u < space->extent.rank; u++) + ret_value *= (app_ref ? space->select.sel_info.hslab->diminfo.app[u].count : + space->select.sel_info.hslab->diminfo.opt[u].count); } /* end if */ else - /* Verify the rank of the provided dataspace */ - if(rank != tmp_space->extent.rank) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "rank of serialized selection does not match dataspace") - - if(flags & H5S_HYPER_REGULAR) { - hsize_t stride[H5S_MAX_RANK]; /* Hyperslab stride information */ - hsize_t count[H5S_MAX_RANK]; /* Hyperslab count information */ - - /* Sanity checks */ - HDassert(H5S_UNLIMITED == HSIZE_UNDEF); - HDassert(version >= H5S_HYPER_VERSION_2); - - /* Iterate over dimensions */ - for(u = 0; u < rank; u++) { - /* Decode start/stride/block/count */ - UINT64DECODE(pp, start[u]); - UINT64DECODE(pp, stride[u]); - UINT64DECODE(pp, count[u]); - UINT64DECODE(pp, block[u]); - } /* end for */ - - /* Select the hyperslab to the current selection */ - if((ret_value = H5S_select_hyperslab(tmp_space, H5S_SELECT_SET, start, stride, count, block)) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't change selection") - } /* end if */ - else { - const hsize_t *stride; /* Hyperslab stride information */ - const hsize_t *count; /* Hyperslab count information */ - hsize_t end[H5S_MAX_RANK]; /* Hyperslab end information */ - hsize_t *tstart; /* Temporary hyperslab pointers */ - hsize_t *tend; /* Temporary hyperslab pointers */ - hsize_t *tblock; /* Temporary hyperslab pointers */ - size_t num_elem; /* Number of elements in selection */ - unsigned v; /* Local counting variable */ - - /* Decode the number of points */ - UINT32DECODE(pp, num_elem); - - /* Set the count & stride for all blocks */ - stride = count = H5S_hyper_ones_g; - - /* Retrieve the coordinates from the buffer */ - for(u = 0; u < num_elem; u++) { - /* Decode the starting points */ - for(tstart = start, v = 0; v < rank; v++, tstart++) - UINT32DECODE(pp, *tstart); - - /* Decode the ending points */ - for(tend = end, v = 0; v < rank; v++, tend++) - UINT32DECODE(pp, *tend); - - /* Change the ending points into blocks */ - for(tblock = block, tstart = start, tend = end, v = 0; v < rank; v++, tstart++, tend++, tblock++) - *tblock = (*tend - *tstart) + 1; - - /* Select or add the hyperslab to the current selection */ - if((ret_value = H5S_select_hyperslab(tmp_space, (u == 0 ? H5S_SELECT_SET : H5S_SELECT_OR), start, stride, count, block)) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't change selection") - } /* end for */ - } /* end else */ - - /* Update decoding pointer */ - *p = pp; - - /* Return space to the caller if allocated */ - if(!*space) - *space = tmp_space; - -done: - /* Free temporary space if not passed to caller (only happens on error) */ - if(!*space && tmp_space) - if(H5S_close(tmp_space) < 0) - HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't close dataspace") + ret_value = H5S__hyper_span_nblocks(space->select.sel_info.hslab->span_lst); FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_deserialize() */ +} /* end H5S__get_select_hyper_nblocks() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_span_blocklist + H5Sget_select_hyper_nblocks PURPOSE - Get a list of hyperslab blocks currently selected + Get the number of hyperslab blocks in current hyperslab selection USAGE - herr_t H5S__hyper_span_blocklist(spans, start, end, rank, startblock, numblocks, buf) - H5S_hyper_span_info_t *spans; IN: Dataspace pointer of selection to query - hsize_t start[]; IN/OUT: Accumulated start points - hsize_t end[]; IN/OUT: Accumulated end points - hsize_t rank; IN: Rank of dataspace - hsize_t *startblock; IN/OUT: Hyperslab block to start with - hsize_t *numblocks; IN/OUT: Number of hyperslab blocks to get - hsize_t **buf; OUT: List of hyperslab blocks selected + hssize_t H5Sget_select_hyper_nblocks(dsid) + hid_t dsid; IN: Dataspace ID of selection to query RETURNS - Non-negative on success/Negative on failure + The number of hyperslab blocks in selection on success, negative on failure DESCRIPTION - Puts a list of the hyperslab blocks into the user's buffer. The blocks - start with the '*startblock'th block in the list of blocks and put - '*numblocks' number of blocks into the user's buffer (or until the end of - the list of blocks, whichever happens first) - The block coordinates have the same dimensionality (rank) as the - dataspace they are located within. The list of blocks is formatted as - follows: <"start" coordinate> immediately followed by <"opposite" corner - coordinate>, followed by the next "start" and "opposite" coordinate, etc. - until all the block information requested has been put into the user's - buffer. - No guarantee of any order of the blocks is implied. + Returns the number of hyperslab blocks in current selection for dataspace. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_span_blocklist(const H5S_hyper_span_info_t *spans, hsize_t start[], - hsize_t end[], hsize_t rank, hsize_t *startblock, hsize_t *numblocks, - hsize_t **buf) +hssize_t +H5Sget_select_hyper_nblocks(hid_t spaceid) { - const H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */ - hsize_t u; /* Index variable */ - herr_t ret_value = SUCCEED; /* return value */ - - FUNC_ENTER_STATIC - - /* Sanity checks */ - HDassert(spans); - HDassert(rank < H5S_MAX_RANK); - HDassert(start); - HDassert(end); - HDassert(startblock); - HDassert(numblocks && *numblocks > 0); - HDassert(buf && *buf); - - /* Walk through the list of spans, recursing or outputting them */ - curr = spans->head; - while(curr != NULL && *numblocks > 0) { - /* Recurse if this node has down spans */ - if(curr->down != NULL) { - /* Add the starting and ending points for this span to the list */ - start[rank] = curr->low; - end[rank] = curr->high; - - /* Recurse down to the next dimension */ - if(H5S__hyper_span_blocklist(curr->down, start, end, (rank + 1), startblock, numblocks, buf) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans") - } /* end if */ - else { - /* Skip this block if we haven't skipped all the startblocks yet */ - if(*startblock > 0) { - /* Decrement the starting block */ - (*startblock)--; - } /* end if */ - /* Process this block */ - else { - /* Encode all the previous dimensions starting & ending points */ - - /* Copy previous starting points */ - for(u = 0; u < rank; u++, (*buf)++) - H5MM_memcpy(*buf, &start[u], sizeof(hsize_t)); - - /* Copy starting point for this span */ - H5MM_memcpy(*buf, &curr->low, sizeof(hsize_t)); - (*buf)++; - - /* Copy previous ending points */ - for(u = 0; u < rank; u++, (*buf)++) - H5MM_memcpy(*buf, &end[u], sizeof(hsize_t)); + H5S_t *space; /* Dataspace to modify selection of */ + hssize_t ret_value; /* return value */ - /* Copy starting point for this span */ - H5MM_memcpy(*buf, &curr->high, sizeof(hsize_t)); - (*buf)++; + FUNC_ENTER_API(FAIL) + H5TRACE1("Hs", "i", spaceid); - /* Decrement the number of blocks processed */ - (*numblocks)--; - } /* end else */ - } /* end else */ + /* Check args */ + if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + if(H5S_GET_SELECT_TYPE(space) != H5S_SEL_HYPERSLABS) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection") + if(space->select.sel_info.hslab->unlim_dim >= 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot get number of blocks for unlimited selection") - /* Advance to next node */ - curr = curr->next; - } /* end while */ + ret_value = (hssize_t)H5S__get_select_hyper_nblocks(space, TRUE); -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_span_blocklist() */ +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Sget_select_hyper_nblocks() */ /*-------------------------------------------------------------------------- NAME - H5S__get_select_hyper_blocklist + H5S__hyper_get_enc_size_real PURPOSE - Get the list of hyperslab blocks currently selected + Determine the size to encode the hyperslab selection info USAGE - herr_t H5S__get_select_hyper_blocklist(space, startblock, numblocks, buf) - H5S_t *space; IN: Dataspace pointer of selection to query - hsize_t startblock; IN: Hyperslab block to start with - hsize_t numblocks; IN: Number of hyperslab blocks to get - hsize_t *buf; OUT: List of hyperslab blocks selected + hssize_t H5S__hyper_get_enc_size_real(max_size, enc_size) + hsize_t max_size: IN: The maximum size of the hyperslab selection info + unint8_t *enc_size: OUT:The encoding size RETURNS - Non-negative on success, negative on failure + The size to encode hyperslab selection info DESCRIPTION - Puts a list of the hyperslab blocks into the user's buffer. The blocks - start with the 'startblock'th block in the list of blocks and put - 'numblocks' number of blocks into the user's buffer (or until the end of - the list of blocks, whichever happens first) - The block coordinates have the same dimensionality (rank) as the - dataspace they are located within. The list of blocks is formatted as - follows: <"start" coordinate> immediately followed by <"opposite" corner - coordinate>, followed by the next "start" and "opposite" coordinate, etc. - until all the block information requested has been put into the user's - buffer. - No guarantee of any order of the blocks is implied. + Determine the size by comparing "max_size" with (2^32 - 1) and (2^16 - 1). GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__get_select_hyper_blocklist(H5S_t *space, hbool_t internal, hsize_t startblock, hsize_t numblocks, hsize_t *buf) +static uint8_t +H5S__hyper_get_enc_size_real(hsize_t max_size) { - herr_t ret_value = SUCCEED; /* Return value */ + uint8_t ret_value; FUNC_ENTER_STATIC_NOERR - HDassert(space); - HDassert(buf); - HDassert(space->select.sel_info.hslab->unlim_dim < 0); - - /* Check for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { - const H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */ - hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary hyperslab counts */ - hsize_t offset[H5S_MAX_RANK]; /* Offset of element in dataspace */ - unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ - unsigned ndims; /* Rank of the dataspace */ - hbool_t done; /* Whether we are done with the iteration */ - unsigned u; /* Counter */ - - /* Set some convienence values */ - ndims = space->extent.rank; - fast_dim = ndims - 1; - - /* Check which set of dimension information to use */ - if(internal) - /* - * Use the "optimized dimension information" to pass back information - * on the blocks set, not the "application information". - */ - diminfo = space->select.sel_info.hslab->diminfo.opt; - else - if(space->select.sel_info.hslab->unlim_dim >= 0) - /* - * There is an unlimited dimension so we must use diminfo.opt as - * it has been "clipped" to the current extent. - */ - diminfo = space->select.sel_info.hslab->diminfo.opt; - else - /* - * Use the "application dimension information" to pass back to - * the user the blocks they set, not the optimized, internal - * information. - */ - diminfo = space->select.sel_info.hslab->diminfo.app; + if(max_size > H5S_UINT32_MAX) + ret_value = H5S_SELECT_INFO_ENC_SIZE_8; + else + ret_value = H5S_SELECT_INFO_ENC_SIZE_4; - /* Build the tables of count sizes as well as the initial offset */ - for(u = 0; u < ndims; u++) { - tmp_count[u] = diminfo[u].count; - offset[u] = diminfo[u].start; - } /* end for */ + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S__hyper_get_enc_size_real() */ - /* We're not done with the iteration */ - done = FALSE; - /* Go iterate over the hyperslabs */ - while(!done && numblocks > 0) { - hsize_t temp_off; /* Offset in a given dimension */ +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_get_version_enc_size + PURPOSE + Determine the version and encoded size to use for encoding hyperslab selection info + USAGE + hssize_t H5S__hyper_get_version_enc_size(space, block_count, version, enc_size) + const H5S_t *space: IN: The dataspace + hsize_t block_count: IN: The number of blocks in the selection + uint32_t *version: OUT: The version to use for encoding + uint8_t *enc_size: OUT: The encoded size to use - /* Iterate over the blocks in the fastest dimension */ - while(tmp_count[fast_dim] > 0 && numblocks > 0) { + RETURNS + The version and the size to encode hyperslab selection info + DESCRIPTION + Determine the version to use for encoding hyperslab selection info based + on the following: + (1) the file format setting in fapl + (2) whether the number of blocks or selection high bounds exceeds H5S_UINT32_MAX or not - /* Check if we should copy this block information */ - if(startblock == 0) { - /* Copy the starting location */ - H5MM_memcpy(buf, offset, sizeof(hsize_t) * ndims); - buf += ndims; + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_get_version_enc_size(const H5S_t *space, hsize_t block_count, uint32_t *version, uint8_t *enc_size) +{ + hsize_t bounds_start[H5S_MAX_RANK]; /* Starting coordinate of bounding box */ + hsize_t bounds_end[H5S_MAX_RANK]; /* Opposite coordinate of bounding box */ + hbool_t count_up_version = FALSE; /* Whether number of blocks exceed (2^32 - 1) */ + hbool_t bound_up_version = FALSE; /* Whether high bounds exceed (2^32 - 1) */ + H5F_libver_t low_bound; /* The 'low' bound of library format versions */ + H5F_libver_t high_bound; /* The 'high' bound of library format versions */ + unsigned u; /* Local index veriable */ + uint32_t tmp_version; /* Temporay version */ + herr_t ret_value = SUCCEED; /* return value */ - /* Compute the ending location */ - H5MM_memcpy(buf, offset, sizeof(hsize_t) * ndims); - for(u = 0; u < ndims; u++) - buf[u] += (diminfo[u].block - 1); - buf += ndims; + FUNC_ENTER_STATIC - /* Decrement the number of blocks to retrieve */ - numblocks--; - } /* end if */ - else - startblock--; + /* Get bounding box for the selection */ + HDmemset(bounds_end, 0, sizeof(bounds_end)); - /* Move the offset to the next sequence to start */ - offset[fast_dim] += diminfo[fast_dim].stride; + if(space->select.sel_info.hslab->unlim_dim < 0) /* ! H5S_UNLIMITED */ + /* Get bounding box for the selection */ + if(H5S__hyper_bounds(space, bounds_start, bounds_end) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds") - /* Decrement the block count */ - tmp_count[fast_dim]--; - } /* end while */ + /* Determine whether the number of blocks or the high bounds in the selection exceed (2^32 - 1) */ + if(block_count > H5S_UINT32_MAX) + count_up_version = TRUE; + else { + for(u = 0; u < space->extent.rank; u++) + if(bounds_end[u] > H5S_UINT32_MAX) + bound_up_version = TRUE; + } - /* Work on other dimensions if necessary */ - if(fast_dim > 0 && numblocks > 0) { - int temp_dim; /* Temporary rank holder */ + /* Get the file's low_bound and high_bound */ + if(H5CX_get_libver_bounds(&low_bound, &high_bound) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTGET, FAIL, "can't get low/high bounds from API context") - /* Reset the block counts */ - tmp_count[fast_dim] = diminfo[fast_dim].count; + /* Use version 2 for unlimited selection */ + if(space->select.sel_info.hslab->unlim_dim >= 0) + tmp_version = H5S_HYPER_VERSION_2; + else if(H5S__hyper_is_regular(space)) { - /* Bubble up the decrement to the slower changing dimensions */ - temp_dim = (int)(fast_dim - 1); - while(temp_dim >= 0 && !done) { - /* Decrement the block count */ - tmp_count[temp_dim]--; + /* If exceed (2^32 -1) */ + if(count_up_version || bound_up_version) + tmp_version = H5S_HYPER_VERSION_2; + else + /* block_count < 4: version 1 */ + /* block_count >= 4: determined by low bound */ + tmp_version = (block_count < 4) ? H5S_HYPER_VERSION_1 : H5O_sds_hyper_ver_bounds[low_bound]; - /* Check if we have more blocks left */ - if(tmp_count[temp_dim] > 0) - break; + } else { + /* Fail for irregular hyperslab if exceeds 32 bits */ + if(count_up_version) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "The number of blocks in hyperslab selection exceeds 2^32") + else if(bound_up_version) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "The end of bounding box in hyperslab selection exceeds 2^32") + tmp_version = H5S_HYPER_VERSION_1; + } - /* Check for getting out of iterator */ - if(temp_dim == 0) - done = TRUE; + /* Version bounds check */ + if(tmp_version > H5O_sds_hyper_ver_bounds[high_bound]) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "Dataspace hyperslab selection version out of bounds") - /* Reset the block count in this dimension */ - tmp_count[temp_dim] = diminfo[temp_dim].count; + *version = tmp_version; - /* Wrapped a dimension, go up to next dimension */ - temp_dim--; - } /* end while */ - } /* end if */ + /* Determine the encoded size based on version */ + switch(tmp_version) { + case H5S_HYPER_VERSION_1: + *enc_size = H5S_SELECT_INFO_ENC_SIZE_4; + break; - /* Re-compute offset array */ - for(u = 0; u < ndims; u++) { - temp_off = diminfo[u].start + diminfo[u].stride * (diminfo[u].count - tmp_count[u]); - offset[u] = temp_off; - } /* end for */ - } /* end while */ - } /* end if */ - else { - hsize_t start[H5S_MAX_RANK]; /* Location of start of hyperslab */ - hsize_t end[H5S_MAX_RANK]; /* Location of end of hyperslab */ + case H5S_HYPER_VERSION_2: + *enc_size = H5S_SELECT_INFO_ENC_SIZE_8; + break; - ret_value = H5S__hyper_span_blocklist(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, &startblock, &numblocks, &buf); - } /* end else */ + default: + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown hyperslab selection version") + break; + } +done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__get_select_hyper_blocklist() */ +} /* H5S__hyper_get_version_enc_size() */ /*-------------------------------------------------------------------------- NAME - H5Sget_select_hyper_blocklist + H5S__hyper_serial_size PURPOSE - Get the list of hyperslab blocks currently selected + Determine the number of bytes needed to store the serialized hyperslab + selection information. USAGE - herr_t H5Sget_select_hyper_blocklist(dsid, startblock, numblocks, buf) - hid_t dsid; IN: Dataspace ID of selection to query - hsize_t startblock; IN: Hyperslab block to start with - hsize_t numblocks; IN: Number of hyperslab blocks to get - hsize_t buf[]; OUT: List of hyperslab blocks selected + hssize_t H5S__hyper_serial_size(space) + H5S_t *space; IN: Dataspace pointer to query RETURNS - Non-negative on success, negative on failure + The number of bytes required on success, negative on an error. DESCRIPTION - Puts a list of the hyperslab blocks into the user's buffer. The blocks - start with the 'startblock'th block in the list of blocks and put - 'numblocks' number of blocks into the user's buffer (or until the end of - the list of blocks, whichever happen first) - The block coordinates have the same dimensionality (rank) as the - dataspace they are located within. The list of blocks is formatted as - follows: <"start" coordinate> immediately followed by <"opposite" corner - coordinate>, followed by the next "start" and "opposite" coordinate, etc. - until all the block information requested has been put into the user's - buffer. - No guarantee of any order of the blocks is implied. + Determines the number of bytes required to serialize the current hyperslab + selection information for storage on disk. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -herr_t -H5Sget_select_hyper_blocklist(hid_t spaceid, hsize_t startblock, - hsize_t numblocks, hsize_t buf[/*numblocks*/]) +static hssize_t +H5S__hyper_serial_size(const H5S_t *space) { - H5S_t *space; /* Dataspace to modify selection of */ - herr_t ret_value; /* return value */ + hsize_t block_count = 0; /* block counter for regular hyperslabs */ + uint32_t version; /* Version number */ + uint8_t enc_size; /* Encoded size of hyperslab selection info */ + hssize_t ret_value = -1; /* return value */ - FUNC_ENTER_API(FAIL) - H5TRACE4("e", "ihh*[a2]h", spaceid, startblock, numblocks, buf); + FUNC_ENTER_STATIC - /* Check args */ - if(buf == NULL) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid pointer") - if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") - if(H5S_GET_SELECT_TYPE(space)!=H5S_SEL_HYPERSLABS) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection") - if(space->select.sel_info.hslab->unlim_dim >= 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot get blocklist for unlimited selection") + HDassert(space); - /* Go get the correct number of blocks */ - if(numblocks > 0) - ret_value = H5S__get_select_hyper_blocklist(space, 0, startblock, numblocks, buf); - else - ret_value = SUCCEED; /* Successfully got 0 blocks... */ + /* Determine the number of blocks */ + if(space->select.sel_info.hslab->unlim_dim < 0) /* ! H5S_UNLIMITED */ + block_count = H5S__get_select_hyper_nblocks(space, FALSE); + + /* Determine the version and the encoded size */ + if(H5S__hyper_get_version_enc_size(space, block_count, &version, &enc_size) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't determine hyper version & enc_size") + + if(version == H5S_HYPER_VERSION_2) { + /* Version 2 */ + /* Size required is always: + * + + + + * + + + * (4 (start/stride/count/block) * * ) = + * 17 + (4 * 8 * rank) bytes + */ + HDassert(enc_size == 8); + ret_value = (hssize_t)17 + ((hssize_t)4 * (hssize_t)8 * (hssize_t)space->extent.rank); + } + else { + HDassert(version == H5S_HYPER_VERSION_1); + HDassert(enc_size == 4); + /* Version 1 */ + /* Basic number of bytes required to serialize hyperslab selection: + * + + + + * + + <# of blocks (4 bytes)> + + * (2 (starting/ending offset) * * * <# of blocks) = + * = 24 bytes + (2 * 4 * rank * block_count) + */ + ret_value = 24; + H5_CHECK_OVERFLOW((8 * space->extent.rank * block_count), hsize_t, hssize_t); + ret_value += (hssize_t)(8 * space->extent.rank * block_count); + } /* end else */ done: - FUNC_LEAVE_API(ret_value) -} /* end H5Sget_select_hyper_blocklist() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_serial_size() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_bounds_helper + H5S__hyper_serialize_helper PURPOSE - Gets the bounding box containing the selection. + Serialize the current selection into a user-provided buffer. USAGE - htri_t H5S_hyper_bounds_helper(spans, offset, rank); - const H5S_hyper_span_info_t *spans; IN: Pointer to current hyperslab span tree - const hssize_t *offset; IN: Pointer to offset array - hsize_t rank; IN: Current rank looking at - hsize_t *start; OUT: Start array bounds - hsize_t *end; OUT: End array bounds + void H5S__hyper_serialize_helper(spans, start, end, rank, enc_size, buf) + H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to serialize + hssize_t start[]; IN/OUT: Accumulated start points + hssize_t end[]; IN/OUT: Accumulated end points + hsize_t rank; IN: Current rank looking at + uint8_t enc_size IN: Encoded size of hyperslab selection info + uint8_t *buf; OUT: Buffer to put serialized selection into RETURNS - Non-negative on success, negative on failure + None DESCRIPTION - Retrieves the bounding box containing the current selection and places - it into the user's buffers. The start and end buffers must be large - enough to hold the dataspace rank number of coordinates. The bounding box - exactly contains the selection, ie. if a 2-D element selection is currently - defined with the following points: (4,5), (6,8) (10,7), the bounding box - with be (4, 5), (10, 8). - The bounding box calculations _does_ include the current offset of the - selection within the dataspace extent. + Serializes the current element selection into a buffer. (Primarily for + storing on disk). GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S_hyper_bounds_helper(const H5S_hyper_span_info_t *spans, const hssize_t *offset, hsize_t rank, hsize_t *start, hsize_t *end) +static void +H5S__hyper_serialize_helper(const H5S_hyper_span_info_t *spans, + hsize_t *start, hsize_t *end, hsize_t rank, uint8_t enc_size, uint8_t **p) { - H5S_hyper_span_t *curr; /* Hyperslab information nodes */ - herr_t ret_value = SUCCEED; /* Return value */ + H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */ + uint8_t *pp = (*p); /* Local pointer for decoding */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR + /* Sanity checks */ HDassert(spans); - HDassert(offset); - HDassert(rank < H5S_MAX_RANK); HDassert(start); HDassert(end); + HDassert(rank < H5S_MAX_RANK); + HDassert(p && pp); - /* Check each point to determine whether selection+offset is within extent */ - curr=spans->head; - while(curr!=NULL) { - /* Check for offset moving selection negative */ - if(((hssize_t)curr->low + offset[rank]) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds") - - /* Check if the current span extends the bounding box */ - if((curr->low + (hsize_t)offset[rank]) < start[rank]) - start[rank] = curr->low + (hsize_t)offset[rank]; - if((curr->high + (hsize_t)offset[rank]) > end[rank]) - end[rank] = curr->high + (hsize_t)offset[rank]; - + /* Walk through the list of spans, recursing or outputting them */ + curr = spans->head; + while(curr != NULL) { /* Recurse if this node has down spans */ if(curr->down != NULL) { - if(H5S_hyper_bounds_helper(curr->down, offset, (rank + 1), start, end) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "failure in lower dimension") + /* Add the starting and ending points for this span to the list */ + start[rank] = curr->low; + end[rank] = curr->high; + + /* Recurse down to the next dimension */ + H5S__hyper_serialize_helper(curr->down, start, end, rank + 1, enc_size, &pp); } /* end if */ + else { + hsize_t u; /* Index variable */ + + /* Encode all the previous dimensions starting & ending points */ + switch(enc_size) { + case H5S_SELECT_INFO_ENC_SIZE_4: + /* Encode previous starting points */ + for(u=0; ulow); + + /* Encode previous ending points */ + for(u=0; uhigh); + break; + + case H5S_SELECT_INFO_ENC_SIZE_8: + /* Encode previous starting points */ + for(u=0; ulow); + + /* Encode previous ending points */ + for(u=0; uhigh); + break; + + default: + HDassert(0 && "Unknown enc size?!?"); + + } /* end switch */ + } /* end else */ /* Advance to next node */ curr = curr->next; } /* end while */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_bounds_helper() */ + /* Update encoding pointer */ + *p = pp; + + FUNC_LEAVE_NOAPI_VOID +} /* end H5S__hyper_serialize_helper() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_bounds + H5S__hyper_serialize PURPOSE - Gets the bounding box containing the selection. + Serialize the current selection into a user-provided buffer. USAGE - herr_t H5S__hyper_bounds(space, hsize_t *start, hsize_t *end) - H5S_t *space; IN: Dataspace pointer of selection to query - hsize_t *start; OUT: Starting coordinate of bounding box - hsize_t *end; OUT: Opposite coordinate of bounding box + herr_t H5S__hyper_serialize(space, p) + const H5S_t *space; IN: Dataspace with selection to serialize + uint8_t **p; OUT: Pointer to buffer to put serialized + selection. Will be advanced to end of + serialized selection. RETURNS - Non-negative on success, negative on failure + Non-negative on success/Negative on failure DESCRIPTION - Retrieves the bounding box containing the current selection and places - it into the user's buffers. The start and end buffers must be large - enough to hold the dataspace rank number of coordinates. The bounding box - exactly contains the selection, ie. if a 2-D element selection is currently - defined with the following points: (4,5), (6,8) (10,7), the bounding box - with be (4, 5), (10, 8). - The bounding box calculations _does_ include the current offset of the - selection within the dataspace extent. + Serializes the current element selection into a buffer. (Primarily for + storing on disk). GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ static herr_t -H5S__hyper_bounds(const H5S_t *space, hsize_t *start, hsize_t *end) +H5S__hyper_serialize(const H5S_t *space, uint8_t **p) { - unsigned rank; /* Dataspace rank */ - unsigned i; /* index variable */ - herr_t ret_value = SUCCEED; /* Return value */ + const H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */ + hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary hyperslab counts */ + hsize_t offset[H5S_MAX_RANK]; /* Offset of element in dataspace */ + hsize_t start[H5S_MAX_RANK]; /* Location of start of hyperslab */ + hsize_t end[H5S_MAX_RANK]; /* Location of end of hyperslab */ + uint8_t *pp; /* Local pointer for encoding */ + uint8_t *lenp = NULL; /* pointer to length location for later storage */ + uint32_t len = 0; /* number of bytes used */ + uint32_t version; /* Version number */ + uint8_t flags = 0; /* Flags for message */ + hsize_t block_count = 0; /* block counter for regular hyperslabs */ + unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + unsigned ndims; /* Rank of the dataspace */ + unsigned u; /* Local counting variable */ + hbool_t complete = FALSE; /* Whether we are done with the iteration */ + hbool_t is_regular; /* Whether selection is regular */ + uint8_t enc_size; /* Encoded size */ + herr_t ret_value = SUCCEED; /* return value */ FUNC_ENTER_STATIC - /* Sanity check */ + /* Sanity checks */ HDassert(space); - HDassert(start); - HDassert(end); + HDassert(p); + pp = (*p); + HDassert(pp); - /* Set the start and end arrays up */ - rank = space->extent.rank; - for(i = 0; i < rank; i++) { - start[i] = HSIZET_MAX; - end[i] = 0; - } /* end for */ + /* Set some convienence values */ + ndims = space->extent.rank; + diminfo = space->select.sel_info.hslab->diminfo.opt; - /* Check for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { - const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->diminfo.opt; /* local alias for diminfo */ + /* Calculate the # of blocks */ + if(space->select.sel_info.hslab->unlim_dim < 0) /* ! H5S_UNLIMITED */ + block_count = H5S__get_select_hyper_nblocks(space, FALSE); - /* Check each dimension */ - for(i = 0; i < rank; i++) { - /* Check for offset moving selection negative */ - if((space->select.offset[i] + (hssize_t)diminfo[i].start) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds") + /* Determine the version and the encoded size */ + if(H5S__hyper_get_version_enc_size(space, block_count, &version, &enc_size) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't determine hyper version & enc_size") - /* Compute the smallest location in this dimension */ - start[i] = diminfo[i].start + (hsize_t)space->select.offset[i]; + is_regular = H5S__hyper_is_regular(space); + if(is_regular && version == H5S_HYPER_VERSION_2) + flags |= H5S_HYPER_REGULAR; - /* Compute the largest location in this dimension */ - if((int)i == space->select.sel_info.hslab->unlim_dim) - end[i] = H5S_UNLIMITED; - else - end[i] = diminfo[i].start + diminfo[i].stride * (diminfo[i].count - 1) + (diminfo[i].block - 1) + (hsize_t)space->select.offset[i]; - } /* end for */ - } /* end if */ - else { - /* Call the recursive routine to get the bounds for the span tree */ - ret_value = H5S_hyper_bounds_helper(space->select.sel_info.hslab->span_lst, space->select.offset, (hsize_t)0, start, end); - } /* end if */ + /* Store the preamble information */ + UINT32ENCODE(pp, (uint32_t)H5S_GET_SELECT_TYPE(space)); /* Store the type of selection */ + UINT32ENCODE(pp, version); /* Store the version number */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_bounds() */ + if(version == H5S_HYPER_VERSION_2) + *(pp)++ = flags; /* Store the flags */ + else + UINT32ENCODE(pp, (uint32_t)0); /* Store the un-used padding */ + lenp = pp; /* keep the pointer to the length location for later */ + pp += 4; /* skip over space for length */ - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_offset - PURPOSE - Gets the linear offset of the first element for the selection. - USAGE - herr_t H5S__hyper_offset(space, offset) - const H5S_t *space; IN: Dataspace pointer of selection to query - hsize_t *offset; OUT: Linear offset of first element in selection - RETURNS - Non-negative on success, negative on failure - DESCRIPTION - Retrieves the linear offset (in "units" of elements) of the first element - selected within the dataspace. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - Calling this function on a "none" selection returns fail. - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_offset(const H5S_t *space, hsize_t *offset) -{ - const hssize_t *sel_offset; /* Pointer to the selection's offset */ - const hsize_t *dim_size; /* Pointer to a dataspace's extent */ - hsize_t accum; /* Accumulator for dimension sizes */ - unsigned rank; /* Dataspace rank */ - int i; /* index variable */ - herr_t ret_value = SUCCEED; /* Return value */ + len += 4; /* ndims */ - FUNC_ENTER_STATIC + /* Encode number of dimensions */ + UINT32ENCODE(pp, (uint32_t)ndims); + + if(is_regular) { + if(version == H5S_HYPER_VERSION_2) { + HDassert(H5S_UNLIMITED == HSIZE_UNDEF); + + /* Iterate over dimensions */ + /* Encode start/stride/block/count */ + switch(enc_size) { + case H5S_SELECT_INFO_ENC_SIZE_8: + HDassert(version == H5S_HYPER_VERSION_2); + for(u = 0; u < space->extent.rank; u++) { + UINT64ENCODE(pp, diminfo[u].start); + UINT64ENCODE(pp, diminfo[u].stride); + if(diminfo[u].count == H5S_UNLIMITED) + UINT64ENCODE(pp, H5S_UINT64_MAX) + else + UINT64ENCODE(pp, diminfo[u].count) + if(diminfo[u].block == H5S_UNLIMITED) + UINT64ENCODE(pp, H5S_UINT64_MAX) + else + UINT64ENCODE(pp, diminfo[u].block) + } /* end for */ + if(version == H5S_HYPER_VERSION_2) + len += (4 * space->extent.rank * 8); + break; + default: + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab") + break; + } /* end switch */ + } /* end if */ + else { + HDassert(version == H5S_HYPER_VERSION_1); + + /* Set some convienence values */ + fast_dim = ndims - 1; + + /* Encode number of hyperslabs */ + H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t); + UINT32ENCODE(pp, (uint32_t)block_count); + len += 4; + + /* Now serialize the information for the regular hyperslab */ + + /* Build the tables of count sizes as well as the initial offset */ + for(u = 0; u < ndims; u++) { + tmp_count[u] = diminfo[u].count; + offset[u] = diminfo[u].start; + } /* end for */ + + /* Go iterate over the hyperslabs */ + while(complete == FALSE) { + /* Iterate over the blocks in the fastest dimension */ + while(tmp_count[fast_dim] > 0) { + /* Add 8 bytes times the rank for each hyperslab selected */ + len += 8 * ndims; + + /* Encode hyperslab starting location */ + for(u = 0; u < ndims; u++) + UINT32ENCODE(pp, (uint32_t)offset[u]); - HDassert(space && space->extent.rank>0); - HDassert(offset); + /* Encode hyperslab ending location */ + for(u = 0; u < ndims; u++) + UINT32ENCODE(pp, (uint32_t)(offset[u] + (diminfo[u].block - 1))); - /* Start at linear offset 0 */ - *offset = 0; + /* Move the offset to the next sequence to start */ + offset[fast_dim]+=diminfo[fast_dim].stride; - /* Set up pointers to arrays of values */ - rank = space->extent.rank; - sel_offset = space->select.offset; - dim_size = space->extent.size; + /* Decrement the block count */ + tmp_count[fast_dim]--; + } /* end while */ - /* Check for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { - const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->diminfo.opt; /* Local alias for diminfo */ + /* Work on other dimensions if necessary */ + if(fast_dim > 0) { + int temp_dim; /* Temporary rank holder */ - /* Loop through starting coordinates, calculating the linear offset */ - accum = 1; - for(i = (int)(rank - 1); i >= 0; i--) { - hssize_t hyp_offset = (hssize_t)diminfo[i].start + sel_offset[i]; /* Hyperslab's offset in this dimension */ + /* Reset the block counts */ + tmp_count[fast_dim] = diminfo[fast_dim].count; - /* Check for offset moving selection out of the dataspace */ - if(hyp_offset < 0 || (hsize_t)hyp_offset >= dim_size[i]) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds") + /* Bubble up the decrement to the slower changing dimensions */ + temp_dim = (int)fast_dim - 1; + while(temp_dim >= 0 && complete == FALSE) { + /* Decrement the block count */ + tmp_count[temp_dim]--; - /* Add the hyperslab's offset in this dimension to the total linear offset */ - *offset += (hsize_t)(hyp_offset * (hssize_t)accum); + /* Check if we have more blocks left */ + if(tmp_count[temp_dim] > 0) + break; - /* Increase the accumulator */ - accum *= dim_size[i]; - } /* end for */ - } /* end if */ - else { - const H5S_hyper_span_t *span; /* Hyperslab span node */ - hsize_t dim_accum[H5S_MAX_RANK]; /* Accumulators, for each dimension */ + /* Check for getting out of iterator */ + if(temp_dim == 0) + complete = TRUE; - /* Calculate the accumulator for each dimension */ - accum = 1; - for(i = (int)(rank - 1); i >= 0; i--) { - /* Set the accumulator for this dimension */ - dim_accum[i] = accum; + /* Reset the block count in this dimension */ + tmp_count[temp_dim] = diminfo[temp_dim].count; - /* Increase the accumulator */ - accum *= dim_size[i]; - } /* end for */ + /* Wrapped a dimension, go up to next dimension */ + temp_dim--; + } /* end while */ + } /* end if */ + else + break; /* Break out now, for 1-D selections */ - /* Get information for the first span, in the slowest changing dimension */ - span = space->select.sel_info.hslab->span_lst->head; + /* Re-compute offset array */ + for(u = 0; u < ndims; u++) + offset[u] = diminfo[u].start + diminfo[u].stride * (diminfo[u].count - tmp_count[u]); + } /* end while */ + } /* end else */ + } /* end if */ + else { /* irregular */ + /* Encode number of hyperslabs */ + switch(enc_size) { + case H5S_SELECT_INFO_ENC_SIZE_4: + HDassert(version == H5S_HYPER_VERSION_1); + H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t); + UINT32ENCODE(pp, (uint32_t)block_count); + break; - /* Work down the spans, computing the linear offset */ - i = 0; - while(span) { - hssize_t hyp_offset = (hssize_t)span->low + sel_offset[i]; /* Hyperslab's offset in this dimension */ + default: + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab") + break; + } /* end switch */ - /* Check for offset moving selection out of the dataspace */ - if(hyp_offset < 0 || (hsize_t)hyp_offset >= dim_size[i]) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds") + if(version == H5S_HYPER_VERSION_1) { + len += 4; /* block_count */ - /* Add the hyperslab's offset in this dimension to the total linear offset */ - *offset += (hsize_t)(hyp_offset * (hssize_t)dim_accum[i]); + /* Add 8 bytes times the rank for each hyperslab selected */ + H5_CHECK_OVERFLOW((8 * ndims * block_count), hsize_t, size_t); + len += (uint32_t)(8 * ndims * block_count); + } /* end if */ - /* Advance to first span in "down" dimension */ - if(span->down) { - HDassert(span->down->head); - span = span->down->head; - } /* end if */ - else - span = NULL; - i++; - } /* end while */ + H5S__hyper_serialize_helper(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, enc_size, &pp); } /* end else */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_offset() */ + /* Encode length */ + UINT32ENCODE(lenp, (uint32_t)len); /* Store the length of the extra information */ - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_unlim_dim - PURPOSE - Return unlimited dimension of selection, or -1 if none - USAGE - int H5S__hyper_unlim_dim(space) - H5S_t *space; IN: Dataspace pointer to check - RETURNS - Unlimited dimension of selection, or -1 if none (never fails). - DESCRIPTION - Returns the index of the unlimited dimension of the selection, or -1 - if the selection has no unlimited dimension. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static int -H5S__hyper_unlim_dim(const H5S_t *space) -{ - FUNC_ENTER_STATIC_NOERR + /* Update encoding pointer */ + *p = pp; - FUNC_LEAVE_NOAPI(space->select.sel_info.hslab->unlim_dim); -} /* end H5S__hyper_unlim_dim() */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_serialize() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_num_elem_non_unlim + H5S__hyper_deserialize PURPOSE - Return number of elements in the non-unlimited dimensions + Deserialize the current selection from a user-provided buffer. USAGE - herr_t H5S__hyper_num_elem_non_unlim(space,num_elem_non_unlim) - H5S_t *space; IN: Dataspace pointer to check - hsize_t *num_elem_non_unlim; OUT: Number of elements in the non-unlimited dimensions + herr_t H5S__hyper_deserialize(space, p) + H5S_t **space; IN/OUT: Dataspace pointer to place + selection into + uint8 **p; OUT: Pointer to buffer holding serialized + selection. Will be advanced to end of + serialized selection. RETURNS Non-negative on success/Negative on failure DESCRIPTION - Returns the number of elements in a slice through the non-unlimited - dimensions of the selection. Fails if the selection has no unlimited - dimension. + Deserializes the current selection into a buffer. (Primarily for retrieving + from disk). GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ static herr_t -H5S__hyper_num_elem_non_unlim(const H5S_t *space, hsize_t *num_elem_non_unlim) +H5S__hyper_deserialize(H5S_t **space, const uint8_t **p) { - herr_t ret_value = SUCCEED; + H5S_t *tmp_space = NULL; /* Pointer to actual dataspace to use, + either *space or a newly allocated one */ + hsize_t dims[H5S_MAX_RANK]; /* Dimenion sizes */ + hsize_t start[H5S_MAX_RANK]; /* hyperslab start information */ + hsize_t block[H5S_MAX_RANK]; /* hyperslab block information */ + uint32_t version; /* Version number */ + uint8_t flags = 0; /* Flags */ + uint8_t enc_size = 0; /* Encoded size of selection info */ + unsigned rank; /* rank of points */ + const uint8_t *pp; /* Local pointer for decoding */ + unsigned u; /* Local counting variable */ + herr_t ret_value=FAIL; /* return value */ FUNC_ENTER_STATIC - /* Sanity check */ - HDassert(space); - HDassert(num_elem_non_unlim); + /* Check args */ + HDassert(p); + pp = (*p); + HDassert(pp); - /* Get number of elements in the non-unlimited dimensions */ - if(space->select.sel_info.hslab->unlim_dim >= 0) - *num_elem_non_unlim = space->select.sel_info.hslab->num_elem_non_unlim; + /* As part of the efforts to push all selection-type specific coding + to the callbacks, the coding for the allocation of a null dataspace + is moved from H5S_select_deserialize() in H5Sselect.c to here. + This is needed for decoding virtual layout in H5O__layout_decode() */ + /* Allocate space if not provided */ + if(!*space) { + if(NULL == (tmp_space = H5S_create(H5S_SIMPLE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create dataspace") + } /* end if */ else - HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "selection has no unlimited dimension") + tmp_space = *space; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_num_elem_non_unlim() */ + /* Decode version */ + UINT32DECODE(pp, version); - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_is_contiguous - PURPOSE - Check if a hyperslab selection is contiguous within the dataspace extent. - USAGE - htri_t H5S__hyper_is_contiguous(space) - H5S_t *space; IN: Dataspace pointer to check - RETURNS - TRUE/FALSE/FAIL - DESCRIPTION - Checks to see if the current selection in the dataspace is contiguous. - This is primarily used for reading the entire selection in one swoop. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static H5_ATTR_PURE htri_t -H5S__hyper_is_contiguous(const H5S_t *space) -{ - hbool_t small_contiguous, /* Flag for small contiguous block */ - large_contiguous; /* Flag for large contiguous block */ - unsigned u; /* index variable */ - htri_t ret_value = FALSE; /* Return value */ + if(version < H5S_HYPER_VERSION_1 || version > H5S_HYPER_VERSION_LATEST) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "bad version number for hyperslab selection") - FUNC_ENTER_STATIC_NOERR + if(version >= (uint32_t)H5S_HYPER_VERSION_2) { + /* Decode flags */ + flags = *(pp)++; - HDassert(space); + /* Skip over the remainder of the header */ + pp += 4; + enc_size = H5S_SELECT_INFO_ENC_SIZE_8; - /* Check for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { - const H5S_hyper_dim_t *diminfo=space->select.sel_info.hslab->diminfo.opt; /* local alias for diminfo */ + /* Check for unknown flags */ + if(flags & ~H5S_SELECT_FLAG_BITS) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTLOAD, FAIL, "unknown flag for selection") + } + else { + /* Skip over the remainder of the header */ + pp += 8; + enc_size = H5S_SELECT_INFO_ENC_SIZE_4; + } /* end else */ - /* - * For a regular hyperslab to be contiguous, it must have only one - * block (i.e. count==1 in all dimensions) and the block size must be - * the same as the dataspace extent's in all but the slowest changing - * dimension. (dubbed "large contiguous" block) - * - * OR - * - * The selection must have only one block (i.e. count==1) in all - * dimensions and the block size must be 1 in all but the fastest - * changing dimension. (dubbed "small contiguous" block) - */ + /* Check encoded */ + if(enc_size & ~H5S_SELECT_INFO_ENC_SIZE_BITS) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTLOAD, FAIL, "unknown size of point/offset info for selection") + + /* Decode the rank of the point selection */ + UINT32DECODE(pp,rank); + + if(!*space) { + /* Patch the rank of the allocated dataspace */ + HDmemset(dims, 0, (size_t)rank * sizeof(dims[0])); + if(H5S_set_extent_simple(tmp_space, rank, dims, NULL) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't set dimensions") + } /* end if */ + else + /* Verify the rank of the provided dataspace */ + if(rank != tmp_space->extent.rank) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "rank of serialized selection does not match dataspace") - /* Initialize flags */ - large_contiguous = TRUE; /* assume true and reset if the dimensions don't match */ - small_contiguous = FALSE; /* assume false initially */ + if(flags & H5S_HYPER_REGULAR) { + hsize_t stride[H5S_MAX_RANK]; /* Hyperslab stride information */ + hsize_t count[H5S_MAX_RANK]; /* Hyperslab count information */ - /* Check for a "large contigous" block */ - for(u = 0; u < space->extent.rank; u++) { - if(diminfo[u].count > 1) { - large_contiguous = FALSE; + /* Sanity checks */ + HDassert(H5S_UNLIMITED == HSIZE_UNDEF); + HDassert(version >= H5S_HYPER_VERSION_2); + + /* Decode start/stride/block/count */ + switch(enc_size) { + case H5S_SELECT_INFO_ENC_SIZE_4: + for(u = 0; u < tmp_space->extent.rank; u++) { + UINT32DECODE(pp, start[u]); + UINT32DECODE(pp, stride[u]); + + UINT32DECODE(pp, count[u]); + if((uint32_t)count[u] == H5S_UINT32_MAX) + count[u] = H5S_UNLIMITED; + + UINT32DECODE(pp, block[u]); + if((uint32_t)block[u] == H5S_UINT32_MAX) + block[u] = H5S_UNLIMITED; + } /* end for */ break; - } /* end if */ - if(u > 0 && diminfo[u].block != space->extent.size[u]) { - large_contiguous = FALSE; + + case H5S_SELECT_INFO_ENC_SIZE_8: + for(u = 0; u < tmp_space->extent.rank; u++) { + UINT64DECODE(pp, start[u]); + UINT64DECODE(pp, stride[u]); + + UINT64DECODE(pp, count[u]); + if((uint64_t)count[u] == H5S_UINT64_MAX) + count[u] = H5S_UNLIMITED; + + UINT64DECODE(pp, block[u]); + if((uint64_t)block[u] == H5S_UINT64_MAX) + block[u] = H5S_UNLIMITED; + } /* end for */ break; - } /* end if */ - } /* end for */ - /* If we didn't find a large contiguous block, check for a small one */ - if(!large_contiguous) { - small_contiguous = TRUE; - for(u = 0; u < space->extent.rank; u++) { - if(diminfo[u].count > 1) { - small_contiguous = FALSE; - break; - } /* end if */ - if(u < (space->extent.rank - 1) && diminfo[u].block != 1) { - small_contiguous = FALSE; - break; - } /* end if */ - } /* end for */ - } /* end if */ + default: + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab") + break; + } /* end switch */ - /* Indicate true if it's either a large or small contiguous block */ - if(large_contiguous || small_contiguous) - ret_value = TRUE; + /* Select the hyperslab to the current selection */ + if((ret_value = H5S_select_hyperslab(tmp_space, H5S_SELECT_SET, start, stride, count, block)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't change selection") } /* end if */ else { - H5S_hyper_span_info_t *spans; /* Hyperslab span info node */ - H5S_hyper_span_t *span; /* Hyperslab span node */ - - /* - * For a hyperslab to be contiguous, it must have only one block and - * either it's size must be the same as the dataspace extent's in all - * but the slowest changing dimension - * OR - * block size must be 1 in all but the fastest changing dimension. - */ - /* Initialize flags */ - large_contiguous = TRUE; /* assume true and reset if the dimensions don't match */ - small_contiguous = FALSE; /* assume false initially */ - - /* Get information for slowest changing information */ - spans = space->select.sel_info.hslab->span_lst; - span = spans->head; + const hsize_t *stride; /* Hyperslab stride information */ + const hsize_t *count; /* Hyperslab count information */ + hsize_t end[H5S_MAX_RANK]; /* Hyperslab end information */ + hsize_t *tstart; /* Temporary hyperslab pointers */ + hsize_t *tend; /* Temporary hyperslab pointers */ + hsize_t *tblock; /* Temporary hyperslab pointers */ + size_t num_elem; /* Number of elements in selection */ + unsigned v; /* Local counting variable */ - /* If there are multiple spans in the slowest changing dimension, the selection isn't contiguous */ - if(span->next != NULL) - large_contiguous = FALSE; - else { - /* Now check the rest of the dimensions */ - if(span->down != NULL) { - u = 1; /* Current dimension working on */ + /* Decode the number of blocks */ + switch(enc_size) { + case H5S_SELECT_INFO_ENC_SIZE_4: + UINT32DECODE(pp, num_elem); + break; - /* Get the span information for the next fastest dimension */ - spans = span->down; + case H5S_SELECT_INFO_ENC_SIZE_8: + UINT64DECODE(pp, num_elem); + break; - /* Cycle down the spans until we run out of down spans or find a non-contiguous span */ - while(spans != NULL) { - span = spans->head; + default: + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab") + break; + } /* end switch */ - /* Check that this is the only span and it spans the entire dimension */ - if(span->next != NULL) { - large_contiguous = FALSE; - break; - } /* end if */ - else { - /* If this span doesn't cover the entire dimension, then this selection isn't contiguous */ - if(((span->high - span->low) + 1) != space->extent.size[u]) { - large_contiguous = FALSE; - break; - } /* end if */ - else { - /* Walk down to the next span */ - spans = span->down; + /* Set the count & stride for all blocks */ + stride = count = H5S_hyper_ones_g; - /* Increment dimension */ - u++; - } /* end else */ - } /* end else */ - } /* end while */ - } /* end if */ - } /* end else */ + /* Retrieve the coordinates from the buffer */ + for(u = 0; u < num_elem; u++) { + /* Decode the starting and ending points */ + switch(enc_size) { + case H5S_SELECT_INFO_ENC_SIZE_4: + for(tstart = start,v = 0; v < rank; v++, tstart++) + UINT32DECODE(pp, *tstart); + for(tend = end, v = 0; v < rank; v++, tend++) + UINT32DECODE(pp, *tend); + break; - /* If we didn't find a large contiguous block, check for a small one */ - if(!large_contiguous) { - small_contiguous = TRUE; + case H5S_SELECT_INFO_ENC_SIZE_8: + for(tstart = start, v = 0; v < rank; v++, tstart++) + UINT64DECODE(pp, *tstart); + for(tend = end, v = 0; v < rank; v++, tend++) + UINT64DECODE(pp, *tend); + break; - /* Get information for slowest changing information */ - spans = space->select.sel_info.hslab->span_lst; - span = spans->head; + default: + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab") + break; + } /* end switch */ - /* Current dimension working on */ - u = 0; + /* Change the ending points into blocks */ + for(tblock = block, tstart = start, tend = end, v = 0; v < rank; v++, tstart++, tend++, tblock++) + *tblock = (*tend - *tstart) + 1; - /* Cycle down the spans until we run out of down spans or find a non-contiguous span */ - while(spans != NULL) { - span = spans->head; + /* Select or add the hyperslab to the current selection */ + if((ret_value = H5S_select_hyperslab(tmp_space, (u == 0 ? H5S_SELECT_SET : H5S_SELECT_OR), start, stride, count, block)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't change selection") + } /* end for */ + } /* end else */ - /* Check that this is the only span and it spans the entire dimension */ - if(span->next != NULL) { - small_contiguous = FALSE; - break; - } /* end if */ - else { - /* If this span doesn't cover the entire dimension, then this selection isn't contiguous */ - if(u < (space->extent.rank - 1) && ((span->high-span->low) + 1) != 1) { - small_contiguous = FALSE; - break; - } /* end if */ - else { - /* Walk down to the next span */ - spans = span->down; + /* Update decoding pointer */ + *p = pp; - /* Increment dimension */ - u++; - } /* end else */ - } /* end else */ - } /* end while */ - } /* end if */ + /* Return space to the caller if allocated */ + if(!*space) + *space = tmp_space; - /* Indicate true if it's either a large or small contiguous block */ - if(large_contiguous || small_contiguous) - ret_value = TRUE; - } /* end else */ +done: + /* Free temporary space if not passed to caller (only happens on error) */ + if(!*space && tmp_space) + if(H5S_close(tmp_space) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't close dataspace") FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_is_contiguous() */ +} /* end H5S__hyper_deserialize() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_is_single + H5S__hyper_span_blocklist PURPOSE - Check if a hyperslab selection is a single block within the dataspace extent. + Get a list of hyperslab blocks currently selected USAGE - htri_t H5S__hyper_is_single(space) - H5S_t *space; IN: Dataspace pointer to check + herr_t H5S__hyper_span_blocklist(spans, start, end, rank, startblock, numblocks, buf) + H5S_hyper_span_info_t *spans; IN: Dataspace pointer of selection to query + hsize_t start[]; IN/OUT: Accumulated start points + hsize_t end[]; IN/OUT: Accumulated end points + hsize_t rank; IN: Rank of dataspace + hsize_t *startblock; IN/OUT: Hyperslab block to start with + hsize_t *numblocks; IN/OUT: Number of hyperslab blocks to get + hsize_t **buf; OUT: List of hyperslab blocks selected RETURNS - TRUE/FALSE/FAIL + Non-negative on success/Negative on failure DESCRIPTION - Checks to see if the current selection in the dataspace is a single block. - This is primarily used for reading the entire selection in one swoop. + Puts a list of the hyperslab blocks into the user's buffer. The blocks + start with the '*startblock'th block in the list of blocks and put + '*numblocks' number of blocks into the user's buffer (or until the end of + the list of blocks, whichever happens first) + The block coordinates have the same dimensionality (rank) as the + dataspace they are located within. The list of blocks is formatted as + follows: <"start" coordinate> immediately followed by <"opposite" corner + coordinate>, followed by the next "start" and "opposite" coordinate, etc. + until all the block information requested has been put into the user's + buffer. + No guarantee of any order of the blocks is implied. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static H5_ATTR_PURE htri_t -H5S__hyper_is_single(const H5S_t *space) +static herr_t +H5S__hyper_span_blocklist(const H5S_hyper_span_info_t *spans, hsize_t start[], + hsize_t end[], hsize_t rank, hsize_t *startblock, hsize_t *numblocks, + hsize_t **buf) { - htri_t ret_value = TRUE; /* return value */ + const H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */ + herr_t ret_value = SUCCEED; /* return value */ - FUNC_ENTER_STATIC_NOERR + FUNC_ENTER_STATIC - HDassert(space); + /* Sanity checks */ + HDassert(spans); + HDassert(rank < H5S_MAX_RANK); + HDassert(start); + HDassert(end); + HDassert(startblock); + HDassert(numblocks && *numblocks > 0); + HDassert(buf && *buf); - /* Check for a "single" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { - unsigned u; /* index variable */ + /* Walk through the list of spans, recursing or outputting them */ + curr = spans->head; + while(curr != NULL && *numblocks > 0) { + /* Recurse if this node has down spans */ + if(curr->down != NULL) { + /* Add the starting and ending points for this span to the list */ + start[rank] = curr->low; + end[rank] = curr->high; - /* - * For a regular hyperslab to be single, it must have only one - * block (i.e. count==1 in all dimensions) - */ + /* Recurse down to the next dimension */ + if(H5S__hyper_span_blocklist(curr->down, start, end, (rank + 1), startblock, numblocks, buf) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans") + } /* end if */ + else { + /* Skip this block if we haven't skipped all the startblocks yet */ + if(*startblock > 0) { + /* Decrement the starting block */ + (*startblock)--; + } /* end if */ + /* Process this block */ + else { + /* Encode all the previous dimensions starting & ending points */ - /* Check for a single block */ - for(u = 0; u < space->extent.rank; u++) - if(space->select.sel_info.hslab->diminfo.opt[u].count > 1) - HGOTO_DONE(FALSE) - } /* end if */ - else { - H5S_hyper_span_info_t *spans; /* Hyperslab span info node */ + /* Copy previous starting points */ + H5MM_memcpy(*buf, start, rank * sizeof(hsize_t)); + (*buf) += rank; + + /* Copy starting point for this span */ + **buf = curr->low; + (*buf)++; - /* - * For a region to be single, it must have only one block - */ - /* Get information for slowest changing information */ - spans = space->select.sel_info.hslab->span_lst; + /* Copy previous ending points */ + H5MM_memcpy(*buf, end, rank * sizeof(hsize_t)); + (*buf) += rank; - /* Cycle down the spans until we run out of down spans or find a non-contiguous span */ - while(spans != NULL) { - H5S_hyper_span_t *span; /* Hyperslab span node */ + /* Copy ending point for this span */ + **buf = curr->high; + (*buf)++; - span = spans->head; + /* Decrement the number of blocks processed */ + (*numblocks)--; + } /* end else */ + } /* end else */ - /* Check that this is the only span and it spans the entire dimension */ - if(span->next != NULL) - HGOTO_DONE(FALSE) - else - /* Walk down to the next span */ - spans = span->down; - } /* end while */ - } /* end else */ + /* Advance to next node */ + curr = curr->next; + } /* end while */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_is_single() */ +} /* end H5S__hyper_span_blocklist() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_is_regular + H5S__get_select_hyper_blocklist PURPOSE - Check if a hyperslab selection is "regular" + Get the list of hyperslab blocks currently selected USAGE - htri_t H5S__hyper_is_regular(space) - const H5S_t *space; IN: Dataspace pointer to check + herr_t H5S__get_select_hyper_blocklist(space, startblock, numblocks, buf) + H5S_t *space; IN: Dataspace pointer of selection to query + hsize_t startblock; IN: Hyperslab block to start with + hsize_t numblocks; IN: Number of hyperslab blocks to get + hsize_t *buf; OUT: List of hyperslab blocks selected RETURNS - TRUE/FALSE/FAIL + Non-negative on success, negative on failure DESCRIPTION - Checks to see if the current selection in a dataspace is the a regular - pattern. - This is primarily used for reading the entire selection in one swoop. + Puts a list of the hyperslab blocks into the user's buffer. The blocks + start with the 'startblock'th block in the list of blocks and put + 'numblocks' number of blocks into the user's buffer (or until the end of + the list of blocks, whichever happens first) + The block coordinates have the same dimensionality (rank) as the + dataspace they are located within. The list of blocks is formatted as + follows: <"start" coordinate> immediately followed by <"opposite" corner + coordinate>, followed by the next "start" and "opposite" coordinate, etc. + until all the block information requested has been put into the user's + buffer. + No guarantee of any order of the blocks is implied. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS - Doesn't check for "regular" hyperslab selections composed of spans EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static htri_t -H5S__hyper_is_regular(const H5S_t *space) +static herr_t +H5S__get_select_hyper_blocklist(H5S_t *space, hsize_t startblock, + hsize_t numblocks, hsize_t *buf) { - htri_t ret_value = FAIL; /* return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC_NOERR - /* Check args */ HDassert(space); + HDassert(buf); + HDassert(space->select.sel_info.hslab->unlim_dim < 0); - /* Only simple check for regular hyperslabs for now... */ - if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) - ret_value = TRUE; - else - ret_value = FALSE; + /* Attempt to rebuild diminfo if it is invalid and has not been confirmed + * to be impossible. + */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO) + H5S__hyper_rebuild(space); - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_is_regular() */ + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + const H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */ + hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary hyperslab counts */ + hsize_t offset[H5S_MAX_RANK]; /* Offset of element in dataspace */ + hsize_t end[H5S_MAX_RANK]; /* End of elements in dataspace */ + unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + unsigned ndims; /* Rank of the dataspace */ + hbool_t done; /* Whether we are done with the iteration */ + unsigned u; /* Counter */ - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_release - PURPOSE - Release hyperslab selection information for a dataspace - USAGE - herr_t H5S__hyper_release(space) - H5S_t *space; IN: Pointer to dataspace - RETURNS - Non-negative on success/Negative on failure - DESCRIPTION - Releases all hyperslab selection information for a dataspace - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_release(H5S_t *space) -{ - herr_t ret_value = SUCCEED; + /* Set some convienence values */ + ndims = space->extent.rank; + fast_dim = ndims - 1; - FUNC_ENTER_STATIC + /* Check which set of dimension information to use */ + if(space->select.sel_info.hslab->unlim_dim >= 0) + /* + * There is an unlimited dimension so we must use diminfo.opt as + * it has been "clipped" to the current extent. + */ + diminfo = space->select.sel_info.hslab->diminfo.opt; + else + /* + * Use the "application dimension information" to pass back to + * the user the blocks they set, not the optimized, internal + * information. + */ + diminfo = space->select.sel_info.hslab->diminfo.app; - /* Check args */ - HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space)); + /* Build the tables of count sizes as well as the initial offset */ + for(u = 0; u < ndims; u++) { + tmp_count[u] = diminfo[u].count; + offset[u] = diminfo[u].start; + end[u] = diminfo[u].start + (diminfo[u].block - 1); + } /* end for */ - /* Reset the number of points selected */ - space->select.num_elem = 0; + /* We're not done with the iteration */ + done = FALSE; - /* Release irregular hyperslab information */ - if(space->select.sel_info.hslab) { - if(space->select.sel_info.hslab->span_lst != NULL) - if(H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans") + /* Go iterate over the hyperslabs */ + while(!done && numblocks > 0) { + /* Skip over initial blocks */ + if(startblock > 0) { + /* Skip all blocks in row */ + if(startblock >= tmp_count[fast_dim]) { + startblock -= tmp_count[fast_dim]; + tmp_count[fast_dim] = 0; + } /* end if */ + else { + /* Move the offset to the next sequence to start */ + offset[fast_dim] += diminfo[fast_dim].stride * startblock; + end[fast_dim] += diminfo[fast_dim].stride * startblock; - /* Release space for the hyperslab selection information */ - space->select.sel_info.hslab = H5FL_FREE(H5S_hyper_sel_t, space->select.sel_info.hslab); + /* Decrement the block count */ + tmp_count[fast_dim] -= startblock; + + /* Done with starting blocks */ + startblock = 0; + } /* end else */ + } /* end if */ + + /* Iterate over the blocks in the fastest dimension */ + while(tmp_count[fast_dim] > 0 && numblocks > 0) { + /* Sanity check */ + HDassert(startblock == 0); + + /* Copy the starting location */ + H5MM_memcpy(buf, offset, sizeof(hsize_t) * ndims); + buf += ndims; + + /* Compute the ending location */ + H5MM_memcpy(buf, end, sizeof(hsize_t) * ndims); + buf += ndims; + + /* Decrement the number of blocks to retrieve */ + numblocks--; + + /* Move the offset to the next sequence to start */ + offset[fast_dim] += diminfo[fast_dim].stride; + end[fast_dim] += diminfo[fast_dim].stride; + + /* Decrement the block count */ + tmp_count[fast_dim]--; + } /* end while */ + + /* Work on other dimensions if necessary */ + if(fast_dim > 0 && numblocks > 0) { + int temp_dim; /* Temporary rank holder */ + + /* Reset the block counts */ + tmp_count[fast_dim] = diminfo[fast_dim].count; + + /* Bubble up the decrement to the slower changing dimensions */ + temp_dim = (int)(fast_dim - 1); + while(temp_dim >= 0 && !done) { + /* Decrement the block count */ + tmp_count[temp_dim]--; + + /* Check if we have more blocks left */ + if(tmp_count[temp_dim] > 0) + break; + + /* Reset the block count in this dimension */ + tmp_count[temp_dim] = diminfo[temp_dim].count; + + /* Check for getting out of iterator */ + if(temp_dim == 0) + done = TRUE; + + /* Wrapped a dimension, go up to next dimension */ + temp_dim--; + } /* end while */ + } /* end if */ + + /* Re-compute offset & end arrays */ + if(!done) + for(u = 0; u < ndims; u++) { + offset[u] = diminfo[u].start + diminfo[u].stride * (diminfo[u].count - tmp_count[u]); + end[u] = offset[u] + (diminfo[u].block - 1); + } /* end for */ + } /* end while */ } /* end if */ + else { + hsize_t start[H5S_MAX_RANK]; /* Location of start of hyperslab */ + hsize_t end[H5S_MAX_RANK]; /* Location of end of hyperslab */ + + ret_value = H5S__hyper_span_blocklist(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, &startblock, &numblocks, &buf); + } /* end else */ -done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_release() */ +} /* end H5S__get_select_hyper_blocklist() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_recover_span + H5Sget_select_hyper_blocklist PURPOSE - Recover a generated span, if appropriate + Get the list of hyperslab blocks currently selected USAGE - herr_t H5S__hyper_recover_span(recover, curr_span, next_span) - unsigned *recover; IN/OUT: Pointer recover flag - H5S_hyper_span_t **curr_span; IN/OUT: Pointer to current span in list - H5S_hyper_span_t *next_span; IN: Pointer to next span + herr_t H5Sget_select_hyper_blocklist(dsid, startblock, numblocks, buf) + hid_t dsid; IN: Dataspace ID of selection to query + hsize_t startblock; IN: Hyperslab block to start with + hsize_t numblocks; IN: Number of hyperslab blocks to get + hsize_t buf[]; OUT: List of hyperslab blocks selected RETURNS Non-negative on success, negative on failure DESCRIPTION - Check if the current span needs to be recovered and free it if so. - Set the current span to the next span in any case. + Puts a list of the hyperslab blocks into the user's buffer. The blocks + start with the 'startblock'th block in the list of blocks and put + 'numblocks' number of blocks into the user's buffer (or until the end of + the list of blocks, whichever happen first) + The block coordinates have the same dimensionality (rank) as the + dataspace they are located within. The list of blocks is formatted as + follows: <"start" coordinate> immediately followed by <"opposite" corner + coordinate>, followed by the next "start" and "opposite" coordinate, etc. + until all the block information requested has been put into the user's + buffer. + No guarantee of any order of the blocks is implied. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_recover_span(hbool_t *recover, H5S_hyper_span_t **curr_span, H5S_hyper_span_t *next_span) +herr_t +H5Sget_select_hyper_blocklist(hid_t spaceid, hsize_t startblock, + hsize_t numblocks, hsize_t buf[/*numblocks*/]) { - FUNC_ENTER_STATIC_NOERR + H5S_t *space; /* Dataspace to modify selection of */ + herr_t ret_value; /* return value */ - HDassert(recover); - HDassert(curr_span); + FUNC_ENTER_API(FAIL) + H5TRACE4("e", "ihh*[a2]h", spaceid, startblock, numblocks, buf); - /* Check if the span should be recovered */ - if(*recover) { - H5S__hyper_free_span(*curr_span); - *recover = FALSE; - } /* end if */ + /* Check args */ + if(buf == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid pointer") + if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + if(H5S_GET_SELECT_TYPE(space)!=H5S_SEL_HYPERSLABS) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection") + if(space->select.sel_info.hslab->unlim_dim >= 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot get blocklist for unlimited selection") - /* Set the current span to next span */ - *curr_span = next_span; + /* Go get the correct number of blocks */ + if(numblocks > 0) + ret_value = H5S__get_select_hyper_blocklist(space, startblock, numblocks, buf); + else + ret_value = SUCCEED; /* Successfully got 0 blocks... */ - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_recover_span() */ +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Sget_select_hyper_blocklist() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_coord_to_span + H5S__hyper_bounds PURPOSE - Create a span tree for a single element + Gets the bounding box containing the selection. USAGE - H5S_hyper_span_t *H5S__hyper_coord_to_span(rank, coords) - unsigned rank; IN: Number of dimensions of coordinate - hsize_t *coords; IN: Location of element + herr_t H5S__hyper_bounds(space, hsize_t *start, hsize_t *end) + H5S_t *space; IN: Dataspace pointer of selection to query + hsize_t *start; OUT: Starting coordinate of bounding box + hsize_t *end; OUT: Opposite coordinate of bounding box RETURNS Non-negative on success, negative on failure DESCRIPTION - Create a span tree for a single element + Retrieves the bounding box containing the current selection and places + it into the user's buffers. The start and end buffers must be large + enough to hold the dataspace rank number of coordinates. The bounding box + exactly contains the selection, ie. if a 2-D element selection is currently + defined with the following points: (4,5), (6,8) (10,7), the bounding box + with be (4, 5), (10, 8). + The bounding box calculations _does_ include the current offset of the + selection within the dataspace extent. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static H5S_hyper_span_t * -H5S__hyper_coord_to_span(unsigned rank, const hsize_t *coords) +static herr_t +H5S__hyper_bounds(const H5S_t *space, hsize_t *start, hsize_t *end) { - H5S_hyper_span_t *new_span; /* Pointer to new span tree for coordinate */ - H5S_hyper_span_info_t *down = NULL; /* Pointer to new span tree for next level down */ - H5S_hyper_span_t *ret_value = NULL; /* Return value */ + const hsize_t *low_bounds, *high_bounds; /* Pointers to the correct pair of low & high bounds */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC - HDassert(rank > 0); - HDassert(coords); + /* Sanity check */ + HDassert(space); + HDassert(start); + HDassert(end); - /* Search for location to insert new element in tree */ - if(rank > 1) { - /* Allocate a span info node */ - if(NULL == (down = H5FL_CALLOC(H5S_hyper_span_info_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") + /* Check which set of low & high bounds we should be using */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + low_bounds = space->select.sel_info.hslab->diminfo.low_bounds; + high_bounds = space->select.sel_info.hslab->diminfo.high_bounds; + } /* end if */ + else { + low_bounds = space->select.sel_info.hslab->span_lst->low_bounds; + high_bounds = space->select.sel_info.hslab->span_lst->high_bounds; + } /* end else */ + /* Check for offset set */ + if(space->select.offset_changed) { + unsigned u; /* Local index variable */ - /* Build span tree for coordinates below this one */ - if(NULL == (down->head = H5S__hyper_coord_to_span(rank - 1, &coords[1]))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") - } /* end if */ + /* Loop over dimensions */ + for(u = 0; u < space->extent.rank; u++) { + /* Sanity check */ + HDassert(low_bounds[u] <= high_bounds[u]); - /* Build span for this coordinate */ - if(NULL == (new_span = H5S__hyper_new_span(coords[0], coords[0], down, NULL))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") + /* Check for offset moving selection negative */ + if(((hssize_t)low_bounds[u] + space->select.offset[u]) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds") - /* Set return value */ - ret_value = new_span; + /* Set the low & high bounds in this dimension */ + start[u] = (hsize_t)((hssize_t)low_bounds[u] + space->select.offset[u]); + if((int)u == space->select.sel_info.hslab->unlim_dim) + end[u] = H5S_UNLIMITED; + else + end[u] = (hsize_t)((hssize_t)high_bounds[u] + space->select.offset[u]); + } /* end for */ + } /* end if */ + else { + /* Offset vector is still zeros, just copy low & high bounds */ + H5MM_memcpy(start, low_bounds, sizeof(hsize_t) * space->extent.rank); + H5MM_memcpy(end, high_bounds, sizeof(hsize_t) * space->extent.rank); + } /* end else */ done: - if(ret_value == NULL && down != NULL) - H5S__hyper_free_span_info(down); - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_coord_to_span() */ +} /* end H5S__hyper_bounds() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_add_span_element_helper + H5S__hyper_offset PURPOSE - Add a single element to a span tree + Gets the linear offset of the first element for the selection. USAGE - herr_t H5S_hyper_add_span_element_helper(prev_span, span_tree, rank, coords) - H5S_hyper_span_info_t *span_tree; IN/OUT: Pointer to span tree to append to - unsigned rank; IN: Number of dimensions of coordinates - hsize_t *coords; IN: Location of element to add to span tree + herr_t H5S__hyper_offset(space, offset) + const H5S_t *space; IN: Dataspace pointer of selection to query + hsize_t *offset; OUT: Linear offset of first element in selection RETURNS Non-negative on success, negative on failure DESCRIPTION - Add a single element to an existing span tree. + Retrieves the linear offset (in "units" of elements) of the first element + selected within the dataspace. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS - Assumes that the element is not already covered by the span tree + Calling this function on a "none" selection returns fail. EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ static herr_t -H5S__hyper_add_span_element_helper(H5S_hyper_span_info_t *span_tree, - unsigned rank, const hsize_t *coords) +H5S__hyper_offset(const H5S_t *space, hsize_t *offset) { - H5S_hyper_span_info_t *tspan_info; /* Temporary pointer to span info */ - H5S_hyper_span_info_t *prev_span_info; /* Pointer to span info for level above current position */ - H5S_hyper_span_t *tmp_span; /* Temporary pointer to a span */ - H5S_hyper_span_t *tmp2_span; /* Another temporary pointer to a span */ - H5S_hyper_span_t *new_span; /* New span created for element */ - herr_t ret_value = SUCCEED; /* Return value */ + const hssize_t *sel_offset; /* Pointer to the selection's offset */ + const hsize_t *dim_size; /* Pointer to a dataspace's extent */ + hsize_t accum; /* Accumulator for dimension sizes */ + unsigned rank; /* Dataspace rank */ + int i; /* index variable */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC - /* Sanity check */ - HDassert(span_tree); - HDassert(rank > 0); - HDassert(coords); - - /* Get pointer to last span in span tree */ - tspan_info=span_tree; - if(span_tree->scratch) - tmp_span=(H5S_hyper_span_t *)span_tree->scratch; - else { - tmp_span=span_tree->head; - HDassert(tmp_span); - span_tree->scratch=(H5S_hyper_span_info_t *)tmp_span; - } /* end else */ - - /* Find last span tree which includes a portion of the coordinate */ - prev_span_info=NULL; - while(coords[0]>=tmp_span->low && coords[0]<=tmp_span->high) { - /* Move rank & coordinate offset down a dimension */ - rank--; - coords++; - - /* Remember the span tree we are descending into */ - prev_span_info=tspan_info; - tspan_info=tmp_span->down; - - /* Get the last span in this span's 'down' tree */ - if(tspan_info->scratch) - tmp_span=(H5S_hyper_span_t *)tspan_info->scratch; - else { - tmp_span=tspan_info->head; - HDassert(tmp_span); - tspan_info->scratch=(H5S_hyper_span_info_t *)tmp_span; - } /* end else */ - } /* end while */ - - /* Check if we made it all the way to the bottom span in the tree */ - if(rank>1) { - /* Before we create another span at this level in the tree, check if - * the last span's "down tree" was equal to any other spans in this - * list of spans in the span tree. - * - * If so, release last span information and make last span merge into - * previous span (if possible), or at least share their "down tree" - * information. - */ - tmp2_span=tspan_info->head; - while(tmp2_span!=tmp_span) { - if(H5S__hyper_cmp_spans(tmp2_span->down,tmp_span->down)==TRUE) { - /* Check for merging into previous span */ - if(tmp2_span->high+1==tmp_span->low) { - /* Release last span created */ - H5S__hyper_free_span(tmp_span); - - /* Increase size of previous span */ - tmp2_span->high++; - tmp2_span->nelem++; - - /* Reset the 'tmp_span' for the rest of this block's algorithm */ - tmp_span=tmp2_span; - } /* end if */ - /* Span is disjoint, but has the same "down tree" selection */ - else { - /* Release "down tree" information */ - H5S__hyper_free_span_info(tmp_span->down); - - /* Point at earlier span's "down tree" */ - tmp_span->down=tmp2_span->down; + HDassert(space && space->extent.rank>0); + HDassert(offset); - /* Increment reference count on shared "down tree" */ - tmp_span->down->count++; - } /* end else */ + /* Start at linear offset 0 */ + *offset = 0; - /* Found span to merge into, break out now */ - break; - } /* end if */ + /* Set up pointers to arrays of values */ + rank = space->extent.rank; + sel_offset = space->select.offset; + dim_size = space->extent.size; - /* Advance to next span to check */ - tmp2_span=tmp2_span->next; - } /* end while */ + /* Check for a "regular" hyperslab selection */ + /* (No need to rebuild the dimension info yet -QAK) */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->diminfo.opt; /* Local alias for diminfo */ - /* Make span tree for current coordinates */ - if(NULL == (new_span = H5S__hyper_coord_to_span(rank, coords))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + /* Loop through starting coordinates, calculating the linear offset */ + accum = 1; + for(i = (int)(rank - 1); i >= 0; i--) { + hssize_t hyp_offset = (hssize_t)diminfo[i].start + sel_offset[i]; /* Hyperslab's offset in this dimension */ - /* Add new span tree as span */ - HDassert(tmp_span); - tmp_span->next=new_span; + /* Check for offset moving selection out of the dataspace */ + if(hyp_offset < 0 || (hsize_t)hyp_offset >= dim_size[i]) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds") - /* Make scratch pointer point to last span in list */ - HDassert(tspan_info); - tspan_info->scratch=(H5S_hyper_span_info_t *)new_span; + /* Add the hyperslab's offset in this dimension to the total linear offset */ + *offset += (hsize_t)(hyp_offset * (hssize_t)accum); - /* Set the proper 'pstride' for new span */ - new_span->pstride=new_span->low-tmp_span->low; + /* Increase the accumulator */ + accum *= dim_size[i]; + } /* end for */ } /* end if */ else { - /* Does new node adjoin existing node? */ - if(tmp_span->high+1==coords[0]) { - tmp_span->high++; - tmp_span->nelem++; - - /* Check if this span tree should now be merged with a level higher in the tree */ - if(prev_span_info!=NULL) { - /* Before we create another span at this level in the tree, check if - * the last span's "down tree" was equal to any other spans in this - * list of spans in the span tree. - * - * If so, release last span information and make last span merge into - * previous span (if possible), or at least share their "down tree" - * information. - */ - tmp2_span=prev_span_info->head; - tmp_span=(H5S_hyper_span_t *)prev_span_info->scratch; - while(tmp2_span!=tmp_span) { - if(H5S__hyper_cmp_spans(tmp2_span->down,tmp_span->down)==TRUE) { - /* Check for merging into previous span */ - if(tmp2_span->high+1==tmp_span->low) { - /* Release last span created */ - H5S__hyper_free_span(tmp_span); - - /* Increase size of previous span */ - tmp2_span->high++; - tmp2_span->nelem++; - - /* Update pointers */ - tmp2_span->next=NULL; - prev_span_info->scratch=(H5S_hyper_span_info_t *)tmp2_span; - } /* end if */ - /* Span is disjoint, but has the same "down tree" selection */ - else { - /* Release "down tree" information */ - H5S__hyper_free_span_info(tmp_span->down); + const H5S_hyper_span_t *span; /* Hyperslab span node */ + hsize_t dim_accum[H5S_MAX_RANK]; /* Accumulators, for each dimension */ - /* Point at earlier span's "down tree" */ - tmp_span->down=tmp2_span->down; + /* Calculate the accumulator for each dimension */ + accum = 1; + for(i = (int)(rank - 1); i >= 0; i--) { + /* Set the accumulator for this dimension */ + dim_accum[i] = accum; - /* Increment reference count on shared "down tree" */ - tmp_span->down->count++; - } /* end else */ + /* Increase the accumulator */ + accum *= dim_size[i]; + } /* end for */ - /* Found span to merge into, break out now */ - break; - } /* end if */ + /* Get information for the first span, in the slowest changing dimension */ + span = space->select.sel_info.hslab->span_lst->head; - /* Advance to next span to check */ - tmp2_span=tmp2_span->next; - } /* end while */ - } /* end if */ - } /* end if */ - else { - if(NULL == (new_span = H5S__hyper_new_span(coords[0], coords[0], NULL, NULL))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + /* Work down the spans, computing the linear offset */ + i = 0; + while(span) { + hssize_t hyp_offset = (hssize_t)span->low + sel_offset[i]; /* Hyperslab's offset in this dimension */ - /* Add new span tree as span */ - HDassert(tmp_span); - tmp_span->next=new_span; + /* Check for offset moving selection out of the dataspace */ + if(hyp_offset < 0 || (hsize_t)hyp_offset >= dim_size[i]) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds") - /* Make scratch pointer point to last span in list */ - tspan_info->scratch=(H5S_hyper_span_info_t *)new_span; + /* Add the hyperslab's offset in this dimension to the total linear offset */ + *offset += (hsize_t)(hyp_offset * (hssize_t)dim_accum[i]); - /* Set the proper 'pstride' for new span */ - new_span->pstride = new_span->low - tmp_span->low; - } /* end else */ + /* Advance to first span in "down" dimension */ + if(span->down) { + HDassert(span->down->head); + span = span->down->head; + } /* end if */ + else + span = NULL; + i++; + } /* end while */ } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_add_span_element_helper() */ +} /* end H5S__hyper_offset() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_add_span_element + H5S__hyper_unlim_dim PURPOSE - Add a single element to a span tree + Return unlimited dimension of selection, or -1 if none USAGE - herr_t H5S_hyper_add_span_element(space, span_tree, rank, coords) - H5S_t *space; IN/OUT: Pointer to dataspace to add coordinate to - unsigned rank; IN: Number of dimensions of coordinates - hsize_t *coords; IN: Location of element to add to span tree + int H5S__hyper_unlim_dim(space) + H5S_t *space; IN: Dataspace pointer to check RETURNS - Non-negative on success, negative on failure + Unlimited dimension of selection, or -1 if none (never fails). DESCRIPTION - Add a single element to an existing span tree. + Returns the index of the unlimited dimension of the selection, or -1 + if the selection has no unlimited dimension. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS - Assumes that the element is not already in the dataspace's selection EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -herr_t -H5S_hyper_add_span_element(H5S_t *space, unsigned rank, const hsize_t *coords) +static int +H5S__hyper_unlim_dim(const H5S_t *space) { - H5S_hyper_span_info_t *head = NULL; /* Pointer to new head of span tree */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(FAIL) - - HDassert(space); - HDassert(rank > 0); - HDassert(coords); - HDassert(space->extent.rank == rank); - - /* Check if this is the first element in the selection */ - if(NULL == space->select.sel_info.hslab) { - /* Allocate a span info node */ - if(NULL == (head = H5FL_CALLOC(H5S_hyper_span_info_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span info") - - /* Set the reference count */ - head->count = 1; - - /* Build span tree for this coordinate */ - if(NULL == (head->head = H5S__hyper_coord_to_span(rank, coords))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab spans for coordinate") - - /* Allocate selection info */ - if(NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab selection") - - /* Set the selection to the new span tree */ - space->select.sel_info.hslab->span_lst = head; - - /* Set selection type */ - space->select.type = H5S_sel_hyper; - - /* Reset "regular" hyperslab flag */ - space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; - - /* Set unlim_dim */ - space->select.sel_info.hslab->unlim_dim = -1; - - /* Set # of elements in selection */ - space->select.num_elem = 1; - } /* end if */ - else { - if(H5S__hyper_add_span_element_helper(space->select.sel_info.hslab->span_lst, rank, coords) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert coordinate into span tree") - - /* Increment # of elements in selection */ - space->select.num_elem++; - } /* end else */ - -done: - if(ret_value < 0) - if(head) - H5S__hyper_free_span_info(head); + FUNC_ENTER_STATIC_NOERR - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_add_span_element() */ + FUNC_LEAVE_NOAPI(space->select.sel_info.hslab->unlim_dim); +} /* end H5S__hyper_unlim_dim() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_reset_scratch + H5S__hyper_num_elem_non_unlim PURPOSE - Reset the scratch information for span tree + Return number of elements in the non-unlimited dimensions USAGE - herr_t H5S_hyper_reset_scratch(space) - H5S_t *space; IN/OUT: Pointer to dataspace to reset scratch pointers + herr_t H5S__hyper_num_elem_non_unlim(space,num_elem_non_unlim) + H5S_t *space; IN: Dataspace pointer to check + hsize_t *num_elem_non_unlim; OUT: Number of elements in the non-unlimited dimensions RETURNS - Non-negative on success, negative on failure + Non-negative on success/Negative on failure DESCRIPTION - Resets the "scratch" pointers used for various tasks in computing hyperslab - spans. + Returns the number of elements in a slice through the non-unlimited + dimensions of the selection. Fails if the selection has no unlimited + dimension. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -herr_t -H5S_hyper_reset_scratch(H5S_t *space) +static herr_t +H5S__hyper_num_elem_non_unlim(const H5S_t *space, hsize_t *num_elem_non_unlim) { - herr_t ret_value = SUCCEED; /* Return value */ + herr_t ret_value = SUCCEED; - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_STATIC + /* Sanity check */ HDassert(space); + HDassert(num_elem_non_unlim); - /* Check if there are spans in the span tree */ - if(space->select.sel_info.hslab->span_lst != NULL) - /* Reset the scratch pointers for the next routine which needs them */ - H5S__hyper_span_scratch(space->select.sel_info.hslab->span_lst); + /* Get number of elements in the non-unlimited dimensions */ + if(space->select.sel_info.hslab->unlim_dim >= 0) + *num_elem_non_unlim = space->select.sel_info.hslab->num_elem_non_unlim; + else + HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "selection has no unlimited dimension") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_reset_scratch() */ +} /* end H5S__hyper_num_elem_non_unlim() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_convert + H5S__hyper_is_contiguous PURPOSE - Convert a compatible selection to span tree form + Check if a hyperslab selection is contiguous within the dataspace extent. USAGE - herr_t H5S_hyper_convert(space) - H5S_t *space; IN/OUT: Pointer to dataspace to convert + htri_t H5S__hyper_is_contiguous(space) + H5S_t *space; IN: Dataspace pointer to check RETURNS - Non-negative on success, negative on failure + TRUE/FALSE/FAIL DESCRIPTION - Converts a compatible selection (currently only "all" selections) to the - span-tree form of a hyperslab selection. (Point and "none" selection aren't - currently supported and hyperslab selection always have the span-tree form - available). + Checks to see if the current selection in the dataspace is contiguous. + This is primarily used for reading the entire selection in one swoop. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -herr_t -H5S_hyper_convert(H5S_t *space) +static H5_ATTR_PURE htri_t +H5S__hyper_is_contiguous(const H5S_t *space) { - herr_t ret_value = SUCCEED; /* Return value */ + hbool_t small_contiguous, /* Flag for small contiguous block */ + large_contiguous; /* Flag for large contiguous block */ + unsigned u; /* index variable */ + htri_t ret_value = FALSE; /* Return value */ - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_STATIC_NOERR HDassert(space); - /* Check the type of selection */ - switch(H5S_GET_SELECT_TYPE(space)) { - case H5S_SEL_ALL: /* All elements selected in dataspace */ - /* Convert current "all" selection to "real" hyperslab selection */ - { - const hsize_t *tmp_start; /* Temporary start information */ - const hsize_t *tmp_stride; /* Temporary stride information */ - const hsize_t *tmp_count; /* Temporary count information */ - const hsize_t *tmp_block; /* Temporary block information */ - - /* Set up temporary information for the dimensions */ - tmp_start = H5S_hyper_zeros_g; - tmp_stride = tmp_count = H5S_hyper_ones_g; - tmp_block = space->extent.size; - - /* Convert to hyperslab selection */ - if(H5S_select_hyperslab(space,H5S_SELECT_SET,tmp_start,tmp_stride,tmp_count,tmp_block)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't convert selection") - } /* end case */ - break; + /* Check for a "regular" hyperslab selection */ + /* (No need to rebuild the dimension info yet -QAK) */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + const H5S_hyper_dim_t *diminfo=space->select.sel_info.hslab->diminfo.opt; /* local alias for diminfo */ - case H5S_SEL_HYPERSLABS: /* Hyperslab selection */ - break; + /* + * For a regular hyperslab to be contiguous, it must have only one + * block (i.e. count==1 in all dimensions) and the block size must be + * the same as the dataspace extent's in all but the slowest changing + * dimension. (dubbed "large contiguous" block) + * + * OR + * + * The selection must have only one block (i.e. count==1) in all + * dimensions and the block size must be 1 in all but the fastest + * changing dimension. (dubbed "small contiguous" block) + */ - case H5S_SEL_NONE: /* No elements selected in dataspace */ - case H5S_SEL_POINTS: /* Point selection */ - case H5S_SEL_ERROR: /* Selection error */ - case H5S_SEL_N: /* Selection count */ - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "can't convert to span tree selection") - } /* end switch */ + /* Initialize flags */ + large_contiguous = TRUE; /* assume true and reset if the dimensions don't match */ + small_contiguous = FALSE; /* assume false initially */ + + /* Check for a "large contigous" block */ + for(u = 0; u < space->extent.rank; u++) { + if(diminfo[u].count > 1) { + large_contiguous = FALSE; + break; + } /* end if */ + if(u > 0 && diminfo[u].block != space->extent.size[u]) { + large_contiguous = FALSE; + break; + } /* end if */ + } /* end for */ + + /* If we didn't find a large contiguous block, check for a small one */ + if(!large_contiguous) { + small_contiguous = TRUE; + for(u = 0; u < space->extent.rank; u++) { + if(diminfo[u].count > 1) { + small_contiguous = FALSE; + break; + } /* end if */ + if(u < (space->extent.rank - 1) && diminfo[u].block != 1) { + small_contiguous = FALSE; + break; + } /* end if */ + } /* end for */ + } /* end if */ + + /* Indicate true if it's either a large or small contiguous block */ + if(large_contiguous || small_contiguous) + ret_value = TRUE; + } /* end if */ + else { + H5S_hyper_span_info_t *spans; /* Hyperslab span info node */ + H5S_hyper_span_t *span; /* Hyperslab span node */ + + /* + * For a hyperslab to be contiguous, it must have only one block and + * either it's size must be the same as the dataspace extent's in all + * but the slowest changing dimension + * OR + * block size must be 1 in all but the fastest changing dimension. + */ + /* Initialize flags */ + large_contiguous = TRUE; /* assume true and reset if the dimensions don't match */ + small_contiguous = FALSE; /* assume false initially */ + + /* Get information for slowest changing information */ + spans = space->select.sel_info.hslab->span_lst; + span = spans->head; + + /* If there are multiple spans in the slowest changing dimension, the selection isn't contiguous */ + if(span->next != NULL) + large_contiguous = FALSE; + else { + /* Now check the rest of the dimensions */ + if(span->down != NULL) { + u = 1; /* Current dimension working on */ + + /* Get the span information for the next fastest dimension */ + spans = span->down; + + /* Cycle down the spans until we run out of down spans or find a non-contiguous span */ + while(spans != NULL) { + span = spans->head; + + /* Check that this is the only span and it spans the entire dimension */ + if(span->next != NULL) { + large_contiguous = FALSE; + break; + } /* end if */ + else { + /* If this span doesn't cover the entire dimension, then this selection isn't contiguous */ + if(((span->high - span->low) + 1) != space->extent.size[u]) { + large_contiguous = FALSE; + break; + } /* end if */ + else { + /* Walk down to the next span */ + spans = span->down; + + /* Increment dimension */ + u++; + } /* end else */ + } /* end else */ + } /* end while */ + } /* end if */ + } /* end else */ + + /* If we didn't find a large contiguous block, check for a small one */ + if(!large_contiguous) { + small_contiguous = TRUE; + + /* Get information for slowest changing information */ + spans = space->select.sel_info.hslab->span_lst; + span = spans->head; + + /* Current dimension working on */ + u = 0; + + /* Cycle down the spans until we run out of down spans or find a non-contiguous span */ + while(spans != NULL) { + span = spans->head; + + /* Check that this is the only span and it spans the entire dimension */ + if(span->next != NULL) { + small_contiguous = FALSE; + break; + } /* end if */ + else { + /* If this span doesn't cover the entire dimension, then this selection isn't contiguous */ + if(u < (space->extent.rank - 1) && ((span->high-span->low) + 1) != 1) { + small_contiguous = FALSE; + break; + } /* end if */ + else { + /* Walk down to the next span */ + spans = span->down; + + /* Increment dimension */ + u++; + } /* end else */ + } /* end else */ + } /* end while */ + } /* end if */ + + /* Indicate true if it's either a large or small contiguous block */ + if(large_contiguous || small_contiguous) + ret_value = TRUE; + } /* end else */ -done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_convert() */ +} /* end H5S__hyper_is_contiguous() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_intersect_block_helper + H5S__hyper_is_single PURPOSE - Helper routine to detect intersections in span trees + Check if a hyperslab selection is a single block within the dataspace extent. USAGE - htri_t H5S_hyper_intersect_block_helper(spans, start, end) - H5S_hyper_span_info_t *spans; IN: First span tree to operate with - hssize_t *offset; IN: Selection offset coordinate - hsize_t *start; IN: Starting coordinate for block - hsize_t *end; IN: Ending coordinate for block - RETURN - Non-negative on success, negative on failure + htri_t H5S__hyper_is_single(space) + H5S_t *space; IN: Dataspace pointer to check + RETURNS + TRUE/FALSE/FAIL DESCRIPTION - Quickly detect intersections between span tree and block + Checks to see if the current selection in the dataspace is a single block. + This is primarily used for reading the entire selection in one swoop. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static hbool_t -H5S__hyper_intersect_block_helper(const H5S_hyper_span_info_t *spans, - const hsize_t *start, const hsize_t *end) +static H5_ATTR_PURE htri_t +H5S__hyper_is_single(const H5S_t *space) { - H5S_hyper_span_t *curr; /* Pointer to current span in 1st span tree */ - hbool_t ret_value = FALSE; /* Return value */ + htri_t ret_value = TRUE; /* return value */ FUNC_ENTER_STATIC_NOERR - /* Sanity check */ - HDassert(spans); - HDassert(start); - HDassert(end); + HDassert(space); - /* Get the span list for spans in this tree */ - curr = spans->head; + /* Check for a "single" hyperslab selection */ + /* (No need to rebuild the dimension info yet, since the span-tree + * algorithm is fast -QAK) + */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + unsigned u; /* index variable */ - /* Iterate over the spans in the tree */ - while(curr != NULL) { - /* Check for span entirely before block */ - if(curr->high < *start) - /* Advance to next span in this dimension */ - curr = curr->next; - /* If this span is past the end of the block, then we're done in this dimension */ - else if(curr->low > *end) - HGOTO_DONE(FALSE) - /* block & span overlap */ - else { - if(curr->down == NULL) - HGOTO_DONE(TRUE) - else { - hbool_t status; /* Status from recursive call */ + /* + * For a regular hyperslab to be single, it must have only one + * block (i.e. count==1 in all dimensions) + */ - /* Recursively check spans in next dimension down */ - status = H5S__hyper_intersect_block_helper(curr->down, start + 1, end + 1); + /* Check for a single block */ + for(u = 0; u < space->extent.rank; u++) + if(space->select.sel_info.hslab->diminfo.opt[u].count > 1) + HGOTO_DONE(FALSE) + } /* end if */ + else { + H5S_hyper_span_info_t *spans; /* Hyperslab span info node */ - /* If there is a span intersection in the down dimensions, the span trees overlap */ - if(status == TRUE) - HGOTO_DONE(TRUE); + /* + * For a region to be single, it must have only one block + */ + /* Get information for slowest changing information */ + spans = space->select.sel_info.hslab->span_lst; - /* No intersection in down dimensions, advance to next span */ - curr = curr->next; - } /* end else */ - } /* end else */ - } /* end while */ + /* Cycle down the spans until we run out of down spans or find a non-contiguous span */ + while(spans != NULL) { + H5S_hyper_span_t *span; /* Hyperslab span node */ - /* Fall through with 'FALSE' return value */ + span = spans->head; + + /* Check that this is the only span and it spans the entire dimension */ + if(span->next != NULL) + HGOTO_DONE(FALSE) + else + /* Walk down to the next span */ + spans = span->down; + } /* end while */ + } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_intersect_block_helper() */ +} /* end H5S__hyper_is_single() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_intersect_block + H5S__hyper_is_regular PURPOSE - Detect intersections in span trees + Check if a hyperslab selection is "regular" USAGE - htri_t H5S_hyper_intersect_block(space, start, end) - H5S_t *space; IN: First dataspace to operate on span tree - hssize_t *start; IN: Starting coordinate for block - hssize_t *end; IN: Ending coordinate for block + htri_t H5S__hyper_is_regular(space) + const H5S_t *space; IN: Dataspace pointer to check RETURNS - Non-negative on success, negative on failure + TRUE/FALSE/FAIL DESCRIPTION - Quickly detect intersections between span tree and block + Checks to see if the current selection in a dataspace is the a regular + pattern. + This is primarily used for reading the entire selection in one swoop. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -htri_t -H5S_hyper_intersect_block(H5S_t *space, const hsize_t *start, const hsize_t *end) +static htri_t +H5S__hyper_is_regular(const H5S_t *space) { - htri_t ret_value = FAIL; /* Return value */ + htri_t ret_value = FAIL; /* return value */ - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_STATIC_NOERR - /* Sanity check */ + /* Check args */ HDassert(space); - HDassert(start); - HDassert(end); - /* Check for 'all' selection, instead of a hyperslab selection */ - /* (Technically, this shouldn't be in the "hyperslab" routines...) */ - if(H5S_GET_SELECT_TYPE(space) == H5S_SEL_ALL) - HGOTO_DONE(TRUE); - - /* Check that the space selection has a span tree */ - if(NULL == space->select.sel_info.hslab->span_lst) - if(H5S__hyper_generate_spans(space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") + /* Attempt to rebuild diminfo if it is invalid and has not been confirmed + * to be impossible. + */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO) + H5S__hyper_rebuild((H5S_t *)space); /* Casting away const OK -NAF */ - /* Perform the span-by-span intersection check */ - ret_value = H5S__hyper_intersect_block_helper(space->select.sel_info.hslab->span_lst, start, end); + /* Only simple check for regular hyperslabs for now... */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) + ret_value = TRUE; + else + ret_value = FALSE; -done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_intersect_block() */ +} /* end H5S__hyper_is_regular() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_adjust_u_helper + H5S__hyper_spans_shape_same_helper PURPOSE - Helper routine to adjust offsets in span trees + Helper routine to check if two hyperslab span trees are the same shape USAGE - void H5S__hyper_adjust_u_helper(spans, offset) - H5S_hyper_span_info_t *spans; IN: Span tree to operate with - const hsize_t *offset; IN: Offset to subtract + hbool_t H5S__hyper_spans_shape_same_helper(span1, span2, offset, rest_zeros) + H5S_hyper_span_info_t *span_info1; IN: First span tree to compare + H5S_hyper_span_info_t *span_info2; IN: Second span tree to compare + hssize_t offset[]; IN: Offset between the span trees + hbool_t rest_zeros[]; IN: Array of flags which indicate + the rest of the offset[] array + is zero values. RETURNS - None + TRUE (1) or FALSE (0) on success, can't fail DESCRIPTION - Adjust the location of the spans in a span tree by subtracting an offset + Compare two hyperslab span trees to determine if they refer to a selection + with the same shape, with a possible (constant) offset between their + elements. Very similar to H5S__hyper_cmp_spans, except the selected + elements can be offset by a vector. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static void -H5S__hyper_adjust_u_helper(H5S_hyper_span_info_t *spans, - const hsize_t *offset) +static H5_ATTR_PURE hbool_t +H5S__hyper_spans_shape_same_helper(const H5S_hyper_span_info_t *span_info1, + const H5S_hyper_span_info_t *span_info2, hssize_t offset[], + hbool_t rest_zeros[]) { - FUNC_ENTER_STATIC_NOERR + hbool_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_PACKAGE_NOERR /* Sanity checks */ - HDassert(spans); - HDassert(spans->scratch == (H5S_hyper_span_info_t *)~((size_t)NULL) || - spans->scratch == NULL); + HDassert(span_info1); + HDassert(span_info2); HDassert(offset); + HDassert(rest_zeros); - /* Check if we've already set this down span tree */ - if(spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)) { - H5S_hyper_span_t *span; /* Pointer to current span in span tree */ + /* Compare low & high bounds for this span list */ + /* (Could compare lower dimensions also, but not certain if + * that's worth it. - QAK, 2019/01/23) + */ + if((hsize_t)((hssize_t)span_info1->low_bounds[0] + offset[0]) != span_info2->low_bounds[0]) + HGOTO_DONE(FALSE) + else if((hsize_t)((hssize_t)span_info1->high_bounds[0] + offset[0]) != span_info2->high_bounds[0]) + HGOTO_DONE(FALSE) + else { + const H5S_hyper_span_t *span1; + const H5S_hyper_span_t *span2; - /* Set the tree's scratch pointer */ - spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL); + /* Get the pointers to the actual lists of spans */ + span1 = span_info1->head; + span2 = span_info2->head; - /* Iterate over the spans in tree */ - span = spans->head; - while(span != NULL) { - /* Adjust span offset */ - HDassert(span->low >= *offset); - span->low -= *offset; - span->high -= *offset; + /* Sanity checking */ + HDassert(span1); + HDassert(span2); - /* Recursively adjust spans in next dimension down */ - if(span->down != NULL) - H5S__hyper_adjust_u_helper(span->down, offset + 1); + /* infinite loop which must be broken out of */ + while(1) { + /* Check for both spans being NULL */ + if(span1 == NULL && span2 == NULL) + HGOTO_DONE(TRUE) - /* Advance to next span in this dimension */ - span = span->next; + /* Check for one span being NULL */ + if(span1 == NULL || span2 == NULL) + HGOTO_DONE(FALSE) + + /* Check if the actual low & high span information is the same */ + if((hsize_t)((hssize_t)span1->low + offset[0]) != span2->low || (hsize_t)((hssize_t)span1->high + offset[0]) != span2->high) + HGOTO_DONE(FALSE) + + /* Check for down tree for this span */ + if(span1->down != NULL || span2->down != NULL) { + /* If the rest of the span trees have a zero offset, use the faster comparison routine */ + if(rest_zeros[0]) { + if(!H5S__hyper_cmp_spans(span1->down, span2->down)) + HGOTO_DONE(FALSE) + else { + /* Keep going... */ + } /* end else */ + } /* end if */ + else { + if(!H5S__hyper_spans_shape_same_helper(span1->down, span2->down, &offset[1], &rest_zeros[1])) + HGOTO_DONE(FALSE) + else { + /* Keep going... */ + } /* end else */ + } /* end else */ + } /* end if */ + else { + /* Keep going... */ + } /* end else */ + + /* Advance to the next nodes in the span list */ + span1 = span1->next; + span2 = span2->next; } /* end while */ - } /* end if */ + } /* end else */ + + /* Fall through, with default return value of 'TRUE' if spans were already visited */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_spans_shape_same_helper() */ - FUNC_LEAVE_NOAPI_VOID -} /* end H5S__hyper_adjust_u_helper() */ - /*-------------------------------------------------------------------------- NAME - H5S__hyper_adjust_u + H5S__hyper_spans_shape_same PURPOSE - Adjust a hyperslab selection by subtracting an offset + Check if two hyperslab span trees are the same shape USAGE - void H5S__hyper_adjust_u(space,offset) - H5S_t *space; IN/OUT: Pointer to dataspace to adjust - const hsize_t *offset; IN: Offset to subtract + hbool_t H5S__hyper_spans_shape_same(span1, span2) + H5S_hyper_span_info_t *span_info1; IN: First span tree to compare + H5S_hyper_span_info_t *span_info2; IN: Second span tree to compare RETURNS - Non-negative on success, negative on failure + TRUE (1) or FALSE (0) on success, can't fail DESCRIPTION - Moves a hyperslab selection by subtracting an offset from it. + Compare two hyperslab span trees to determine if they refer to a selection + with the same shape. Very similar to H5S__hyper_cmp_spans, except the + selected elements can be offset by a vector. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_adjust_u(H5S_t *space, const hsize_t *offset) -{ - hbool_t non_zero_offset = FALSE; /* Whether any offset is non-zero */ - unsigned u; /* Local index variable */ - - FUNC_ENTER_STATIC_NOERR - - /* Sanity check */ - HDassert(space); - HDassert(offset); - - /* Check for an all-zero offset vector */ - for(u = 0; u < space->extent.rank; u++) - if(0 != offset[u]) { - non_zero_offset = TRUE; - break; - } - - /* Only perform operation if the offset is non-zero */ - if(non_zero_offset) { - /* Subtract the offset from the "regular" coordinates, if they exist */ - if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { - for(u = 0; u < space->extent.rank; u++) { - HDassert(space->select.sel_info.hslab->diminfo.opt[u].start >= offset[u]); - space->select.sel_info.hslab->diminfo.opt[u].start -= offset[u]; - } /* end for */ - } /* end if */ - - /* Subtract the offset from the span tree coordinates, if they exist */ - if(space->select.sel_info.hslab->span_lst) { - H5S__hyper_adjust_u_helper(space->select.sel_info.hslab->span_lst, offset); - - /* Reset the scratch pointers for the next routine which needs them */ - H5S__hyper_span_scratch(space->select.sel_info.hslab->span_lst); - } /* end if */ - } /* end if */ - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_adjust_u() */ - - -/*------------------------------------------------------------------------- - * Function: H5S__hyper_project_scalar - * - * Purpose: Projects a single element hyperslab selection into a scalar - * dataspace - * - * Return: non-negative on success, negative on failure. - * - * Programmer: Quincey Koziol - * Sunday, July 18, 2010 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5S__hyper_project_scalar(const H5S_t *space, hsize_t *offset) -{ - hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */ - - FUNC_ENTER_STATIC_NOERR - - /* Check args */ - HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space)); - HDassert(offset); - - /* Check for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { - const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->diminfo.opt; /* Alias for dataspace's diminfo information */ - unsigned u; /* Counter */ - - /* Build the table of the initial offset */ - for(u = 0; u < space->extent.rank; u++) { - /* Keep the offset for later */ - block[u] = diminfo[u].start; - } /* end for */ - } /* end if */ - else { - const H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */ - unsigned curr_dim; /* Current dimension being operated on */ - - /* Advance down selected spans */ - curr = space->select.sel_info.hslab->span_lst->head; - curr_dim = 0; - while(curr) { - /* Sanity check for more than one span */ - HDassert(NULL == curr->next); - HDassert(curr->low == curr->high); - - /* Save the location of the selection in current dimension */ - block[curr_dim] = curr->low; - - /* Advance down to next dimension */ - curr = curr->down->head; - curr_dim++; - } /* end while */ - } /* end else */ - - /* Calculate offset of selection in projected buffer */ - *offset = H5VM_array_offset(space->extent.rank, space->extent.size, block); - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_project_scalar() */ - - -/*------------------------------------------------------------------------- - * Function: H5S__hyper_project_simple_lower - * - * Purpose: Projects a hyperslab selection onto/into a simple dataspace - * of a lower rank - * - * Return: non-negative on success, negative on failure. - * - * Programmer: Quincey Koziol - * Sunday, July 18, 2010 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5S__hyper_project_simple_lower(const H5S_t *base_space, H5S_t *new_space) -{ - H5S_hyper_span_info_t *down; /* Pointer to list of spans */ - unsigned curr_dim; /* Current dimension being operated on */ - - FUNC_ENTER_STATIC_NOERR - - /* Check args */ - HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space)); - HDassert(new_space); - HDassert(new_space->extent.rank < base_space->extent.rank); - - /* Walk down the span tree until we reach the selection to project */ - down = base_space->select.sel_info.hslab->span_lst; - curr_dim = 0; - while(down && curr_dim < (base_space->extent.rank - new_space->extent.rank)) { - /* Sanity check */ - HDassert(NULL == down->head->next); - - /* Advance down to next dimension */ - down = down->head->down; - curr_dim++; - } /* end while */ - HDassert(down); - - /* Share the underlying hyperslab span information */ - new_space->select.sel_info.hslab->span_lst = down; - new_space->select.sel_info.hslab->span_lst->count++; - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_project_simple_lower() */ - - -/*------------------------------------------------------------------------- - * Function: H5S__hyper_project_simple_higher - * - * Purpose: Projects a hyperslab selection onto/into a simple dataspace - * of a higher rank - * - * Return: non-negative on success, negative on failure. - * - * Programmer: Quincey Koziol - * Sunday, July 18, 2010 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5S__hyper_project_simple_higher(const H5S_t *base_space, H5S_t *new_space) +static H5_ATTR_PURE hbool_t +H5S__hyper_spans_shape_same(const H5S_hyper_span_info_t *span_info1, + const H5S_hyper_span_info_t *span_info2, unsigned ndims) { - H5S_hyper_span_t *prev_span = NULL; /* Pointer to previous list of spans */ - unsigned curr_dim; /* Current dimension being operated on */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_STATIC + const H5S_hyper_span_t *span1; /* Pointer to spans in first span tree */ + const H5S_hyper_span_t *span2; /* Pointer to spans in second span tree */ + hssize_t offset[H5S_MAX_RANK]; /* Offset vector for selections */ + hbool_t rest_zeros[H5S_MAX_RANK]; /* Vector of flags to indicate when remaining offset is all zero */ + hbool_t zero_offset; /* Whether the two selections have a non-zero offset */ + unsigned u; /* Local index variable */ + hbool_t ret_value = TRUE; /* Return value */ - /* Check args */ - HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space)); - HDassert(new_space); - HDassert(new_space->extent.rank > base_space->extent.rank); + FUNC_ENTER_STATIC_NOERR - /* Create nodes until reaching the correct # of dimensions */ - new_space->select.sel_info.hslab->span_lst = NULL; - curr_dim = 0; - while(curr_dim < (new_space->extent.rank - base_space->extent.rank)) { - H5S_hyper_span_info_t *new_span_info; /* Pointer to list of spans */ - H5S_hyper_span_t *new_span; /* Temporary hyperslab span */ + /* Sanity check */ + HDassert(span_info1); + HDassert(span_info2); + HDassert(ndims > 0); + + /* Initialize arrays */ + HDmemset(offset, 0, sizeof(offset)); + HDmemset(rest_zeros, 0, sizeof(rest_zeros)); + + /* Check for an offset between the two selections */ + span1 = span_info1->head; + span2 = span_info2->head; + zero_offset = TRUE; + for(u = 0; u < ndims; u++) { + /* Check for offset in this dimension */ + if(span1->low != span2->low) { + offset[u] = (hssize_t)span2->low - (hssize_t)span1->low; - /* Allocate a new span_info node */ - if(NULL == (new_span_info = H5FL_CALLOC(H5S_hyper_span_info_t))) { - if(prev_span) - if(H5S__hyper_free_span(prev_span) < 0) - HERROR(H5E_DATASPACE, H5E_CANTFREE, "can't free hyperslab span"); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span info") + /* Indicate that the offset vector is not all zeros */ + if(zero_offset) + zero_offset = FALSE; } /* end if */ - /* Check for linking into higher span */ - if(prev_span) - prev_span->down = new_span_info; + /* Sanity check */ + /* (Both span trees must have the same depth) */ + HDassert((span1->down && span2->down) || (NULL == span1->down && NULL == span2->down)); - /* Allocate a new node */ - if(NULL == (new_span = H5S__hyper_new_span((hsize_t)0, (hsize_t)0, NULL, NULL))) { - HDassert(new_span_info); - if(!prev_span) - (void)H5FL_FREE(H5S_hyper_span_info_t, new_span_info); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span") + /* Advance to next dimension */ + if(span1->down) { + span1 = span1->down->head; + span2 = span2->down->head; } /* end if */ + } /* end for */ - /* Set the span_info information */ - new_span_info->count = 1; - new_span_info->head = new_span; - - /* Attach to new space, if top span info */ - if(NULL == new_space->select.sel_info.hslab->span_lst) - new_space->select.sel_info.hslab->span_lst = new_span_info; + /* Check if there's a "tail" of all zeros in a non-zero offset vector */ + if(!zero_offset) { + int i; /* Local index variable */ - /* Remember previous span info */ - prev_span = new_span; + /* Find first non-zero offset, from the fastest dimension up */ + for(i = (int)(ndims - 1); i >= 0; i--) + if(offset[i]) { + rest_zeros[i] = TRUE; + break; + } /* end if */ - /* Advance to next dimension */ - curr_dim++; - } /* end while */ - HDassert(new_space->select.sel_info.hslab->span_lst); - HDassert(prev_span); + /* Sanity check */ + /* (Must eventually have found a non-zero offset) */ + HDassert(i >= 0); + } /* end if */ - /* Share the underlying hyperslab span information */ - prev_span->down = base_space->select.sel_info.hslab->span_lst; - prev_span->down->count++; + /* If the offset vector is all zero, we can use the faster span tree + * comparison routine. Otherwise, use a generalized version of that + * routine. + */ + if(zero_offset) + ret_value = H5S__hyper_cmp_spans(span_info1, span_info2); + else + ret_value = H5S__hyper_spans_shape_same_helper(span_info1, span_info2, offset, rest_zeros); -done: - if(ret_value < 0 && new_space->select.sel_info.hslab->span_lst) { - if(new_space->select.sel_info.hslab->span_lst->head) - if(H5S__hyper_free_span(new_space->select.sel_info.hslab->span_lst->head) < 0) - HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free hyperslab span") + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_spans_shape_same() */ - new_space->select.sel_info.hslab->span_lst = H5FL_FREE(H5S_hyper_span_info_t, new_space->select.sel_info.hslab->span_lst); - } /* end if */ - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_project_simple_higher() */ +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_shape_same + PURPOSE + Check if a two hyperslab selections are the same shape + USAGE + htri_t H5S__hyper_shape_same(space1, space2) + const H5S_t *space1; IN: First dataspace to check + const H5S_t *space2; IN: Second dataspace to check + RETURNS + TRUE / FALSE / FAIL + DESCRIPTION + Checks to see if the current selection in each dataspace are the same + shape. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Handles when both are regular in an efficient way, otherwise converts + both to span tree form (if necessary) and compares efficiently them in + that form. - -/*------------------------------------------------------------------------- - * Function: H5S__hyper_project_simple - * - * Purpose: Projects a hyperslab selection onto/into a simple dataspace - * of a different rank - * - * Return: non-negative on success, negative on failure. - * - * Programmer: Quincey Koziol - * Sunday, July 18, 2010 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5S__hyper_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *offset) + Rank of space1 must always be >= to rank of space2. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static htri_t +H5S__hyper_shape_same(const H5S_t *space1, const H5S_t *space2) { - herr_t ret_value = SUCCEED; /* Return value */ + unsigned space1_rank; /* Number of dimensions of first dataspace */ + unsigned space2_rank; /* Number of dimensions of second dataspace */ + htri_t ret_value = TRUE; /* Return value */ FUNC_ENTER_STATIC /* Check args */ - HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space)); - HDassert(new_space); - HDassert(offset); - - /* We are setting a new selection, remove any current selection in new dataspace */ - if(H5S_SELECT_RELEASE(new_space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") - - /* Allocate space for the hyperslab selection information */ - if(NULL == (new_space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info") - - /* Set unlim_dim */ - new_space->select.sel_info.hslab->unlim_dim = -1; - - /* Check for a "regular" hyperslab selection */ - if(base_space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { - unsigned base_space_dim; /* Current dimension in the base dataspace */ - unsigned new_space_dim; /* Current dimension in the new dataspace */ - - /* Check if the new space's rank is < or > base space's rank */ - if(new_space->extent.rank < base_space->extent.rank) { - const H5S_hyper_dim_t *opt_diminfo = base_space->select.sel_info.hslab->diminfo.opt; /* Alias for dataspace's diminfo information */ - hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */ - unsigned u; /* Local index variable */ + HDassert(space1); + HDassert(space2); - /* Compute the offset for the down-projection */ - HDmemset(block, 0, sizeof(block)); - for(u = 0; u < (base_space->extent.rank - new_space->extent.rank); u++) - block[u] = opt_diminfo[u].start; - *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block); + /* Get dataspace ranks */ + space1_rank = space1->extent.rank; + space2_rank = space2->extent.rank; - /* Set the correct dimensions for the base & new spaces */ - base_space_dim = base_space->extent.rank - new_space->extent.rank; - new_space_dim = 0; - } /* end if */ - else { - HDassert(new_space->extent.rank > base_space->extent.rank); + /* Sanity check */ + HDassert(space1_rank >= space2_rank); + HDassert(space2_rank > 0); + + /* Rebuild diminfo if it is invalid and has not been confirmed to be + * impossible */ + if(space1->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO) + H5S__hyper_rebuild((H5S_t *)space1); /* Casting away const OK -QAK */ + if(space2->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO) + H5S__hyper_rebuild((H5S_t *)space2); /* Casting away const OK -QAK */ + + /* If both are regular hyperslabs, compare their diminfo values */ + if(space1->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES + && space2->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + int space1_dim; /* Current dimension in first dataspace */ + int space2_dim; /* Current dimension in second dataspace */ + + /* Initialize dimensions */ + space1_dim = (int)space1_rank - 1; + space2_dim = (int)space2_rank - 1; + + /* Check that the shapes are the same in the common dimensions, and that + * block == 1 in all dimensions that appear only in space1. + */ + while(space2_dim >= 0) { + if(space1->select.sel_info.hslab->diminfo.opt[space1_dim].stride != + space2->select.sel_info.hslab->diminfo.opt[space2_dim].stride) + HGOTO_DONE(FALSE) - /* The offset is zero when projected into higher dimensions */ - *offset = 0; + if(space1->select.sel_info.hslab->diminfo.opt[space1_dim].count != + space2->select.sel_info.hslab->diminfo.opt[space2_dim].count) + HGOTO_DONE(FALSE) - /* Set the diminfo information for the higher dimensions */ - for(new_space_dim = 0; new_space_dim < (new_space->extent.rank - base_space->extent.rank); new_space_dim++) { - new_space->select.sel_info.hslab->diminfo.app[new_space_dim].start = 0; - new_space->select.sel_info.hslab->diminfo.app[new_space_dim].stride = 1; - new_space->select.sel_info.hslab->diminfo.app[new_space_dim].count = 1; - new_space->select.sel_info.hslab->diminfo.app[new_space_dim].block = 1; + if(space1->select.sel_info.hslab->diminfo.opt[space1_dim].block != + space2->select.sel_info.hslab->diminfo.opt[space2_dim].block) + HGOTO_DONE(FALSE) - new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].start = 0; - new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].stride = 1; - new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].count = 1; - new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].block = 1; - } /* end for */ + space1_dim--; + space2_dim--; + } /* end while */ - /* Start at beginning of base space's dimension info */ - base_space_dim = 0; - } /* end else */ + while(space1_dim >= 0) { + if(space1->select.sel_info.hslab->diminfo.opt[space1_dim].block != 1) + HGOTO_DONE(FALSE) - /* Copy the diminfo */ - while(base_space_dim < base_space->extent.rank) { - new_space->select.sel_info.hslab->diminfo.app[new_space_dim].start = - base_space->select.sel_info.hslab->diminfo.app[base_space_dim].start; - new_space->select.sel_info.hslab->diminfo.app[new_space_dim].stride = - base_space->select.sel_info.hslab->diminfo.app[base_space_dim].stride; - new_space->select.sel_info.hslab->diminfo.app[new_space_dim].count = - base_space->select.sel_info.hslab->diminfo.app[base_space_dim].count; - new_space->select.sel_info.hslab->diminfo.app[new_space_dim].block = - base_space->select.sel_info.hslab->diminfo.app[base_space_dim].block; + space1_dim--; + } /* end while */ + } /* end if */ + /* If both aren't regular, use fast irregular comparison */ + else { + H5S_hyper_span_info_t *spans1; /* Hyperslab spans for first dataspace */ + + /* Make certain that both selections have span trees */ + if(NULL == space1->select.sel_info.hslab->span_lst) + if(H5S__hyper_generate_spans((H5S_t *)space1) < 0) /* Casting away const OK -QAK */ + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "can't construct span tree for hyperslab selection") + if(NULL == space2->select.sel_info.hslab->span_lst) + if(H5S__hyper_generate_spans((H5S_t *)space2) < 0) /* Casting away const OK -QAK */ + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "can't construct span tree for hyperslab selection") + + /* If rank of space A is different (guaranteed greater) than + * rank of space B, walk down the span tree, verifying + * that the block size is 1 on the way down. + */ + if(space1_rank > space2_rank) { + unsigned diff_rank = space1_rank - space2_rank; /* Difference in ranks */ - new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].start = - base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].start; - new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].stride = - base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].stride; - new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].count = - base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].count; - new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].block = - base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].block; + /* Walk down the dimensions */ + spans1 = space1->select.sel_info.hslab->span_lst; + while(diff_rank > 0) { + H5S_hyper_span_t *span; /* Span for this dimension */ - /* Advance to next dimensions */ - base_space_dim++; - new_space_dim++; - } /* end for */ + /* Get pointer to first span in tree */ + span = spans1->head; - /* Indicate that the dimension information is valid */ - new_space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES; + /* Check for more spans in this dimension */ + if(span->next) + HGOTO_DONE(FALSE) - /* Indicate that there's no slab information */ - new_space->select.sel_info.hslab->span_lst = NULL; - } /* end if */ - else { - /* Check if the new space's rank is < or > base space's rank */ - if(new_space->extent.rank < base_space->extent.rank) { - const H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */ - hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */ - unsigned curr_dim; /* Current dimension being operated on */ + /* Check for span size > 1 element */ + if(span->low != span->high) + HGOTO_DONE(FALSE) - /* Clear the block buffer */ - HDmemset(block, 0, sizeof(block)); + /* Walk down to the next dimension */ + spans1 = span->down; + diff_rank--; + } /* end while */ - /* Advance down selected spans */ - curr = base_space->select.sel_info.hslab->span_lst->head; - curr_dim = 0; - while(curr && curr_dim < (base_space->extent.rank - new_space->extent.rank)) { - /* Save the location of the selection in current dimension */ - block[curr_dim] = curr->low; + /* Sanity check */ + HDassert(spans1); + } /* end if */ + else + spans1 = space1->select.sel_info.hslab->span_lst; - /* Advance down to next dimension */ - curr = curr->down->head; - curr_dim++; - } /* end while */ + /* Compare the span trees */ + ret_value = H5S__hyper_spans_shape_same(spans1, space2->select.sel_info.hslab->span_lst, space2_rank); + } /* end else */ - /* Compute the offset for the down-projection */ - *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block); + /* Fall through with 'TRUE' value, if not set earlier */ - /* Project the base space's selection down in less dimensions */ - if(H5S__hyper_project_simple_lower(base_space, new_space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't project hyperslab selection into less dimensions") - } /* end if */ - else { - HDassert(new_space->extent.rank > base_space->extent.rank); +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_shape_same() */ - /* The offset is zero when projected into higher dimensions */ - *offset = 0; + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_release + PURPOSE + Release hyperslab selection information for a dataspace + USAGE + herr_t H5S__hyper_release(space) + H5S_t *space; IN: Pointer to dataspace + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Releases all hyperslab selection information for a dataspace + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_release(H5S_t *space) +{ + FUNC_ENTER_STATIC_NOERR - /* Project the base space's selection down in more dimensions */ - if(H5S__hyper_project_simple_higher(base_space, new_space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't project hyperslab selection into less dimensions") - } /* end else */ + /* Check args */ + HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space)); - /* Indicate that the dimension information is not valid */ - new_space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; - } /* end else */ + /* Reset the number of points selected */ + space->select.num_elem = 0; - /* Number of elements selected will be the same */ - new_space->select.num_elem = base_space->select.num_elem; + /* Release irregular hyperslab information */ + if(space->select.sel_info.hslab) { + if(space->select.sel_info.hslab->span_lst != NULL) + H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst); - /* Set selection type */ - new_space->select.type = H5S_sel_hyper; + /* Release space for the hyperslab selection information */ + space->select.sel_info.hslab = H5FL_FREE(H5S_hyper_sel_t, space->select.sel_info.hslab); + } /* end if */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_project_simple() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_release() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_adjust_s_helper + H5S__hyper_coord_to_span PURPOSE - Helper routine to adjust offsets in span trees + Create a span tree for a single element USAGE - void H5S__hyper_adjust_s_helper(spans, offset) - H5S_hyper_span_info_t *spans; IN: Span tree to operate with - const hssize_t *offset; IN: Offset to subtract + H5S_hyper_span_t *H5S__hyper_coord_to_span(rank, coords) + unsigned rank; IN: Number of dimensions of coordinate + hsize_t *coords; IN: Location of element RETURNS - None + Non-NULL pointer to new span tree on success, NULL on failure DESCRIPTION - Adjust the location of the spans in a span tree by subtracting an offset + Create a span tree for a single element GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static void -H5S__hyper_adjust_s_helper(H5S_hyper_span_info_t *spans, - const hssize_t *offset) +static H5S_hyper_span_t * +H5S__hyper_coord_to_span(unsigned rank, const hsize_t *coords) { - FUNC_ENTER_STATIC_NOERR + H5S_hyper_span_t *new_span; /* Pointer to new span tree for coordinate */ + H5S_hyper_span_info_t *down = NULL; /* Pointer to new span tree for next level down */ + H5S_hyper_span_t *ret_value = NULL; /* Return value */ - /* Sanity checks */ - HDassert(spans); - HDassert(spans->scratch == (H5S_hyper_span_info_t *)~((size_t)NULL) || - spans->scratch == NULL); - HDassert(offset); + FUNC_ENTER_STATIC - /* Check if we've already set this down span tree */ - if(spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)) { - H5S_hyper_span_t *span; /* Pointer to current span in span tree */ + HDassert(rank > 0); + HDassert(coords); - /* Set the tree's scratch pointer */ - spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL); + /* Search for location to insert new element in tree */ + if(rank > 1) { + /* Allocate a span info node for coordinates below this one */ + if(NULL == (down = H5S__hyper_new_span_info(rank - 1))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") - /* Iterate over the spans in tree */ - span = spans->head; - while(span != NULL) { - /* Adjust span offset */ - HDassert((hssize_t)span->low >= *offset); - span->low = (hsize_t)((hssize_t)span->low - *offset); - span->high = (hsize_t)((hssize_t)span->high - *offset); + /* Set the low & high bounds for this span info node */ + H5MM_memcpy(down->low_bounds, &coords[1], (rank - 1) * sizeof(hsize_t)); + H5MM_memcpy(down->high_bounds, &coords[1], (rank - 1) * sizeof(hsize_t)); - /* Recursively adjust spans in next dimension down */ - if(span->down != NULL) - H5S__hyper_adjust_s_helper(span->down, offset + 1); + /* Build span tree for coordinates below this one */ + if(NULL == (down->head = H5S__hyper_coord_to_span(rank - 1, &coords[1]))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") - /* Advance to next span in this dimension */ - span = span->next; - } /* end while */ + /* Update the tail pointer of the down dimension, and it's a single span element */ + down->tail = down->head; } /* end if */ - FUNC_LEAVE_NOAPI_VOID -} /* end H5S__hyper_adjust_s_helper() */ + /* Build span for this coordinate */ + if(NULL == (new_span = H5S__hyper_new_span(coords[0], coords[0], down, NULL))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") + + /* Set return value */ + ret_value = new_span; + +done: + if(ret_value == NULL && down != NULL) + H5S__hyper_free_span_info(down); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_coord_to_span() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_adjust_s + H5S__hyper_add_span_element_helper PURPOSE - Adjust a hyperslab selection by subtracting an offset + Helper routine to add a single element to a span tree USAGE - herr_t H5S_hyper_adjust_s(space,offset) - H5S_t *space; IN/OUT: Pointer to dataspace to adjust - const hssize_t *offset; IN: Offset to subtract + herr_t H5S__hyper_add_span_element_helper(span_tree, rank, coords, first_dim_modified) + H5S_hyper_span_info_t *span_tree; IN/OUT: Pointer to span tree to append to + unsigned rank; IN: Number of dimensions of coordinates + hsize_t *coords; IN: Location of element to add to span tree + int *first_dim_modified; IN: Index of the first dimension modified RETURNS Non-negative on success, negative on failure DESCRIPTION - Moves a hyperslab selection by subtracting an offset from it. + Add a single element to an existing span tree. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS + Assumes that the element is not already covered by the span tree EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -herr_t -H5S_hyper_adjust_s(H5S_t *space, const hssize_t *offset) +static herr_t +H5S__hyper_add_span_element_helper(H5S_hyper_span_info_t *span_tree, + unsigned rank, const hsize_t *coords, int *first_dim_modified) { - hbool_t non_zero_offset = FALSE; /* Whether any offset is non-zero */ - unsigned u; /* Local index variable */ + H5S_hyper_span_t *tail_span; /* Pointer to the tail span of one dimension */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_STATIC - /* Sanity checks */ - HDassert(space); - HDassert(offset); + /* Sanity check */ + HDassert(span_tree); + HDassert(rank > 0); + HDassert(coords); + HDassert(first_dim_modified); - /* Check for an all-zero offset vector */ - for(u = 0; u < space->extent.rank; u++) - if(0 != offset[u]) { - non_zero_offset = TRUE; - break; - } /* end if */ + /* Get pointer to last span in span tree */ + tail_span = span_tree->tail; + + /* Determine if tail span includes a portion of the coordinate */ + /* (Should never happen with the lowest level in the span tree) */ + if(coords[0] >= tail_span->low && coords[0] <= tail_span->high) { + H5S_hyper_span_t *prev_down_tail_span; /* Pointer to previous down spans' tail pointer */ + hsize_t prev_down_tail_span_high; /* Value of previous down spans' tail's high value */ + + /* Retain into about down spans' tail */ + prev_down_tail_span = tail_span->down->tail; + prev_down_tail_span_high = tail_span->down->tail->high; + + /* Drop down a dimension */ + HDassert(rank > 1); + if(H5S__hyper_add_span_element_helper(tail_span->down, rank - 1, &coords[1], first_dim_modified) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "can't insert coordinate into span tree") + + /* Check & update high bounds for lower dimensions */ + if(*first_dim_modified >= 0) { + unsigned first_dim; /* First dimension modified, relative to this span tree */ + hbool_t first_dim_set = FALSE; /* Whether first dimension modified is set */ + unsigned u; /* Local index variable */ - /* Only perform operation if the offset is non-zero */ - if(non_zero_offset) { - /* Subtract the offset from the "regular" coordinates, if they exist */ - if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { - for(u = 0; u < space->extent.rank; u++) { - HDassert((hssize_t)space->select.sel_info.hslab->diminfo.opt[u].start >= offset[u]); - space->select.sel_info.hslab->diminfo.opt[u].start = (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.opt[u].start - offset[u]); + /* Adjust first dimension modified to be relative to this span tree */ + first_dim = (unsigned)(*first_dim_modified + 1); + + /* Reset modified dimension, in case no bounds in this span tree change */ + *first_dim_modified = -1; + + /* Iterate through coordinates */ + for(u = first_dim; u < rank; u++) { + /* Check if coordinate is outside the bounds for this span tree */ + if(coords[u] > span_tree->high_bounds[u]) { + /* Update high bounds for this tree */ + span_tree->high_bounds[u] = coords[u]; + + /* Need to signal to higher dimensions if high bounds changed */ + if(!first_dim_set) { + *first_dim_modified = (int)u; + first_dim_set = TRUE; + } /* end if */ + } /* end if */ } /* end for */ } /* end if */ - /* Subtract the offset from the span tree coordinates, if they exist */ - if(space->select.sel_info.hslab->span_lst) { - H5S__hyper_adjust_s_helper(space->select.sel_info.hslab->span_lst, offset); + /* Check if previous tail span in down spans is different than current + * tail span, or if its high value changed, in which case we should + * check if the updated node can share down spans with other nodes. + */ + if(tail_span->down->tail != prev_down_tail_span || + prev_down_tail_span_high != tail_span->down->tail->high) { + H5S_hyper_span_t *stop_span; /* Pointer to span to stop at */ + H5S_hyper_span_t *tmp_span; /* Temporary pointer to a span */ + uint64_t op_gen; /* Operation generation value */ + + /* Determine which span to stop at */ + if(tail_span->down->tail != prev_down_tail_span) { + /* Sanity check */ + HDassert(prev_down_tail_span->next == tail_span->down->tail); + + /* Set the span to stop at */ + stop_span = prev_down_tail_span; + } /* end if */ + else { + /* Sanity check */ + HDassert(prev_down_tail_span_high != tail_span->down->tail->high); - /* Reset the scratch pointers for the next routine which needs them */ - H5S__hyper_span_scratch(space->select.sel_info.hslab->span_lst); - } /* end if */ - } + /* Set the span to stop at */ + stop_span = tail_span->down->tail; + } /* end else */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_adjust_s() */ + /* Acquire an operation generation value for this operation */ + op_gen = H5S__hyper_get_op_gen(); - -/*-------------------------------------------------------------------------- - NAME - H5S_hyper_normalize_offset - PURPOSE - "Normalize" a hyperslab selection by adjusting it's coordinates by the - amount of the selection offset. - USAGE - hbool_t H5S_hyper_normalize_offset(space, old_offset) - H5S_t *space; IN/OUT: Pointer to dataspace to move - hssize_t *old_offset; OUT: Pointer to space to store old offset - RETURNS - TRUE if space has been normalized, FALSE if not - DESCRIPTION - Copies the current selection offset into the array provided, then - inverts the selection offset, subtracts the offset from the hyperslab - selection and resets the offset to zero. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -htri_t -H5S_hyper_normalize_offset(H5S_t *space, hssize_t *old_offset) -{ - htri_t ret_value = FALSE; /* Return value */ + /* Check if the 'stop' span in the "down tree" is equal to any other + * spans in the list of spans in the span tree. + * + * If so, release last span information and make last span merge into + * previous span (if possible), or at least share their "down tree" + * information. + */ + tmp_span = tail_span->down->head; + while(tmp_span != stop_span) { + hbool_t attempt_merge_spans = FALSE; /* Whether to merge spans */ - FUNC_ENTER_NOAPI(FAIL) + /* Different tests for when to run the 'merge' algorithm, + * depending whether there's "down trees" or not. + */ + if(NULL == tmp_span->down) { + /* Spin through spans until we find the one before the 'stop' span */ + if(tmp_span->next == stop_span) + attempt_merge_spans = TRUE; + } /* end if */ + else { + /* Check if we've compared the 'stop' span's "down tree" to + * this span's "down tree" already. + */ + if(tmp_span->down->op_info[0].op_gen != op_gen) { + if(H5S__hyper_cmp_spans(tmp_span->down, stop_span->down)) + attempt_merge_spans = TRUE; + + /* Remember that we visited this span's "down tree" already */ + /* (Because it wasn't the same as the 'stop' span's down tree + * and we don't need to compare it again) + */ + tmp_span->down->op_info[0].op_gen = op_gen; + } /* end if */ + } /* end else */ - /* Sanity checks */ - HDassert(space); - HDassert(old_offset); + /* Check for merging into previous span */ + if(attempt_merge_spans) { + if(tmp_span->high + 1 == stop_span->low) { + /* Increase size of previous span */ + tmp_span->high++; - /* Check for hyperslab selection & offset changed */ - if(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS && space->select.offset_changed) { - unsigned u; /* Local index variable */ + /* Update pointers appropriately */ + if(stop_span == prev_down_tail_span) { + /* Sanity check */ + HDassert(stop_span->next == tail_span->down->tail); - /* Copy & invert the selection offset */ - for(u = 0; u < space->extent.rank; u++) { - old_offset[u] = space->select.offset[u]; - space->select.offset[u] = -space->select.offset[u]; - } /* end for */ + tmp_span->next = stop_span->next; + } /* end if */ + else { + /* Sanity check */ + HDassert(tmp_span->next == tail_span->down->tail); - /* Call the 'adjust' routine */ - if(H5S_hyper_adjust_s(space, space->select.offset) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection") + tmp_span->next = NULL; + tail_span->down->tail = tmp_span; + } /* end else */ - /* Zero out the selection offset */ - HDmemset(space->select.offset, 0, sizeof(hssize_t) * space->extent.rank); + /* Release last span created */ + H5S__hyper_free_span(stop_span); + } /* end if */ + /* Span is disjoint, but has the same "down tree" selection */ + /* (If it has a "down tree") */ + else if(stop_span->down) { + /* Release "down tree" information */ + H5S__hyper_free_span_info(stop_span->down); - /* Indicate that the offset was normalized */ - ret_value = TRUE; + /* Point at earlier span's "down tree" */ + stop_span->down = tmp_span->down; + + /* Increment reference count on shared "down tree" */ + stop_span->down->count++; + } /* end else */ + + /* Found span to merge into, break out now */ + break; + } /* end if */ + + /* Advance to next span to check */ + tmp_span = tmp_span->next; + } /* end while */ + } /* end if */ } /* end if */ + else { + unsigned u; /* Local index variable */ + + /* Check if we made it all the way to the bottom span list in the tree + * and the new coordinate adjoins the current tail span. + */ + if(rank == 1 && (tail_span->high + 1) == coords[0]) + /* Append element to current tail span */ + tail_span->high++; + else { + H5S_hyper_span_t *new_span; /* New span created for element */ + + /* Make span tree for current coordinate(s) */ + if(NULL == (new_span = H5S__hyper_coord_to_span(rank, coords))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab spans for coordinate") + + /* Add new span to span tree list */ + tail_span->next = new_span; + span_tree->tail = new_span; + } /* end else */ + + /* Update high bound for current span tree */ + HDassert(coords[0] > span_tree->high_bounds[0]); + span_tree->high_bounds[0] = coords[0]; + + /* Update high bounds for dimensions below this one */ + for(u = 1; u < rank; u++) + if(coords[u] > span_tree->high_bounds[u]) + span_tree->high_bounds[u] = coords[u]; + + /* Need to signal to higher dimensions that high bounds changed */ + *first_dim_modified = 0; + } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_normalize_offset() */ +} /* end H5S__hyper_add_span_element_helper() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_denormalize_offset + H5S_hyper_add_span_element PURPOSE - "Denormalize" a hyperslab selection by reverse adjusting it's coordinates - by the amount of the former selection offset. + Add a single element to a span tree USAGE - herr_t H5S_hyper_denormalize_offset(space, old_offset) - H5S_t *space; IN/OUT: Pointer to dataspace to move - hssize_t *old_offset; IN: Pointer to old offset array + herr_t H5S_hyper_add_span_element(space, span_tree, rank, coords) + H5S_t *space; IN/OUT: Pointer to dataspace to add coordinate to + unsigned rank; IN: Number of dimensions of coordinates + hsize_t *coords; IN: Location of element to add to span tree RETURNS Non-negative on success, negative on failure DESCRIPTION - Subtracts the old offset from the current selection (canceling out the - effect of the "normalize" routine), then restores the old offset into - the dataspace. + Add a single element to an existing span tree. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS + Assumes that the element is not already in the dataspace's selection + + NOTE: There's also an assumption about the context of this function call - + This function is only called is only being called from H5D_chunk_mem_cb + in src/H5Dchunk.c, when the library is iterating over a memory + selection, so the coordinates passed to H5S_hyper_add_span_element will + always be in increasing order (according to a row-major (i.e. C, not + FORTRAN) scan) over the dataset. Therefore, for every input of + coordinates, only the last span element (i.e., the tail pointer) in + one dimension is checked against the input. + + NOTE: This algorithm is definitely "correct" and tries to conserve memory + as much as possible, but it's doing a _lot_ of work that might be + better spent running a similar algorithm to "condense" the span tree + (possibly even back into a regular selection) just before the selection + is used for I/O on the chunk. I'm not going to spend the time on this + currently, but it does sound like a good direction to explore. + QAK, 2019/01/24 + EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ herr_t -H5S_hyper_denormalize_offset(H5S_t *space, const hssize_t *old_offset) +H5S_hyper_add_span_element(H5S_t *space, unsigned rank, const hsize_t *coords) { - herr_t ret_value = SUCCEED; /* Return value */ + H5S_hyper_span_info_t *head = NULL; /* Pointer to new head of span tree */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) - /* Sanity checks */ HDassert(space); - HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS); + HDassert(rank > 0); + HDassert(coords); + HDassert(space->extent.rank == rank); - /* Call the 'adjust' routine */ - if(H5S_hyper_adjust_s(space, old_offset) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection") + /* Check if this is the first element in the selection */ + if(NULL == space->select.sel_info.hslab) { + /* Allocate a span info node */ + if(NULL == (head = H5S__hyper_new_span_info(rank))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span info") + + /* Set the low & high bounds for this span info node */ + H5MM_memcpy(head->low_bounds, coords, rank * sizeof(hsize_t)); + H5MM_memcpy(head->high_bounds, coords, rank * sizeof(hsize_t)); + + /* Set the reference count */ + head->count = 1; + + /* Build span tree for this coordinate */ + if(NULL == (head->head = H5S__hyper_coord_to_span(rank, coords))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab spans for coordinate") + + /* Update the tail pointer of this newly created span in dimension "rank" */ + head->tail = head->head; + + /* Allocate selection info */ + if(NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab selection") + + /* Set the selection to the new span tree */ + space->select.sel_info.hslab->span_lst = head; + + /* Set selection type */ + space->select.type = H5S_sel_hyper; + + /* Reset "regular" hyperslab flag */ + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; + + /* Set unlim_dim */ + space->select.sel_info.hslab->unlim_dim = -1; + + /* Set # of elements in selection */ + space->select.num_elem = 1; + } /* end if */ + else { + int first_dim_modified = -1; /* Index of first dimension modified */ - /* Copy the selection offset over */ - H5MM_memcpy(space->select.offset, old_offset, sizeof(hssize_t) * space->extent.rank); + /* Add the element to the current set of spans */ + if(H5S__hyper_add_span_element_helper(space->select.sel_info.hslab->span_lst, rank, coords, &first_dim_modified) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert coordinate into span tree") + + /* Increment # of elements in selection */ + space->select.num_elem++; + } /* end else */ done: + if(ret_value < 0) + if(head) + H5S__hyper_free_span_info(head); + FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_denormalize_offset() */ +} /* end H5S_hyper_add_span_element() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_append_span + H5S__hyper_intersect_block_helper PURPOSE - Create a new span and append to span list + Helper routine to detect intersections in span trees USAGE - herr_t H5S__hyper_append_span(prev_span, span_tree, low, high, down, next) - H5S_hyper_span_t **prev_span; IN/OUT: Pointer to previous span in list - H5S_hyper_span_info_t **span_tree; IN/OUT: Pointer to span tree to append to - hsize_t low, high; IN: Low and high bounds for new span node - H5S_hyper_span_info_t *down; IN: Down span tree for new node - H5S_hyper_span_t *next; IN: Next span for new node - RETURNS - Non-negative on success, negative on failure + hbool_t H5S__hyper_intersect_block_helper(spans, rank, start, end, op_info_i, op_gen) + H5S_hyper_span_info_t *spans; IN: First span tree to operate with + unsigned rank; IN: Number of dimensions for span tree + hsize_t *start; IN: Starting coordinate for block + hsize_t *end; IN: Ending coordinate for block + unsigned op_info_i; IN: Index of op info to use + uint64_t op_gen; IN: Operation generation + RETURN + Non-negative (TRUE/FALSE) on success, can't fail DESCRIPTION - Create a new span node and append to a span list. Update the previous - span in the list also. + Quickly detect intersections between span tree and block GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_append_span(H5S_hyper_span_t **prev_span, - H5S_hyper_span_info_t **span_tree, hsize_t low, hsize_t high, H5S_hyper_span_info_t *down, H5S_hyper_span_t *next) +static hbool_t +H5S__hyper_intersect_block_helper(H5S_hyper_span_info_t *spans, + unsigned rank, const hsize_t *start, const hsize_t *end, unsigned op_info_i, + uint64_t op_gen) { - H5S_hyper_span_t *new_span = NULL; - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_STATIC + hbool_t ret_value = FALSE; /* Return value */ - /* Sanity checks */ - HDassert(prev_span); - HDassert(span_tree); + FUNC_ENTER_STATIC_NOERR - /* Check for adding first node to merged spans */ - if(*prev_span == NULL) { - /* Allocate new span node to append to list */ - if(NULL == (new_span = H5S__hyper_new_span(low, high, down, next))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span") + /* Sanity check */ + HDassert(spans); + HDassert(start); + HDassert(end); - /* Make first node in span list */ + /* Check if we've already visited this span tree */ + if(spans->op_info[op_info_i].op_gen != op_gen) { + H5S_hyper_span_t *curr; /* Pointer to current span in 1st span tree */ + unsigned u; /* Local index variable */ - /* Check that we haven't already allocated a span tree */ - HDassert(*span_tree == NULL); + /* Verify that there is a possibility of an overlap by checking the block + * against the low & high bounds for the span tree. + */ + for(u = 0; u < rank; u++) + if(start[u] > spans->high_bounds[u] || end[u] < spans->low_bounds[u]) + HGOTO_DONE(FALSE) - /* Allocate a new span_info node */ - if(NULL == (*span_tree = H5FL_CALLOC(H5S_hyper_span_info_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span") + /* Get the span list for spans in this tree */ + curr = spans->head; - /* Set the span tree's basic information */ - (*span_tree)->count = 1; - (*span_tree)->head = new_span; + /* Iterate over the spans in the tree */ + while(curr != NULL) { + /* Check for span entirely before block */ + if(curr->high < *start) + /* Advance to next span in this dimension */ + curr = curr->next; + /* If this span is past the end of the block, then we're done in this dimension */ + else if(curr->low > *end) + HGOTO_DONE(FALSE) + /* block & span overlap */ + else { + /* If this is the bottom dimension, then the span tree overlaps the block */ + if(curr->down == NULL) + HGOTO_DONE(TRUE) + /* Recursively check spans in next dimension down */ + else { + /* If there is an intersection in the "down" dimensions, + * the span trees overlap. + */ + if(H5S__hyper_intersect_block_helper(curr->down, rank - 1, start + 1, end + 1, op_info_i, op_gen)) + HGOTO_DONE(TRUE) + + /* No intersection in down dimensions, advance to next span */ + curr = curr->next; + } /* end else */ + } /* end else */ + } /* end while */ - /* Update previous merged span */ - *prev_span = new_span; + /* Set the tree's operation generation */ + spans->op_info[op_info_i].op_gen = op_gen; } /* end if */ - /* Merge or append to existing merged spans list */ - else { - /* Check if span can just extend the previous merged span */ - if((((*prev_span)->high + 1) == low) && - H5S__hyper_cmp_spans(down, (*prev_span)->down)==TRUE) { - /* Extend previous merged span to include new high bound */ - (*prev_span)->high = high; - (*prev_span)->nelem += (high - low) + 1; - } /* end if */ - else { - /* Allocate new span node to append to list */ - if(NULL == (new_span = H5S__hyper_new_span(low, high, down, next))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") - - /* Check if there is actually a down span */ - if(new_span->down) { - /* Check if the down spans for the new span node are the same as the previous span node */ - if(H5S__hyper_cmp_spans(new_span->down, (*prev_span)->down)) { - /* Release the down span for the new node */ - H5S__hyper_free_span_info(new_span->down); - - /* Point the new node's down span at the previous node's down span */ - new_span->down = (*prev_span)->down; - - /* Increment the reference count to the shared down span */ - new_span->down->count++; - } /* end if */ - } /* end if */ - - /* Indicate elements from previous span */ - new_span->pstride = low - (*prev_span)->low; - /* Append to end of merged spans list */ - (*prev_span)->next = new_span; - *prev_span = new_span; - } /* end else */ - } /* end else */ + /* Fall through with 'FALSE' return value */ done: - if(ret_value < 0) - if(new_span && H5S__hyper_free_span(new_span) < 0) - HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "failed to release new hyperslab span") - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_append_span() */ +} /* end H5S__hyper_intersect_block_helper() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_clip_spans + H5S__hyper_intersect_block PURPOSE - Clip a new span tree against the current spans in the hyperslab selection + Detect intersections of selection with block USAGE - herr_t H5S__hyper_clip_spans(span_a, span_b, a_not_b, a_and_b, b_not_a) - H5S_hyper_span_t *a_spans; IN: Span tree 'a' to clip with. - H5S_hyper_span_t *b_spans; IN: Span tree 'b' to clip with. - H5S_hyper_span_t **a_not_b; OUT: Span tree of 'a' hyperslab spans which - doesn't overlap with 'b' hyperslab - spans. - H5S_hyper_span_t **a_and_b; OUT: Span tree of 'a' hyperslab spans which - overlaps with 'b' hyperslab spans. - H5S_hyper_span_t **b_not_a; OUT: Span tree of 'b' hyperslab spans which - doesn't overlap with 'a' hyperslab - spans. + htri_t H5S__hyper_intersect_block(space, start, end) + const H5S_t *space; IN: Dataspace with selection to use + const hsize_t *start; IN: Starting coordinate for block + const hsize_t *end; IN: Ending coordinate for block RETURNS - non-negative on success, negative on failure + Non-negative TRUE / FALSE on success, negative on failure DESCRIPTION - Clip one span tree ('a') against another span tree ('b'). Creates span - trees for the area defined by the 'a' span tree which does not overlap the - 'b' span tree, the area defined by the overlap of the 'a' hyperslab span - tree and the 'b' span tree, and the area defined by the 'b' hyperslab span - tree which does not overlap the 'a' span tree. + Quickly detect intersections between both regular hyperslabs and span trees + with a block GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS + Does not use selection offset. EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans, - H5S_hyper_span_info_t **a_not_b, H5S_hyper_span_info_t **a_and_b, - H5S_hyper_span_info_t **b_not_a) +static htri_t +H5S__hyper_intersect_block(const H5S_t *space, const hsize_t *start, const hsize_t *end) { - H5S_hyper_span_t *span_a; /* Pointer to a node in span tree 'a' */ - H5S_hyper_span_t *span_b; /* Pointer to a node in span tree 'b' */ - H5S_hyper_span_t *tmp_span; /* Temporary pointer to new span */ - H5S_hyper_span_t *last_a_not_b; /* Pointer to previous node in span tree 'a_not_b' */ - H5S_hyper_span_t *last_a_and_b; /* Pointer to previous node in span tree 'a_and_b' */ - H5S_hyper_span_t *last_b_not_a; /* Pointer to previous node in span tree 'b_not_a' */ - H5S_hyper_span_info_t *down_a_not_b; /* Temporary pointer to a_not_b span tree of down spans for overlapping nodes */ - H5S_hyper_span_info_t *down_a_and_b; /* Temporary pointer to a_and_b span tree of down spans for overlapping nodes */ - H5S_hyper_span_info_t *down_b_not_a; /* Temporary pointer to b_and_a span tree of down spans for overlapping nodes */ - hbool_t recover_a, recover_b; /* Flags to indicate when to recover temporary spans */ - herr_t ret_value = SUCCEED; /* Return value */ + htri_t ret_value = FAIL; /* Return value */ - FUNC_ENTER_STATIC + FUNC_ENTER_STATIC_NOERR - /* Check args */ - HDassert(a_spans); - HDassert(b_spans); - HDassert(a_not_b); - HDassert(a_and_b); - HDassert(b_not_a); + /* Sanity check */ + HDassert(space); + HDassert(H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space)); + HDassert(start); + HDassert(end); - /* Check if both span trees are not defined */ - if(a_spans == NULL && b_spans == NULL) { - *a_not_b = NULL; - *a_and_b = NULL; - *b_not_a = NULL; - } /* end if */ - /* If span 'a' is not defined, but 'b' is, copy 'b' and set the other return span trees to empty */ - else if(a_spans == NULL) { - *a_not_b = NULL; - *a_and_b = NULL; - if(NULL == (*b_not_a = H5S__hyper_copy_span(b_spans))) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree") - } /* end if */ - /* If span 'b' is not defined, but 'a' is, copy 'a' and set the other return span trees to empty */ - else if(b_spans == NULL) { - if(NULL == (*a_not_b = H5S__hyper_copy_span(a_spans)) ) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree") - *a_and_b = NULL; - *b_not_a = NULL; - } /* end if */ - /* If span 'a' and 'b' are both defined, calculate the proper span trees */ - else { - /* Check if both span trees completely overlap */ - if(H5S__hyper_cmp_spans(a_spans, b_spans)) { - *a_not_b = NULL; - if(NULL == (*a_and_b = H5S__hyper_copy_span(a_spans))) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree") - *b_not_a = NULL; - } /* end if */ - else { - /* Get the pointers to the new and old span lists */ - span_a = a_spans->head; - span_b = b_spans->head; + /* Attempt to rebuild diminfo if it is invalid and has not been confirmed + * to be impossible. + */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO) + H5S__hyper_rebuild((H5S_t *)space); /* Casting away const OK -QAK */ - /* Reset the pointers to the previous spans */ - last_a_not_b = last_a_and_b = last_b_not_a = NULL; + /* Check for regular hyperslab intersection */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + hbool_t single_block; /* Whether the regular selection is a single block */ + unsigned u; /* Local index variable */ - /* No spans to recover yet */ - recover_a = recover_b = FALSE; + /* Check for a single block */ + /* For a regular hyperslab to be single, it must have only one block + * (i.e. count == 1 in all dimensions). + */ + single_block = TRUE; + for(u = 0; u < space->extent.rank; u++) + if(space->select.sel_info.hslab->diminfo.opt[u].count > 1) + single_block = FALSE; - /* Work through the list of spans in the new list */ - while(span_a != NULL && span_b != NULL) { - /* Check if span 'a' is completely before span 'b' */ - /* AAAAAAA */ - /* <-----------------------------------> */ - /* BBBBBBBBBB */ - if(span_a->high < span_b->low) { - /* Copy span 'a' and add to a_not_b list */ + /* Single blocks have already been "compared" above, in the low / high + * bound checking, so just return TRUE if we've reached here - they + * would have been rejected earlier, if they didn't intersect. + */ + if(single_block) + HGOTO_DONE(TRUE) + else { + /* Loop over the dimensions, checking for an intersection */ + for(u = 0; u < space->extent.rank; u++) { + /* If the block's start is <= the hyperslab start, they intersect */ + /* (So, if the start is > the hyperslab start, check more conditions) */ + if(start[u] > space->select.sel_info.hslab->diminfo.opt[u].start) { + hsize_t adj_start; /* Start coord, adjusted for hyperslab selection parameters */ + hsize_t nstride; /* Number of strides into the selection */ + + /* Adjust start coord for selection's 'start' offset */ + adj_start = start[u] - space->select.sel_info.hslab->diminfo.opt[u].start; + + /* Compute # of strides into the selection */ + if(space->select.sel_info.hslab->diminfo.opt[u].count > 1) + nstride = adj_start / space->select.sel_info.hslab->diminfo.opt[u].stride; + else + nstride = 0; - /* Merge/add span 'a' with/to a_not_b list */ - if(H5S__hyper_append_span(&last_a_not_b, a_not_b, span_a->low, span_a->high, span_a->down, NULL) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* Sanity check */ + HDassert(nstride <= space->select.sel_info.hslab->diminfo.opt[u].count); - /* Advance span 'a', leave span 'b' */ - H5S__hyper_recover_span(&recover_a, &span_a, span_a->next); - } /* end if */ - /* Check if span 'a' overlaps only the lower bound */ - /* of span 'b' , up to the upper bound of span 'b' */ - /* AAAAAAAAAAAA */ - /* <-----------------------------------> */ - /* BBBBBBBBBB */ - else if(span_a->low < span_b->low && (span_a->high >= span_b->low && span_a->high <= span_b->high)) { - /* Split span 'a' into two parts at the low bound of span 'b' */ + /* "Rebase" the adjusted start coord into the same range + * range of values as the selections's first block. + */ + adj_start -= nstride * space->select.sel_info.hslab->diminfo.opt[u].stride; - /* Merge/add lower part of span 'a' with/to a_not_b list */ - if(H5S__hyper_append_span(&last_a_not_b, a_not_b, span_a->low, span_b->low - 1, span_a->down, NULL) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* If the adjusted start doesn't fall within the first hyperslab + * span, check for the block overlapping with the next one. + */ + if(adj_start >= space->select.sel_info.hslab->diminfo.opt[u].block) { + hsize_t adj_end; /* End coord, adjusted for hyperslab selection parameters */ - /* Check for overlaps between upper part of span 'a' and lower part of span 'b' */ + /* Adjust end coord for selection's 'start' offset */ + adj_end = end[u] - space->select.sel_info.hslab->diminfo.opt[u].start; - /* Make certain both spans either have a down span or both don't have one */ - HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL)); + /* "Rebase" the adjusted end coord into the same range + * range of values as the selections's first block. + */ + adj_end -= nstride * space->select.sel_info.hslab->diminfo.opt[u].stride; - /* If there are no down spans, just add the overlapping area to the a_and_b list */ - if(span_a->down == NULL) { - /* Merge/add overlapped part with/to a_and_b list */ - if(H5S__hyper_append_span(&last_a_and_b, a_and_b, span_b->low, span_a->high, NULL, NULL) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* If block doesn't extend over beginning of next span, + * it doesn't intersect. + */ + if(adj_end < space->select.sel_info.hslab->diminfo.opt[u].stride) + HGOTO_DONE(FALSE) } /* end if */ - /* If there are down spans, check for the overlap in them and add to each appropriate list */ - else { - /* NULL out the temporary pointers to clipped areas in down spans */ - down_a_not_b = NULL; - down_a_and_b = NULL; - down_b_not_a = NULL; - - /* Check for overlaps in the 'down spans' of span 'a' & 'b' */ - if(H5S__hyper_clip_spans(span_a->down,span_b->down,&down_a_not_b,&down_a_and_b,&down_b_not_a)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") - - /* Check for additions to the a_not_b list */ - if(down_a_not_b) { - /* Merge/add overlapped part with/to a_not_b list */ - if(H5S__hyper_append_span(&last_a_not_b,a_not_b,span_b->low,span_a->high,down_a_not_b,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_a_not_b); - } /* end if */ - - /* Check for additions to the a_and_b list */ - if(down_a_and_b) { - /* Merge/add overlapped part with/to a_and_b list */ - if(H5S__hyper_append_span(&last_a_and_b,a_and_b,span_b->low,span_a->high,down_a_and_b,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_a_and_b); - } /* end if */ - - /* Check for additions to the b_not_a list */ - if(down_b_not_a) { - /* Merge/add overlapped part with/to b_not_a list */ - if(H5S__hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_a->high,down_b_not_a,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + } /* end if */ + } /* end for */ - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_b_not_a); - } /* end if */ - } /* end else */ + /* If we've looped through all dimensions and none of them didn't + * overlap, then all of them do, so we report TRUE. + */ + HGOTO_DONE(TRUE) + } /* end else */ + } /* end if */ + else { + uint64_t op_gen; /* Operation generation value */ - /* Split off upper part of span 'b' at upper span of span 'a' */ + /* Acquire an operation generation value for this operation */ + op_gen = H5S__hyper_get_op_gen(); - /* Check if there is actually an upper part of span 'b' to split off */ - if(span_a->highhigh) { - /* Allocate new span node for upper part of span 'b' */ - if(NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down, span_b->next))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + /* Perform the span-by-span intersection check */ + /* Always use op_info[0] since we own this op_info, so there can be no + * simultaneous operations */ + ret_value = H5S__hyper_intersect_block_helper(space->select.sel_info.hslab->span_lst, space->extent.rank, start, end, 0, op_gen); + } /* end else */ - /* Advance span 'a' */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_intersect_block() */ - /* Make upper part of span 'b' into new span 'b' */ - H5S__hyper_recover_span(&recover_b,&span_b,tmp_span); - recover_b = TRUE; - } /* end if */ - /* No upper part of span 'b' to split */ - else { - /* Advance both 'a' and 'b' */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end else */ - } /* end if */ - /* Check if span 'a' overlaps the lower & upper bound */ - /* of span 'b' */ - /* AAAAAAAAAAAAAAAAAAAAA */ - /* <-----------------------------------> */ - /* BBBBBBBBBB */ - else if(span_a->low < span_b->low && span_a->high > span_b->high) { - /* Split off lower part of span 'a' at lower span of span 'b' */ + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_adjust_u_helper + PURPOSE + Helper routine to adjust offsets in span trees + USAGE + void H5S__hyper_adjust_u_helper(spans, rank, offset, op_info_i, op_gen) + H5S_hyper_span_info_t *spans; IN: Span tree to operate with + unsigned rank; IN: Number of dimensions for span tree + const hsize_t *offset; IN: Offset to subtract + unsigned op_info_i; IN: Index of op info to use + uint64_t op_gen; IN: Operation generation + RETURNS + None + DESCRIPTION + Adjust the location of the spans in a span tree by subtracting an offset + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static void +H5S__hyper_adjust_u_helper(H5S_hyper_span_info_t *spans, unsigned rank, + const hsize_t *offset, unsigned op_info_i, uint64_t op_gen) +{ + FUNC_ENTER_STATIC_NOERR - /* Merge/add lower part of span 'a' with/to a_not_b list */ - if(H5S__hyper_append_span(&last_a_not_b,a_not_b,span_a->low,span_b->low-1,span_a->down,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* Sanity checks */ + HDassert(spans); + HDassert(offset); - /* Check for overlaps between middle part of span 'a' and span 'b' */ + /* Check if we've already set this span tree */ + if(spans->op_info[op_info_i].op_gen != op_gen) { + H5S_hyper_span_t *span; /* Pointer to current span in span tree */ + unsigned u; /* Local index variable */ - /* Make certain both spans either have a down span or both don't have one */ - HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL)); + /* Adjust the span tree's low & high bounds */ + for(u = 0; u < rank; u++) { + HDassert(spans->low_bounds[u] >= offset[u]); + spans->low_bounds[u] -= offset[u]; + spans->high_bounds[u] -= offset[u]; + } /* end for */ - /* If there are no down spans, just add the overlapping area to the a_and_b list */ - if(span_a->down == NULL) { - /* Merge/add overlapped part with/to a_and_b list */ - if(H5S__hyper_append_span(&last_a_and_b,a_and_b,span_b->low,span_b->high,NULL,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - } /* end if */ - /* If there are down spans, check for the overlap in them and add to each appropriate list */ - else { - /* NULL out the temporary pointers to clipped areas in down spans */ - down_a_not_b = NULL; - down_a_and_b = NULL; - down_b_not_a = NULL; + /* Iterate over the spans in tree */ + span = spans->head; + while(span != NULL) { + /* Adjust span offset */ + HDassert(span->low >= *offset); + span->low -= *offset; + span->high -= *offset; - /* Check for overlaps in the 'down spans' of span 'a' & 'b' */ - if(H5S__hyper_clip_spans(span_a->down,span_b->down,&down_a_not_b,&down_a_and_b,&down_b_not_a)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") + /* Recursively adjust spans in next dimension down */ + if(span->down != NULL) + H5S__hyper_adjust_u_helper(span->down, rank - 1, offset + 1, op_info_i, op_gen); - /* Check for additions to the a_not_b list */ - if(down_a_not_b) { - /* Merge/add overlapped part with/to a_not_b list */ - if(H5S__hyper_append_span(&last_a_not_b,a_not_b,span_b->low,span_b->high,down_a_not_b,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* Advance to next span in this dimension */ + span = span->next; + } /* end while */ - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_a_not_b); - } /* end if */ + /* Set the tree's operation generation */ + spans->op_info[op_info_i].op_gen = op_gen; + } /* end if */ - /* Check for additions to the a_and_b list */ - if(down_a_and_b) { - /* Merge/add overlapped part with/to a_and_b list */ - if(H5S__hyper_append_span(&last_a_and_b,a_and_b,span_b->low,span_b->high,down_a_and_b,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + FUNC_LEAVE_NOAPI_VOID +} /* end H5S__hyper_adjust_u_helper() */ - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_a_and_b); - } /* end if */ + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_adjust_u + PURPOSE + Adjust a hyperslab selection by subtracting an offset + USAGE + void H5S__hyper_adjust_u(space,offset) + H5S_t *space; IN/OUT: Pointer to dataspace to adjust + const hsize_t *offset; IN: Offset to subtract + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Moves a hyperslab selection by subtracting an offset from it. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_adjust_u(H5S_t *space, const hsize_t *offset) +{ + hbool_t non_zero_offset = FALSE; /* Whether any offset is non-zero */ + unsigned u; /* Local index variable */ - /* Check for additions to the b_not_a list */ - if(down_b_not_a) { - /* Merge/add overlapped part with/to b_not_a list */ - if(H5S__hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_b->high,down_b_not_a,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + FUNC_ENTER_STATIC_NOERR - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_b_not_a); - } /* end if */ - } /* end else */ + /* Sanity check */ + HDassert(space); + HDassert(offset); - /* Split off upper part of span 'a' at upper span of span 'b' */ + /* Check for an all-zero offset vector */ + for(u = 0; u < space->extent.rank; u++) + if(0 != offset[u]) { + non_zero_offset = TRUE; + break; + } - /* Allocate new span node for upper part of span 'a' */ - if(NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down, span_a->next))) - HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + /* Only perform operation if the offset is non-zero */ + if(non_zero_offset) { + /* Subtract the offset from the "regular" coordinates, if they exist */ + /* (No need to rebuild the dimension info yet -QAK) */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + for(u = 0; u < space->extent.rank; u++) { + HDassert(space->select.sel_info.hslab->diminfo.opt[u].start >= offset[u]); + space->select.sel_info.hslab->diminfo.opt[u].start -= offset[u]; - /* Make upper part of span 'a' the new span 'a' */ - H5S__hyper_recover_span(&recover_a,&span_a,tmp_span); - recover_a = TRUE; + /* Adjust the low & high bounds */ + HDassert(space->select.sel_info.hslab->diminfo.low_bounds[u] >= offset[u]); + space->select.sel_info.hslab->diminfo.low_bounds[u] -= offset[u]; + space->select.sel_info.hslab->diminfo.high_bounds[u] -= offset[u]; + } /* end for */ + } /* end if */ - /* Advance span 'b' */ - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end if */ - /* Check if span 'a' is entirely within span 'b' */ - /* AAAAA */ - /* <-----------------------------------> */ - /* BBBBBBBBBB */ - else if(span_a->low >= span_b->low && span_a->high <= span_b->high) { - /* Split off lower part of span 'b' at lower span of span 'a' */ + /* Subtract the offset from the span tree coordinates, if they exist */ + if(space->select.sel_info.hslab->span_lst) { + uint64_t op_gen; /* Operation generation value */ - /* Check if there is actually a lower part of span 'b' to split off */ - if(span_a->low > span_b->low) { - /* Merge/add lower part of span 'b' with/to b_not_a list */ - if(H5S__hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_a->low-1,span_b->down,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - } /* end if */ - else { - /* Keep going, nothing to split off */ - } /* end else */ + /* Acquire an operation generation value for this operation */ + op_gen = H5S__hyper_get_op_gen(); - /* Check for overlaps between span 'a' and midle of span 'b' */ + /* Perform adjustment */ + /* Always use op_info[0] since we own this op_info, so there can be no + * simultaneous operations */ + H5S__hyper_adjust_u_helper(space->select.sel_info.hslab->span_lst, space->extent.rank, offset, 0, op_gen); + } /* end if */ + } /* end if */ - /* Make certain both spans either have a down span or both don't have one */ - HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL)); + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_adjust_u() */ - /* If there are no down spans, just add the overlapping area to the a_and_b list */ - if(span_a->down == NULL) { - /* Merge/add overlapped part with/to a_and_b list */ - if(H5S__hyper_append_span(&last_a_and_b,a_and_b,span_a->low,span_a->high,NULL,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - } /* end if */ - /* If there are down spans, check for the overlap in them and add to each appropriate list */ - else { - /* NULL out the temporary pointers to clipped areas in down spans */ - down_a_not_b = NULL; - down_a_and_b = NULL; - down_b_not_a = NULL; + +/*------------------------------------------------------------------------- + * Function: H5S__hyper_project_scalar + * + * Purpose: Projects a single element hyperslab selection into a scalar + * dataspace + * + * Return: Non-negative on success, negative on failure. + * + * Programmer: Quincey Koziol + * Sunday, July 18, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S__hyper_project_scalar(const H5S_t *space, hsize_t *offset) +{ + hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */ - /* Check for overlaps in the 'down spans' of span 'a' & 'b' */ - if(H5S__hyper_clip_spans(span_a->down,span_b->down,&down_a_not_b,&down_a_and_b,&down_b_not_a)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") + FUNC_ENTER_STATIC_NOERR - /* Check for additions to the a_not_b list */ - if(down_a_not_b) { - /* Merge/add overlapped part with/to a_not_b list */ - if(H5S__hyper_append_span(&last_a_not_b,a_not_b,span_a->low,span_a->high,down_a_not_b,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* Check args */ + HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space)); + HDassert(offset); - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_a_not_b); - } /* end if */ + /* Check for a "regular" hyperslab selection */ + /* (No need to rebuild the dimension info yet -QAK) */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->diminfo.opt; /* Alias for dataspace's diminfo information */ + unsigned u; /* Counter */ - /* Check for additions to the a_and_b list */ - if(down_a_and_b!=NULL) { - /* Merge/add overlapped part with/to a_and_b list */ - if(H5S__hyper_append_span(&last_a_and_b,a_and_b,span_a->low,span_a->high,down_a_and_b,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* Build the table of the initial offset */ + for(u = 0; u < space->extent.rank; u++) { + /* Sanity check diminfo */ + HDassert(1 == diminfo[u].count); + HDassert(1 == diminfo[u].block); - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_a_and_b); - } /* end if */ + /* Sanity check bounds, while we're here */ + HDassert(diminfo[u].start == space->select.sel_info.hslab->diminfo.low_bounds[u]); - /* Check for additions to the b_not_a list */ - if(down_b_not_a!=NULL) { - /* Merge/add overlapped part with/to b_not_a list */ - if(H5S__hyper_append_span(&last_b_not_a,b_not_a,span_a->low,span_a->high,down_b_not_a,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* Keep the offset for later */ + block[u] = diminfo[u].start; + } /* end for */ + } /* end if */ + else { + const H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */ + unsigned curr_dim; /* Current dimension being operated on */ - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_b_not_a); - } /* end if */ - } /* end else */ + /* Advance down selected spans */ + curr = space->select.sel_info.hslab->span_lst->head; + curr_dim = 0; + while(1) { + /* Sanity checks */ + HDassert(NULL == curr->next); + HDassert(curr->low == curr->high); + HDassert(curr_dim < space->extent.rank); - /* Check if there is actually an upper part of span 'b' to split off */ - if(span_a->highhigh) { - /* Split off upper part of span 'b' at upper span of span 'a' */ + /* Save the location of the selection in current dimension */ + block[curr_dim] = curr->low; - /* Allocate new span node for upper part of spans 'a' */ - if(NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down, span_b->next))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + /* Advance down to next dimension */ + if(curr->down) { + curr = curr->down->head; + curr_dim++; + } /* end if */ + else + break; + } /* end while */ + } /* end else */ - /* And advance span 'a' */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); + /* Calculate offset of selection in projected buffer */ + *offset = H5VM_array_offset(space->extent.rank, space->extent.size, block); - /* Make upper part of span 'b' the new span 'b' */ - H5S__hyper_recover_span(&recover_b,&span_b,tmp_span); - recover_b=1; - } /* end if */ - else { - /* Advance both span 'a' & span 'b' */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end else */ - } /* end if */ - /* Check if span 'a' overlaps only the upper bound */ - /* of span 'b' */ - /* AAAAAAAAAA */ - /* <-----------------------------------> */ - /* BBBBBBBBBB */ - else if((span_a->low>=span_b->low && span_a->low<=span_b->high) && span_a->high>span_b->high) { - /* Check if there is actually a lower part of span 'b' to split off */ - if(span_a->low>span_b->low) { - /* Split off lower part of span 'b' at lower span of span 'a' */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_project_scalar() */ - /* Merge/add lower part of span 'b' with/to b_not_a list */ - if(H5S__hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_a->low-1,span_b->down,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - } /* end if */ - else { - /* Keep going, nothing to split off */ - } /* end else */ + +/*------------------------------------------------------------------------- + * Function: H5S__hyper_project_simple_lower + * + * Purpose: Projects a hyperslab selection onto/into a simple dataspace + * of a lower rank + * + * Return: Non-negative on success, negative on failure. + * + * Programmer: Quincey Koziol + * Sunday, July 18, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S__hyper_project_simple_lower(const H5S_t *base_space, H5S_t *new_space) +{ + H5S_hyper_span_info_t *down; /* Pointer to list of spans */ + unsigned curr_dim; /* Current dimension being operated on */ - /* Check for overlaps between lower part of span 'a' and upper part of span 'b' */ + FUNC_ENTER_STATIC_NOERR - /* Make certain both spans either have a down span or both don't have one */ - HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL)); + /* Check args */ + HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space)); + HDassert(new_space); + HDassert(new_space->extent.rank < base_space->extent.rank); - /* If there are no down spans, just add the overlapping area to the a_and_b list */ - if(span_a->down == NULL) { - /* Merge/add overlapped part with/to a_and_b list */ - if(H5S__hyper_append_span(&last_a_and_b,a_and_b,span_a->low,span_b->high,NULL,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - } /* end if */ - /* If there are down spans, check for the overlap in them and add to each appropriate list */ - else { - /* NULL out the temporary pointers to clipped areas in down spans */ - down_a_not_b = NULL; - down_a_and_b = NULL; - down_b_not_a = NULL; + /* Walk down the span tree until we reach the selection to project */ + down = base_space->select.sel_info.hslab->span_lst; + curr_dim = 0; + while(down && curr_dim < (base_space->extent.rank - new_space->extent.rank)) { + /* Sanity check */ + HDassert(NULL == down->head->next); - /* Check for overlaps in the 'down spans' of span 'a' & 'b' */ - if(H5S__hyper_clip_spans(span_a->down,span_b->down,&down_a_not_b,&down_a_and_b,&down_b_not_a)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") + /* Advance down to next dimension */ + down = down->head->down; + curr_dim++; + } /* end while */ + HDassert(down); - /* Check for additions to the a_not_b list */ - if(down_a_not_b) { - /* Merge/add overlapped part with/to a_not_b list */ - if(H5S__hyper_append_span(&last_a_not_b,a_not_b,span_a->low,span_b->high,down_a_not_b,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* Share the underlying hyperslab span information */ + new_space->select.sel_info.hslab->span_lst = down; + new_space->select.sel_info.hslab->span_lst->count++; - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_a_not_b); - } /* end if */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_project_simple_lower() */ - /* Check for additions to the a_and_b list */ - if(down_a_and_b!=NULL) { - /* Merge/add overlapped part with/to a_and_b list */ - if(H5S__hyper_append_span(&last_a_and_b,a_and_b,span_a->low,span_b->high,down_a_and_b,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + +/*------------------------------------------------------------------------- + * Function: H5S__hyper_project_simple_higher + * + * Purpose: Projects a hyperslab selection onto/into a simple dataspace + * of a higher rank + * + * Return: Non-negative on success, negative on failure. + * + * Programmer: Quincey Koziol + * Sunday, July 18, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S__hyper_project_simple_higher(const H5S_t *base_space, H5S_t *new_space) +{ + H5S_hyper_span_t *prev_span = NULL; /* Pointer to previous list of spans */ + unsigned delta_rank; /* Difference in dataspace ranks */ + unsigned curr_dim; /* Current dimension being operated on */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_a_and_b); - } /* end if */ + FUNC_ENTER_STATIC - /* Check for additions to the b_not_a list */ - if(down_b_not_a) { - /* Merge/add overlapped part with/to b_not_a list */ - if(H5S__hyper_append_span(&last_b_not_a,b_not_a,span_a->low,span_b->high,down_b_not_a,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* Check args */ + HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space)); + HDassert(new_space); + HDassert(new_space->extent.rank > base_space->extent.rank); - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_b_not_a); - } /* end if */ - } /* end else */ + /* Create nodes until reaching the correct # of dimensions */ + new_space->select.sel_info.hslab->span_lst = NULL; + curr_dim = 0; + delta_rank = (new_space->extent.rank - base_space->extent.rank); + while(curr_dim < delta_rank) { + H5S_hyper_span_info_t *new_span_info; /* Pointer to list of spans */ + H5S_hyper_span_t *new_span; /* Temporary hyperslab span */ - /* Split off upper part of span 'a' at upper span of span 'b' */ + /* Allocate a new span_info node */ + if(NULL == (new_span_info = H5S__hyper_new_span_info(new_space->extent.rank))) { + if(prev_span) + H5S__hyper_free_span(prev_span); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span info") + } /* end if */ - /* Allocate new span node for upper part of span 'a' */ - if(NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down, span_a->next))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + /* Check for linking into higher span */ + if(prev_span) + prev_span->down = new_span_info; - /* Make upper part of span 'a' into new span 'a' */ - H5S__hyper_recover_span(&recover_a,&span_a,tmp_span); - recover_a=1; + /* Allocate a new node */ + if(NULL == (new_span = H5S__hyper_new_span((hsize_t)0, (hsize_t)0, NULL, NULL))) { + HDassert(new_span_info); + if(!prev_span) + (void)H5FL_ARR_FREE(hbounds_t, new_span_info); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span") + } /* end if */ - /* Advance span 'b' */ - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end if */ - /* span 'a' must be entirely above span 'b' */ - /* AAAAA */ - /* <-----------------------------------> */ - /* BBBBBBBBBB */ - else { - /* Copy span 'b' and add to b_not_a list */ + /* Set the span_info information */ + new_span_info->count = 1; + new_span_info->head = new_span; + new_span_info->tail = new_span; - /* Merge/add span 'b' with/to b_not_a list */ - if(H5S__hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_b->high,span_b->down,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* Set the bounding box */ + for(u = 0; u < delta_rank; u++) { + new_span_info->low_bounds[u] = 0; + new_span_info->high_bounds[u] = 0; + } /* end for */ + for(; u < new_space->extent.rank; u++) { + new_span_info->low_bounds[u] = base_space->select.sel_info.hslab->span_lst->low_bounds[u - delta_rank]; + new_span_info->high_bounds[u] = base_space->select.sel_info.hslab->span_lst->high_bounds[u - delta_rank]; + } /* end for */ - /* Advance span 'b', leave span 'a' */ - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end else */ - } /* end while */ + /* Attach to new space, if top span info */ + if(NULL == new_space->select.sel_info.hslab->span_lst) + new_space->select.sel_info.hslab->span_lst = new_span_info; - /* Clean up 'a' spans which haven't been covered yet */ - if(span_a != NULL && span_b == NULL) { - while(span_a != NULL) { - /* Copy span 'a' and add to a_not_b list */ + /* Remember previous span info */ + prev_span = new_span; - /* Merge/add span 'a' with/to a_not_b list */ - if(H5S__hyper_append_span(&last_a_not_b,a_not_b,span_a->low,span_a->high,span_a->down,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* Advance to next dimension */ + curr_dim++; + } /* end while */ + HDassert(new_space->select.sel_info.hslab->span_lst); + HDassert(prev_span); - /* Advance to the next 'a' span */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - } /* end while */ - } /* end if */ - /* Clean up 'b' spans which haven't been covered yet */ - else if(span_a == NULL && span_b != NULL) { - while(span_b != NULL) { - /* Copy span 'b' and add to b_not_a list */ + /* Share the underlying hyperslab span information */ + prev_span->down = base_space->select.sel_info.hslab->span_lst; + prev_span->down->count++; - /* Merge/add span 'b' with/to b_not_a list */ - if(H5S__hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_b->high,span_b->down,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") +done: + if(ret_value < 0 && new_space->select.sel_info.hslab->span_lst) { + if(new_space->select.sel_info.hslab->span_lst->head) + H5S__hyper_free_span(new_space->select.sel_info.hslab->span_lst->head); - /* Advance to the next 'b' span */ - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end while */ - } /* end if */ - } /* end else */ - } /* end else */ + new_space->select.sel_info.hslab->span_lst = (H5S_hyper_span_info_t *)H5FL_ARR_FREE(hbounds_t, new_space->select.sel_info.hslab->span_lst); + } /* end if */ -done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_clip_spans() */ +} /* end H5S__hyper_project_simple_higher() */ -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_merge_spans_helper - PURPOSE - Merge two hyperslab span tree together - USAGE - H5S_hyper_span_info_t *H5S__hyper_merge_spans_helper(a_spans, b_spans) - H5S_hyper_span_info_t *a_spans; IN: First hyperslab spans to merge - together - H5S_hyper_span_info_t *b_spans; IN: Second hyperslab spans to merge - together - RETURNS - Pointer to span tree containing the merged spans on success, NULL on failure - DESCRIPTION - Merge two sets of hyperslab spans together and return the span tree from - the merged set. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static H5S_hyper_span_info_t * -H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans) +/*------------------------------------------------------------------------- + * Function: H5S__hyper_project_simple + * + * Purpose: Projects a hyperslab selection onto/into a simple dataspace + * of a different rank + * + * Return: Non-negative on success, negative on failure. + * + * Programmer: Quincey Koziol + * Sunday, July 18, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S__hyper_project_simple(const H5S_t *base_space, H5S_t *new_space, + hsize_t *offset) { - H5S_hyper_span_info_t *merged_spans = NULL; /* Pointer to the merged span tree */ - H5S_hyper_span_info_t *tmp_spans; /* Pointer to temporary new span tree */ - H5S_hyper_span_t *tmp_span; /* Pointer to temporary new span */ - H5S_hyper_span_t *span_a; /* Pointer to current span 'a' working on */ - H5S_hyper_span_t *span_b; /* Pointer to current span 'b' working on */ - H5S_hyper_span_t *prev_span_merge; /* Pointer to previous merged span */ - hbool_t recover_a, recover_b; /* Flags to indicate when to recover temporary spans */ - H5S_hyper_span_info_t *ret_value = NULL; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC - /* Make certain both 'a' & 'b' spans have down span trees or neither does */ - HDassert((a_spans != NULL && b_spans != NULL) || (a_spans == NULL && b_spans == NULL)); - - /* Check if the span trees for the 'a' span and the 'b' span are the same */ - if(H5S__hyper_cmp_spans(a_spans, b_spans)) { - if(a_spans == NULL) - merged_spans = NULL; - else { - /* Copy one of the span trees to return */ - if(NULL == (merged_spans = H5S__hyper_copy_span(a_spans))) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree") - } /* end else */ - } /* end if */ - else { - /* Get the pointers to the 'a' and 'b' span lists */ - span_a = a_spans->head; - span_b = b_spans->head; - - /* Set the pointer to the previous spans */ - prev_span_merge = NULL; - - /* No spans to recover yet */ - recover_a = recover_b = FALSE; - - /* Work through the list of spans in the new list */ - while(span_a != NULL && span_b != NULL) { - /* Check if the 'a' span is completely before 'b' span */ - /* AAAAAAA */ - /* <-----------------------------------> */ - /* BBBBBBBBBB */ - if(span_a->high < span_b->low) { - /* Merge/add span 'a' with/to the merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,span_a->down,NULL)==FAIL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + /* Check args */ + HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space)); + HDassert(new_space); + HDassert(offset); - /* Advance span 'a' */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - } /* end if */ - /* Check if span 'a' overlaps only the lower bound */ - /* of span 'b', up to the upper bound of span 'b' */ - /* AAAAAAAAAAAA */ - /* <-----------------------------------> */ - /* BBBBBBBBBB */ - else if(span_a->low < span_b->low && (span_a->high >= span_b->low && span_a->high <= span_b->high)) { - /* Check if span 'a' and span 'b' down spans are equal */ - if(H5S__hyper_cmp_spans(span_a->down, span_b->down)) { - /* Merge/add copy of span 'a' with/to merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,span_a->down,NULL)==FAIL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - } /* end if */ - else { - /* Merge/add lower part of span 'a' with/to merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->low-1,span_a->down,NULL)==FAIL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + /* We are setting a new selection, remove any current selection in new dataspace */ + if(H5S_SELECT_RELEASE(new_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") - /* Get merged span tree for overlapped section */ - tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down); + /* Allocate space for the hyperslab selection information */ + if(NULL == (new_space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info") - /* Merge/add overlapped section to merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->high,tmp_spans,NULL)==FAIL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + /* Set unlim_dim */ + new_space->select.sel_info.hslab->unlim_dim = -1; - /* Release merged span tree for overlapped section */ - H5S__hyper_free_span_info(tmp_spans); - } /* end else */ + /* Check for a "regular" hyperslab selection */ + /* (No need to rebuild the dimension info yet -QAK) */ + if(base_space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + unsigned base_space_dim; /* Current dimension in the base dataspace */ + unsigned new_space_dim; /* Current dimension in the new dataspace */ + unsigned u; /* Local index variable */ - /* Check if there is an upper part of span 'b' */ - if(span_a->high < span_b->high) { - /* Copy upper part of span 'b' as new span 'b' */ + /* Check if the new space's rank is < or > base space's rank */ + if(new_space->extent.rank < base_space->extent.rank) { + const H5S_hyper_dim_t *opt_diminfo = base_space->select.sel_info.hslab->diminfo.opt; /* Alias for dataspace's diminfo information */ + hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */ - /* Allocate new span node to append to list */ - if((tmp_span = H5S__hyper_new_span(span_a->high+1,span_b->high,span_b->down,span_b->next))==NULL) - HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, NULL, "can't allocate hyperslab span") + /* Compute the offset for the down-projection */ + HDmemset(block, 0, sizeof(block)); + for(u = 0; u < (base_space->extent.rank - new_space->extent.rank); u++) + block[u] = opt_diminfo[u].start; + *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block); - /* Advance span 'a' */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); + /* Set the correct dimensions for the base & new spaces */ + base_space_dim = base_space->extent.rank - new_space->extent.rank; + new_space_dim = 0; + } /* end if */ + else { + HDassert(new_space->extent.rank > base_space->extent.rank); - /* Set new span 'b' to tmp_span */ - H5S__hyper_recover_span(&recover_b,&span_b,tmp_span); - recover_b = TRUE; - } /* end if */ - else { - /* Advance both span 'a' & 'b' */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end else */ - } /* end if */ - /* Check if span 'a' overlaps the lower & upper bound */ - /* of span 'b' */ - /* AAAAAAAAAAAAAAAAAAAAA */ - /* <-----------------------------------> */ - /* BBBBBBBBBB */ - else if(span_a->low < span_b->low && span_a->high > span_b->high) { - /* Check if span 'a' and span 'b' down spans are equal */ - if(H5S__hyper_cmp_spans(span_a->down, span_b->down)) { - /* Merge/add copy of lower & middle parts of span 'a' to merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->high,span_a->down,NULL)==FAIL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - } /* end if */ - else { - /* Merge/add lower part of span 'a' to merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->low-1,span_a->down,NULL)==FAIL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + /* The offset is zero when projected into higher dimensions */ + *offset = 0; - /* Get merged span tree for overlapped section */ - tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down); + /* Set the diminfo information for the higher dimensions */ + for(new_space_dim = 0; new_space_dim < (new_space->extent.rank - base_space->extent.rank); new_space_dim++) { + new_space->select.sel_info.hslab->diminfo.app[new_space_dim].start = 0; + new_space->select.sel_info.hslab->diminfo.app[new_space_dim].stride = 1; + new_space->select.sel_info.hslab->diminfo.app[new_space_dim].count = 1; + new_space->select.sel_info.hslab->diminfo.app[new_space_dim].block = 1; - /* Merge/add overlapped section to merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,tmp_spans,NULL)==FAIL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].start = 0; + new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].stride = 1; + new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].count = 1; + new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].block = 1; + } /* end for */ - /* Release merged span tree for overlapped section */ - H5S__hyper_free_span_info(tmp_spans); - } /* end else */ + /* Start at beginning of base space's dimension info */ + base_space_dim = 0; + } /* end else */ - /* Copy upper part of span 'a' as new span 'a' (remember to free) */ + /* Copy the diminfo */ + while(base_space_dim < base_space->extent.rank) { + new_space->select.sel_info.hslab->diminfo.app[new_space_dim].start = + base_space->select.sel_info.hslab->diminfo.app[base_space_dim].start; + new_space->select.sel_info.hslab->diminfo.app[new_space_dim].stride = + base_space->select.sel_info.hslab->diminfo.app[base_space_dim].stride; + new_space->select.sel_info.hslab->diminfo.app[new_space_dim].count = + base_space->select.sel_info.hslab->diminfo.app[base_space_dim].count; + new_space->select.sel_info.hslab->diminfo.app[new_space_dim].block = + base_space->select.sel_info.hslab->diminfo.app[base_space_dim].block; - /* Allocate new span node to append to list */ - if(NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down, span_a->next))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") + new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].start = + base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].start; + new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].stride = + base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].stride; + new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].count = + base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].count; + new_space->select.sel_info.hslab->diminfo.opt[new_space_dim].block = + base_space->select.sel_info.hslab->diminfo.opt[base_space_dim].block; - /* Set new span 'a' to tmp_span */ - H5S__hyper_recover_span(&recover_a,&span_a,tmp_span); - recover_a = TRUE; + /* Advance to next dimensions */ + base_space_dim++; + new_space_dim++; + } /* end for */ - /* Advance span 'b' */ - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end if */ - /* Check if span 'a' is entirely within span 'b' */ - /* AAAAA */ - /* <-----------------------------------> */ - /* BBBBBBBBBB */ - else if(span_a->low >= span_b->low && span_a->high <= span_b->high) { - /* Check if span 'a' and span 'b' down spans are equal */ - if(H5S__hyper_cmp_spans(span_a->down, span_b->down)) { - /* Merge/add copy of lower & middle parts of span 'b' to merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->high,span_a->down,NULL)==FAIL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - } /* end if */ - else { - /* Check if there is a lower part of span 'b' */ - if(span_a->low > span_b->low) { - /* Merge/add lower part of span 'b' to merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->low-1,span_b->down,NULL)==FAIL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - } /* end if */ - else { - /* No lower part of span 'b' , keep going... */ - } /* end else */ + /* Update the bounding box */ + for(u = 0; u < new_space->extent.rank; u++) { + new_space->select.sel_info.hslab->diminfo.low_bounds[u] = new_space->select.sel_info.hslab->diminfo.opt[u].start; + new_space->select.sel_info.hslab->diminfo.high_bounds[u] = new_space->select.sel_info.hslab->diminfo.low_bounds[u] + new_space->select.sel_info.hslab->diminfo.opt[u].stride * (new_space->select.sel_info.hslab->diminfo.opt[u].count - 1) + (new_space->select.sel_info.hslab->diminfo.opt[u].block - 1); + } /* end for */ - /* Get merged span tree for overlapped section */ - tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down); + /* Indicate that the dimension information is valid */ + new_space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES; - /* Merge/add overlapped section to merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,tmp_spans,NULL)==FAIL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + /* Indicate that there's no slab information */ + new_space->select.sel_info.hslab->span_lst = NULL; + } /* end if */ + else { + /* Check if the new space's rank is < or > base space's rank */ + if(new_space->extent.rank < base_space->extent.rank) { + const H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */ + hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */ + unsigned curr_dim; /* Current dimension being operated on */ - /* Release merged span tree for overlapped section */ - H5S__hyper_free_span_info(tmp_spans); - } /* end else */ + /* Clear the block buffer */ + HDmemset(block, 0, sizeof(block)); - /* Check if there is an upper part of span 'b' */ - if(span_a->high < span_b->high) { - /* Copy upper part of span 'b' as new span 'b' (remember to free) */ + /* Advance down selected spans */ + curr = base_space->select.sel_info.hslab->span_lst->head; + curr_dim = 0; + while(curr && curr_dim < (base_space->extent.rank - new_space->extent.rank)) { + /* Save the location of the selection in current dimension */ + block[curr_dim] = curr->low; - /* Allocate new span node to append to list */ - if(NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down, span_b->next))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") + /* Advance down to next dimension */ + curr = curr->down->head; + curr_dim++; + } /* end while */ - /* Advance span 'a' */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); + /* Compute the offset for the down-projection */ + *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block); - /* Set new span 'b' to tmp_span */ - H5S__hyper_recover_span(&recover_b,&span_b,tmp_span); - recover_b = TRUE; - } /* end if */ - else { - /* Advance both spans */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end else */ - } /* end if */ - /* Check if span 'a' overlaps only the upper bound */ - /* of span 'b' */ - /* AAAAAAAAAA */ - /* <-----------------------------------> */ - /* BBBBBBBBBB */ - else if((span_a->low >= span_b->low && span_a->low <= span_b->high) && span_a->high > span_b->high) { - /* Check if span 'a' and span 'b' down spans are equal */ - if(H5S__hyper_cmp_spans(span_a->down, span_b->down)) { - /* Merge/add copy of span 'b' to merged spans if so */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,span_b->down,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - } /* end if */ - else { - /* Check if there is a lower part of span 'b' */ - if(span_a->low > span_b->low) { - /* Merge/add lower part of span 'b' to merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->low-1,span_b->down,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - } /* end if */ - else { - /* No lower part of span 'b' , keep going... */ - } /* end else */ + /* Project the base space's selection down in less dimensions */ + if(H5S__hyper_project_simple_lower(base_space, new_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't project hyperslab selection into less dimensions") + } /* end if */ + else { + HDassert(new_space->extent.rank > base_space->extent.rank); - /* Get merged span tree for overlapped section */ - tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down); + /* The offset is zero when projected into higher dimensions */ + *offset = 0; - /* Merge/add overlapped section to merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->high,tmp_spans,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + /* Project the base space's selection down in more dimensions */ + if(H5S__hyper_project_simple_higher(base_space, new_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't project hyperslab selection into less dimensions") + } /* end else */ - /* Release merged span tree for overlapped section */ - H5S__hyper_free_span_info(tmp_spans); - } /* end else */ + /* Copy the status of the dimension information */ + new_space->select.sel_info.hslab->diminfo_valid = base_space->select.sel_info.hslab->diminfo_valid; + } /* end else */ - /* Copy upper part of span 'a' as new span 'a' */ + /* Number of elements selected will be the same */ + new_space->select.num_elem = base_space->select.num_elem; - /* Allocate new span node to append to list */ - if(NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down, span_a->next))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") + /* Set selection type */ + new_space->select.type = H5S_sel_hyper; - /* Set new span 'a' to tmp_span */ - H5S__hyper_recover_span(&recover_a,&span_a,tmp_span); - recover_a = TRUE; +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_project_simple() */ - /* Advance span 'b' */ - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end if */ - /* Span 'a' must be entirely above span 'b' */ - /* AAAAA */ - /* <-----------------------------------> */ - /* BBBBBBBBBB */ - else { - /* Merge/add span 'b' with the merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,span_b->down,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_adjust_s_helper + PURPOSE + Helper routine to adjust offsets in span trees + USAGE + void H5S__hyper_adjust_s_helper(spans, rank, offset, op_info_i, op_gen) + H5S_hyper_span_info_t *spans; IN: Span tree to operate with + unsigned rank; IN: Number of dimensions for span tree + const hssize_t *offset; IN: Offset to subtract + unsigned op_info_i; IN: Index of op info to use + uint64_t op_gen; IN: Operation generation + RETURNS + None + DESCRIPTION + Adjust the location of the spans in a span tree by subtracting an offset + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static void +H5S__hyper_adjust_s_helper(H5S_hyper_span_info_t *spans, unsigned rank, + const hssize_t *offset, unsigned op_info_i, uint64_t op_gen) +{ + FUNC_ENTER_STATIC_NOERR - /* Advance span 'b' */ - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end else */ - } /* end while */ + /* Sanity checks */ + HDassert(spans); + HDassert(offset); - /* Clean up 'a' spans which haven't been added to the list of merged spans */ - if(span_a != NULL && span_b == NULL) { - while(span_a != NULL) { - /* Merge/add all 'a' spans into the merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,span_a->down,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + /* Check if we've already set this span tree */ + if(spans->op_info[op_info_i].op_gen != op_gen) { + H5S_hyper_span_t *span; /* Pointer to current span in span tree */ + unsigned u; /* Local index variable */ - /* Advance to next 'a' span, until all processed */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - } /* end while */ - } /* end if */ + /* Adjust the span tree's low & high bounds */ + for(u = 0; u < rank; u++) { + HDassert((hssize_t)spans->low_bounds[u] >= offset[u]); + spans->low_bounds[u] = (hsize_t)((hssize_t)spans->low_bounds[u] - offset[u]); + spans->high_bounds[u] = (hsize_t)((hssize_t)spans->high_bounds[u] - offset[u]); + } /* end for */ - /* Clean up 'b' spans which haven't been added to the list of merged spans */ - if(span_a == NULL && span_b != NULL) { - while(span_b != NULL) { - /* Merge/add all 'b' spans into the merged spans */ - if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,span_b->down,NULL)==FAIL) - HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + /* Iterate over the spans in tree */ + span = spans->head; + while(span != NULL) { + /* Adjust span offset */ + HDassert((hssize_t)span->low >= *offset); + span->low = (hsize_t)((hssize_t)span->low - *offset); + span->high = (hsize_t)((hssize_t)span->high - *offset); - /* Advance to next 'b' span, until all processed */ - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end while */ - } /* end if */ - } /* end else */ + /* Recursively adjust spans in next dimension down */ + if(span->down != NULL) + H5S__hyper_adjust_s_helper(span->down, rank - 1, offset + 1, op_info_i, op_gen); - /* Set return value */ - ret_value = merged_spans; + /* Advance to next span in this dimension */ + span = span->next; + } /* end while */ -done: - if(ret_value == NULL) - if(merged_spans && H5S__hyper_free_span_info(merged_spans) < 0) - HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, NULL, "failed to release merged hyperslab spans") + /* Set the tree's operation generation */ + spans->op_info[op_info_i].op_gen = op_gen; + } /* end if */ - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_merge_spans_helper() */ + FUNC_LEAVE_NOAPI_VOID +} /* end H5S__hyper_adjust_s_helper() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_merge_spans + H5S__hyper_adjust_s PURPOSE - Merge new hyperslab spans to existing hyperslab selection + Adjust a hyperslab selection by subtracting an offset USAGE - herr_t H5S__hyper_merge_spans(space, new_spans, can_own) - H5S_t *space; IN: Dataspace to add new spans to hyperslab - selection. - H5S_hyper_span_t *new_spans; IN: Span tree of new spans to add to - hyperslab selection - hbool_t can_own; IN: Flag to indicate that it is OK to point - directly to the new spans, instead of - copying them. + herr_t H5S__hyper_adjust_s(space,offset) + H5S_t *space; IN/OUT: Pointer to dataspace to adjust + const hssize_t *offset; IN: Offset to subtract RETURNS - non-negative on success, negative on failure + Non-negative on success, negative on failure DESCRIPTION - Add a set of hyperslab spans to an existing hyperslab selection. The - new spans are required to be non-overlapping with the existing spans in - the dataspace's current hyperslab selection. + Moves a hyperslab selection by subtracting an offset from it. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ static herr_t -H5S__hyper_merge_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans, hbool_t can_own) +H5S__hyper_adjust_s(H5S_t *space, const hssize_t *offset) { - FUNC_ENTER_NOAPI_NOINIT_NOERR + hbool_t non_zero_offset = FALSE; /* Whether any offset is non-zero */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Check args */ + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity checks */ HDassert(space); - HDassert(new_spans); + HDassert(offset); - /* If this is the first span tree in the hyperslab selection, just use it */ - if(space->select.sel_info.hslab->span_lst == NULL) { - if(can_own) - space->select.sel_info.hslab->span_lst = new_spans; - else - space->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(new_spans); - } /* end if */ - else { - H5S_hyper_span_info_t *merged_spans; + /* Check for an all-zero offset vector */ + for(u = 0; u < space->extent.rank; u++) + if(0 != offset[u]) { + non_zero_offset = TRUE; + break; + } /* end if */ - /* Get the merged spans */ - merged_spans = H5S__hyper_merge_spans_helper(space->select.sel_info.hslab->span_lst, new_spans); + /* Only perform operation if the offset is non-zero */ + if(non_zero_offset) { + /* Subtract the offset from the "regular" coordinates, if they exist */ + /* (No need to rebuild the dimension info yet -QAK) */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + for(u = 0; u < space->extent.rank; u++) { + HDassert((hssize_t)space->select.sel_info.hslab->diminfo.opt[u].start >= offset[u]); + space->select.sel_info.hslab->diminfo.opt[u].start = (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.opt[u].start - offset[u]); + + /* Adjust the low & high bounds */ + HDassert((hssize_t)space->select.sel_info.hslab->diminfo.low_bounds[u] >= offset[u]); + space->select.sel_info.hslab->diminfo.low_bounds[u] = (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.low_bounds[u] - offset[u]); + space->select.sel_info.hslab->diminfo.high_bounds[u] = (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.high_bounds[u] - offset[u]); + } /* end for */ + } /* end if */ - /* Sanity checking since we started with some spans, we should still have some after the merge */ - HDassert(merged_spans); + /* Subtract the offset from the span tree coordinates, if they exist */ + if(space->select.sel_info.hslab->span_lst) { + uint64_t op_gen; /* Operation generation value */ - /* Free the previous spans */ - H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst); + /* Acquire an operation generation value for this operation */ + op_gen = H5S__hyper_get_op_gen(); - /* Point to the new merged spans */ - space->select.sel_info.hslab->span_lst = merged_spans; - } /* end else */ + /* Perform the adjustment */ + /* Always use op_info[0] since we own this op_info, so there can be no + * simultaneous operations */ + H5S__hyper_adjust_s_helper(space->select.sel_info.hslab->span_lst, space->extent.rank, offset, 0, op_gen); + } /* end if */ + } - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_merge_spans() */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_adjust_s() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_spans_nelem + H5S_hyper_normalize_offset PURPOSE - Count the number of elements in a span tree + "Normalize" a hyperslab selection by adjusting it's coordinates by the + amount of the selection offset. USAGE - hsize_t H5S__hyper_spans_nelem(spans) - const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of + htri_t H5S_hyper_normalize_offset(space, old_offset) + H5S_t *space; IN/OUT: Pointer to dataspace to move + hssize_t *old_offset; OUT: Pointer to space to store old offset RETURNS - Number of elements in span tree on success; negative on failure + TRUE/FALSE for hyperslab selection, FAIL on error DESCRIPTION - Counts the number of elements described by the spans in a span tree. + Copies the current selection offset into the array provided, then + inverts the selection offset, subtracts the offset from the hyperslab + selection and resets the offset to zero. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static hsize_t -H5S__hyper_spans_nelem(const H5S_hyper_span_info_t *spans) +htri_t +H5S_hyper_normalize_offset(H5S_t *space, hssize_t *old_offset) { - hsize_t ret_value = 0; /* Return value */ + htri_t ret_value = FALSE; /* Return value */ - FUNC_ENTER_STATIC_NOERR + FUNC_ENTER_NOAPI(FAIL) - /* Count the number of elements in the span tree */ - if(spans != NULL) { - const H5S_hyper_span_t *span; /* Hyperslab span */ + /* Sanity checks */ + HDassert(space); + HDassert(old_offset); - span = spans->head; - while(span != NULL) { - /* If there are down spans, multiply the size of this span by the total down span elements */ - if(span->down != NULL) - ret_value += span->nelem * H5S__hyper_spans_nelem(span->down); - /* If there are no down spans, just count the elements in this span */ - else - ret_value += span->nelem; + /* Check for hyperslab selection & offset changed */ + if(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS && space->select.offset_changed) { + unsigned u; /* Local index variable */ - /* Advance to next span */ - span = span->next; - } /* end while */ - } /* end else */ + /* Copy & invert the selection offset */ + for(u = 0; u < space->extent.rank; u++) { + old_offset[u] = space->select.offset[u]; + space->select.offset[u] = -space->select.offset[u]; + } /* end for */ + + /* Call the 'adjust' routine */ + if(H5S__hyper_adjust_s(space, space->select.offset) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection") + + /* Zero out the selection offset */ + HDmemset(space->select.offset, 0, sizeof(hssize_t) * space->extent.rank); + + /* Indicate that the offset was normalized */ + ret_value = TRUE; + } /* end if */ +done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_spans_nelem() */ +} /* end H5S_hyper_normalize_offset() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_make_spans + H5S_hyper_denormalize_offset PURPOSE - Create a span tree + "Denormalize" a hyperslab selection by reverse adjusting it's coordinates + by the amount of the former selection offset. USAGE - H5S_hyper_span_t *H5S__hyper_make_spans(rank, start, stride, count, block) - unsigned rank; IN: # of dimensions of the space - const hsize_t *start; IN: Starting location of the hyperslabs - const hsize_t *stride; IN: Stride from the beginning of one block to - the next - const hsize_t *count; IN: Number of blocks - const hsize_t *block; IN: Size of hyperslab block + herr_t H5S_hyper_denormalize_offset(space, old_offset) + H5S_t *space; IN/OUT: Pointer to dataspace to move + hssize_t *old_offset; IN: Pointer to old offset array RETURNS - Pointer to new span tree on success, NULL on failure + Non-negative on success, negative on failure DESCRIPTION - Generates a new span tree for the hyperslab parameters specified. - Each span tree has a list of the elements spanned in each dimension, with - each span node containing a pointer to the list of spans in the next - dimension down. + Subtracts the old offset from the current selection (canceling out the + effect of the "normalize" routine), then restores the old offset into + the dataspace. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static H5S_hyper_span_info_t * -H5S__hyper_make_spans(unsigned rank, const hsize_t *start, const hsize_t *stride, - const hsize_t *count, const hsize_t *block) +herr_t +H5S_hyper_denormalize_offset(H5S_t *space, const hssize_t *old_offset) { - H5S_hyper_span_info_t *down = NULL; /* Pointer to spans in next dimension down */ - H5S_hyper_span_t *last_span; /* Current position in hyperslab span list */ - H5S_hyper_span_t *head = NULL; /* Head of new hyperslab span list */ - hsize_t stride_iter; /* Iterator over the stride values */ - int i; /* Counters */ - unsigned u; /* Counters */ - H5S_hyper_span_info_t *ret_value = NULL; /* Return value */ - - FUNC_ENTER_STATIC - - /* Check args */ - HDassert(rank > 0); - HDassert(start); - HDassert(stride); - HDassert(count); - HDassert(block); - - /* Start creating spans in fastest changing dimension */ - for(i = (int)(rank - 1); i >= 0; i--) { - - /* Sanity check */ - if(0 == count[i]) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, NULL, "count == 0 is invalid") - - /* Start a new list in this dimension */ - head = NULL; - last_span = NULL; - - /* Generate all the span segments for this dimension */ - for(u = 0, stride_iter = 0; u < count[i]; u++, stride_iter += stride[i]) - { - H5S_hyper_span_t *span; /* New hyperslab span */ - - /* Allocate a span node */ - if(NULL == (span = H5FL_MALLOC(H5S_hyper_span_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") - - /* Set the span's basic information */ - span->low = start[i] + stride_iter; - span->high = span->low + (block[i] - 1); - span->nelem = block[i]; - span->pstride = stride[i]; - span->next = NULL; - - /* Append to the list of spans in this dimension */ - if(head == NULL) - head = span; - else - last_span->next = span; - - /* Move current pointer */ - last_span = span; - - /* Set the information for the next dimension down's spans, if appropriate */ - if(down != NULL) { - span->down = down; - down->count++; /* Increment reference count for shared span */ - } /* end if */ - else - span->down = NULL; - } /* end for */ - - /* Allocate a span info node */ - if(NULL == (down = H5FL_CALLOC(H5S_hyper_span_info_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") - - /* Keep the pointer to the next dimension down's completed list */ - down->head = head; - - } /* end for */ - - /* Indicate that there is a pointer to this tree */ - if(down) - down->count = 1; + herr_t ret_value = SUCCEED; /* Return value */ - /* Success! Return the head of the list in the slowest changing dimension */ - ret_value = down; + FUNC_ENTER_NOAPI(FAIL) -done: - /* cleanup if error (ret_value will be NULL) */ - if(!ret_value) { - if(head || down) { - if(head && down) - if(down->head != head) - down = NULL; + /* Sanity checks */ + HDassert(space); + HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS); - do { - if(down) { - head = down->head; - down = H5FL_FREE(H5S_hyper_span_info_t, down); - } /* end if */ - down = head->down; + /* Call the 'adjust' routine */ + if(H5S__hyper_adjust_s(space, old_offset) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection") - while(head) { - last_span = head->next; - head = H5FL_FREE(H5S_hyper_span_t, head); - head = last_span; - } /* end while */ - } while(down); - } /* end if */ - } /* end if */ + /* Copy the selection offset over */ + H5MM_memcpy(space->select.offset, old_offset, sizeof(hssize_t) * space->extent.rank); +done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_make_spans() */ +} /* end H5S_hyper_denormalize_offset() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_rebuild_helper + H5S__hyper_append_span PURPOSE - Helper routine to rebuild optimized hyperslab information if possible. - (It can be recovered with regular selection) + Create a new span and append to span list USAGE - herr_t H5S__hyper_rebuild_helper(space) - const H5S_hyper_span_t *span; IN: Portion of span tree to check - H5S_hyper_dim_t span_slab[]; OUT: Rebuilt section of hyperslab description - unsigned rank; IN: Current dimension to work on + herr_t H5S__hyper_append_span(span_tree, ndims, low, high, down) + H5S_hyper_span_info_t **span_tree; IN/OUT: Pointer to span tree to append to + unsigned ndims; IN: Number of dimension for span + hsize_t low, high; IN: Low and high bounds for new span node + H5S_hyper_span_info_t *down; IN: Down span tree for new node RETURNS - TRUE/FALSE for hyperslab selection rebuilt + Non-negative on success, negative on failure DESCRIPTION - Examine the span tree for a hyperslab selection and rebuild - the start/stride/count/block information for the selection, if possible. + Create a new span node and append to a span list. Update the previous + span in the list also. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS - To be able to recover the optimized information, the span tree must conform - to span tree able to be generated from a single H5S_SELECT_SET operation. EXAMPLES REVISION LOG - KY, 2005/9/22 --------------------------------------------------------------------------*/ -static hbool_t -H5S__hyper_rebuild_helper(const H5S_hyper_span_t *span, H5S_hyper_dim_t span_slab_info[], - unsigned rank) +static herr_t +H5S__hyper_append_span(H5S_hyper_span_info_t **span_tree, unsigned ndims, + hsize_t low, hsize_t high, H5S_hyper_span_info_t *down) { - hbool_t ret_value = TRUE; /* Return value */ - - FUNC_ENTER_STATIC_NOERR + H5S_hyper_span_t *new_span = NULL; + herr_t ret_value = SUCCEED; /* Return value */ - if(span) { - const H5S_hyper_span_t *prev_span = NULL; /* Previous span in list */ - H5S_hyper_dim_t canon_down_span_slab_info[H5S_MAX_RANK]; - hsize_t curr_stride; - hsize_t curr_block; - hsize_t curr_start; - hsize_t curr_low; - size_t outcount; /* Number of spans encountered in this dimension */ - - /* Initialization */ - curr_stride = 1; - curr_low = 0; - outcount = 0; - - /* Get "canonical" down span information */ - if(span->down) { - HDassert(span->down->head); + FUNC_ENTER_STATIC - /* Go to the next down span and check whether the selection can be rebuilt */ - if(!H5S__hyper_rebuild_helper(span->down->head, span_slab_info, rank - 1)) - HGOTO_DONE(FALSE) + /* Sanity checks */ + HDassert(span_tree); - H5MM_memcpy(canon_down_span_slab_info, span_slab_info, sizeof(H5S_hyper_dim_t) * rank); - } /* end if */ + /* Check for adding first node to merged spans */ + if(*span_tree == NULL) { + /* Allocate new span node to append to list */ + if(NULL == (new_span = H5S__hyper_new_span(low, high, down, NULL))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span") - /* Assign the initial starting point & block size */ - curr_start = span->low; - curr_block = (span->high - span->low) + 1; + /* Make new span the first node in span list */ - /* Loop the spans */ - while(span) { - if(outcount > 0) { - hsize_t next_stride; /* Stride from previous span */ - hsize_t next_block; /* Block size of current span */ + /* Allocate a new span_info node */ + if(NULL == (*span_tree = H5S__hyper_new_span_info(ndims))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span") - /* Check that down spans match current slab info */ - /* (Can skip check if previous span's down pointer is same as current one) */ - if(span->down && (NULL == prev_span || prev_span->down != span->down)) { - H5S_hyper_dim_t *curr_down_span_slab_info; - unsigned u; /* Local index variable */ + /* Set the span tree's basic information */ + (*span_tree)->count = 1; + (*span_tree)->head = new_span; + (*span_tree)->tail = new_span; - HDassert(span->down->head); + /* Set low & high bounds for new span tree */ + (*span_tree)->low_bounds[0] = low; + (*span_tree)->high_bounds[0] = high; + if(down) { + /* Sanity check */ + HDassert(ndims > 1); - /* Go to the next down span and check whether the selection can be rebuilt.*/ - if(!H5S__hyper_rebuild_helper(span->down->head, span_slab_info, rank - 1)) - HGOTO_DONE(FALSE) + H5MM_memcpy(&((*span_tree)->low_bounds[1]), down->low_bounds, sizeof(hsize_t) * (ndims - 1)); + H5MM_memcpy(&((*span_tree)->high_bounds[1]), down->high_bounds, sizeof(hsize_t) * (ndims - 1)); + } /* end if */ + } /* end if */ + /* Merge or append to existing merged spans list */ + else { + htri_t down_cmp = (-1); /* Comparison value for down spans */ - /* Compare the slab information of the adjacent spans in the down span tree. - We have to compare all the sub-tree slab information with the canon_down_span_slab_info.*/ - for(u = 0; u < rank - 1; u++) { - curr_down_span_slab_info = &span_slab_info[u]; - - if(curr_down_span_slab_info->count > 0 && canon_down_span_slab_info[u].count > 0) { - if(curr_down_span_slab_info->start != canon_down_span_slab_info[u].start - || curr_down_span_slab_info->stride != canon_down_span_slab_info[u].stride - || curr_down_span_slab_info->block != canon_down_span_slab_info[u].block - || curr_down_span_slab_info->count != canon_down_span_slab_info[u].count) - HGOTO_DONE(FALSE) - } /* end if */ - else if(!((curr_down_span_slab_info->count == 0) && (canon_down_span_slab_info[u].count == 0))) - HGOTO_DONE(FALSE) - } /* end for */ - } /* end if */ + /* Check if span can just extend the previous merged span */ + if((((*span_tree)->tail->high + 1) == low) && + (down_cmp = H5S__hyper_cmp_spans(down, (*span_tree)->tail->down))) { + /* Extend previous merged span to include new high bound */ + (*span_tree)->tail->high = high; - /* Obtain values for stride and block */ - next_stride = span->low - curr_low; - next_block = (span->high - span->low) + 1; + /* Extend span tree's high bound in this dimension */ + /* (No need to update lower dimensions, since this span shares them with previous span) */ + (*span_tree)->high_bounds[0] = high; + } /* end if */ + else { + H5S_hyper_span_info_t *new_down; /* Down pointer for new span node */ - /* Compare stride and block in this span, to compare stride, - * three spans are needed. Account for the first two spans. - */ - if(next_block != curr_block) - HGOTO_DONE(FALSE) - if(outcount > 1 && curr_stride != next_stride) - HGOTO_DONE(FALSE) + /* Sanity check */ + /* (If down_cmp was set to TRUE above, we won't be in this branch) */ + HDassert(down_cmp != TRUE); - /* Keep the isolated stride to be 1 */ - curr_stride = next_stride; + /* Check if there is actually a down span */ + if(down) { + /* Check if the down spans for the new span node are the same as the previous span node */ + /* (Uses the 'down span comparison' from earlier, if already computed) */ + if(down_cmp < 0 && (down_cmp = H5S__hyper_cmp_spans(down, (*span_tree)->tail->down))) + /* Share the previous span's down span tree */ + new_down = (*span_tree)->tail->down; + else + new_down = down; } /* end if */ + else + new_down = NULL; - /* Keep current starting point */ - curr_low = span->low; - - /* Advance to next span */ - prev_span = span; - span = span->next; - outcount++; - } /* end while */ + /* Allocate new span node to append to list */ + if(NULL == (new_span = H5S__hyper_new_span(low, high, new_down, NULL))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span") + + /* Update the high bounds for current dimension */ + (*span_tree)->high_bounds[0] = high; + + /* Update low & high bounds in lower dimensions, if there are any */ + if(down) { + /* Sanity checks */ + HDassert(ndims > 1); + HDassert(down_cmp >= 0); + + /* Check if we are sharing down spans with a previous node */ + /* (Only need to check for bounds changing if down spans aren't shared) */ + if(down_cmp == FALSE) { + unsigned u; /* Local index variable */ + + /* Loop over lower dimensions, checking & updating low & high bounds */ + for(u = 0; u < (ndims - 1); u++) { + if(down->low_bounds[u] < (*span_tree)->low_bounds[u + 1]) + (*span_tree)->low_bounds[u + 1] = down->low_bounds[u]; + if(down->high_bounds[u] > (*span_tree)->high_bounds[u + 1]) + (*span_tree)->high_bounds[u + 1] = down->high_bounds[u]; + } /* end for */ + } /* end if */ + } /* end if */ - /* Save the span information. */ - span_slab_info[rank - 1].start = curr_start; - span_slab_info[rank - 1].count = outcount; - span_slab_info[rank - 1].block = curr_block; - span_slab_info[rank - 1].stride = curr_stride; - } /* end if */ + /* Append to end of merged spans list */ + (*span_tree)->tail->next = new_span; + (*span_tree)->tail = new_span; + } /* end else */ + } /* end else */ done: + if(ret_value < 0) + if(new_span) + H5S__hyper_free_span(new_span); + FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_rebuild_helper() */ +} /* end H5S__hyper_append_span() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_rebuild + H5S__hyper_clip_spans PURPOSE - Rebuild optimized hyperslab information if possible. - (It can be recovered with regular selection) + Clip a new span tree against the current spans in the hyperslab selection USAGE - hbool_t H5S__hyper_rebuild(space) - const H5S_t *space; IN: Dataspace to check + herr_t H5S__hyper_clip_spans(span_a, span_b, selector, curr_dim, dim_size, + span_a_b_bounds[4], all_clips_bound, + a_not_b, a_and_b, b_not_a) + H5S_hyper_span_t *a_spans; IN: Span tree 'a' to clip with. + H5S_hyper_span_t *b_spans; IN: Span tree 'b' to clip with. + unsigned selector; IN: The parameter deciding which output is needed + (only considering the last three bits ABC: + If A is set, then a_not_b is needed; + If B is set, then a_and_b is needed; + If C is set, then b_not_a is needed; + ) + unsigned ndims; IN: Number of dimensions of this span tree + H5S_hyper_span_t **a_not_b; OUT: Span tree of 'a' hyperslab spans which + doesn't overlap with 'b' hyperslab + spans. + H5S_hyper_span_t **a_and_b; OUT: Span tree of 'a' hyperslab spans which + overlaps with 'b' hyperslab spans. + H5S_hyper_span_t **b_not_a; OUT: Span tree of 'b' hyperslab spans which + doesn't overlap with 'a' hyperslab + spans. RETURNS - TRUE/FALSE for hyperslab selection rebuilt + non-negative on success, negative on failure DESCRIPTION - Examine the span tree for a hyperslab selection and rebuild - the start/stride/count/block information for the selection, if possible. + Clip one span tree ('a') against another span tree ('b'). Creates span + trees for the area defined by the 'a' span tree which does not overlap the + 'b' span tree ("a not b"), the area defined by the overlap of the 'a' + hyperslab span tree and the 'b' span tree ("a and b"), and the area defined + by the 'b' hyperslab span tree which does not overlap the 'a' span + tree ("b not a"). GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS - To be able to recover the optimized information, the span tree must conform - to span tree able to be generated from a single H5S_SELECT_SET operation. EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static hbool_t -H5S__hyper_rebuild(H5S_t *space) +static herr_t +H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans, + unsigned selector, unsigned ndims, + H5S_hyper_span_info_t **a_not_b, H5S_hyper_span_info_t **a_and_b, + H5S_hyper_span_info_t **b_not_a) { - H5S_hyper_dim_t top_span_slab_info[H5S_MAX_RANK]; - unsigned rank, curr_dim; - hbool_t ret_value = TRUE; /* Return value */ + hbool_t need_a_not_b; /* Whether to generate a_not_b list */ + hbool_t need_a_and_b; /* Whether to generate a_and_b list */ + hbool_t need_b_not_a; /* Whether to generate b_not_a list */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_STATIC_NOERR + FUNC_ENTER_STATIC /* Check args */ - HDassert(space); - HDassert(space->select.sel_info.hslab->span_lst); + HDassert(a_spans); + HDassert(b_spans); + HDassert(a_not_b); + HDassert(a_and_b); + HDassert(b_not_a); - /* Check the rank of space */ - rank = space->extent.rank; + /* Set which list(s) to be generated, based on selector */ + need_a_not_b = ((selector & H5S_HYPER_COMPUTE_A_NOT_B) != 0); + need_a_and_b = ((selector & H5S_HYPER_COMPUTE_A_AND_B) != 0); + need_b_not_a = ((selector & H5S_HYPER_COMPUTE_B_NOT_A) != 0); + + /* Check if both span trees are not defined */ + if(a_spans == NULL && b_spans == NULL) { + *a_not_b = NULL; + *a_and_b = NULL; + *b_not_a = NULL; + } /* end if */ + /* If span 'a' is not defined, but 'b' is, copy 'b' and set the other return span trees to empty */ + else if(a_spans == NULL) { + *a_not_b = NULL; + *a_and_b = NULL; + if(need_b_not_a) { + if(NULL == (*b_not_a = H5S__hyper_copy_span(b_spans, ndims))) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree") + } /* end if */ + else + *b_not_a = NULL; + } /* end if */ + /* If span 'b' is not defined, but 'a' is, copy 'a' and set the other return span trees to empty */ + else if(b_spans == NULL) { + *a_and_b = NULL; + *b_not_a = NULL; + if(need_a_not_b) { + if(NULL == (*a_not_b = H5S__hyper_copy_span(a_spans, ndims))) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree") + } /* end if */ + else + *a_not_b = NULL; + } /* end if */ + /* If span 'a' and 'b' are both defined, calculate the proper span trees */ + else { + /* Check if both span trees completely overlap */ + if(H5S__hyper_cmp_spans(a_spans, b_spans)) { + *a_not_b = NULL; + *b_not_a = NULL; + if(need_a_and_b) { + if(NULL == (*a_and_b = H5S__hyper_copy_span(a_spans, ndims))) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree") + } /* end if */ + else + *a_and_b = NULL; + } /* end if */ + else { + H5S_hyper_span_t *span_a; /* Pointer to a node in span tree 'a' */ + H5S_hyper_span_t *span_b; /* Pointer to a node in span tree 'b' */ + hbool_t recover_a, recover_b; /* Flags to indicate when to recover temporary spans */ + + /* Get the pointers to the new and old span lists */ + span_a = a_spans->head; + span_b = b_spans->head; + + /* No spans to recover yet */ + recover_a = recover_b = FALSE; + + /* Work through the list of spans in the new list */ + while(span_a != NULL && span_b != NULL) { + H5S_hyper_span_info_t *down_a_not_b; /* Temporary pointer to a_not_b span tree of down spans for overlapping nodes */ + H5S_hyper_span_info_t *down_a_and_b; /* Temporary pointer to a_and_b span tree of down spans for overlapping nodes */ + H5S_hyper_span_info_t *down_b_not_a; /* Temporary pointer to b_and_a span tree of down spans for overlapping nodes */ + H5S_hyper_span_t *tmp_span; /* Temporary pointer to new span */ + + /* Check if span 'a' is completely before span 'b' */ + /* AAAAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + if(span_a->high < span_b->low) { + /* Copy span 'a' and add to a_not_b list */ + + /* Merge/add span 'a' with/to a_not_b list */ + if(need_a_not_b) + if(H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_a->high, span_a->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + + /* Advance span 'a', leave span 'b' */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next); + } /* end if */ + /* Check if span 'a' overlaps only the lower bound */ + /* of span 'b' , up to the upper bound of span 'b' */ + /* AAAAAAAAAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + else if(span_a->low < span_b->low && (span_a->high >= span_b->low && span_a->high <= span_b->high)) { + /* Split span 'a' into two parts at the low bound of span 'b' */ + + /* Merge/add lower part of span 'a' with/to a_not_b list */ + if(need_a_not_b) + if(H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_b->low - 1, span_a->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + + /* Check for overlaps between upper part of span 'a' and lower part of span 'b' */ + + /* Make certain both spans either have a down span or both don't have one */ + HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL)); + + /* If there are no down spans, just add the overlapping area to the a_and_b list */ + if(span_a->down == NULL) { + /* Merge/add overlapped part with/to a_and_b list */ + if(need_a_and_b) + if(H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_a->high, NULL) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + } /* end if */ + /* If there are down spans, check for the overlap in them and add to each appropriate list */ + else { + /* NULL out the temporary pointers to clipped areas in down spans */ + down_a_not_b = NULL; + down_a_and_b = NULL; + down_b_not_a = NULL; + + /* Check for overlaps in the 'down spans' of span 'a' & 'b' */ + /** Note: since the bound box of remaining dimensions + * has been updated in the following clip function (via + * all_clips_bounds), there's no need updating the bound box + * after each append call in the following codes */ + if(H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1, &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") + + /* Check for additions to the a_not_b list */ + if(down_a_not_b) { + HDassert(need_a_not_b == TRUE); + + /* Merge/add overlapped part with/to a_not_b list */ + if(H5S__hyper_append_span(a_not_b, ndims, span_b->low, span_a->high, down_a_not_b) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_not_b); + } /* end if */ + + /* Check for additions to the a_and_b list */ + if(down_a_and_b) { + HDassert(need_a_and_b == TRUE); + + /* Merge/add overlapped part with/to a_and_b list */ + if(H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_a->high, down_a_and_b) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_and_b); + } /* end if */ + + /* Check for additions to the b_not_a list */ + if(down_b_not_a) { + HDassert(need_b_not_a == TRUE); + + /* Merge/add overlapped part with/to b_not_a list */ + if(H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_a->high, down_b_not_a) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_b_not_a); + } /* end if */ + } /* end else */ + + /* Split off upper part of span 'b' at upper span of span 'a' */ + + /* Check if there is actually an upper part of span 'b' to split off */ + if(span_a->high < span_b->high) { + /* Allocate new span node for upper part of span 'b' */ + if(NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down, span_b->next))) + HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + + /* Advance span 'a' */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next); + + /* Make upper part of span 'b' into new span 'b' */ + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span); + recover_b = TRUE; + } /* end if */ + /* No upper part of span 'b' to split */ + else { + /* Advance both 'a' and 'b' */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next); + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next); + } /* end else */ + } /* end if */ + /* Check if span 'a' overlaps the lower & upper bound */ + /* of span 'b' */ + /* AAAAAAAAAAAAAAAAAAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + else if(span_a->low < span_b->low && span_a->high > span_b->high) { + /* Split off lower part of span 'a' at lower span of span 'b' */ - /* Check whether the slab can be rebuilt. Only regular selection can be rebuilt. If yes, fill in correct values.*/ - if(!H5S__hyper_rebuild_helper(space->select.sel_info.hslab->span_lst->head, top_span_slab_info, rank)) { - HGOTO_DONE(FALSE) - } /* end if */ - else { - H5S_hyper_dim_t *diminfo; - H5S_hyper_dim_t *app_diminfo; + /* Merge/add lower part of span 'a' with/to a_not_b list */ + if(need_a_not_b) + if(H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_b->low - 1, span_a->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - diminfo = space->select.sel_info.hslab->diminfo.opt; - app_diminfo = space->select.sel_info.hslab->diminfo.app; + /* Check for overlaps between middle part of span 'a' and span 'b' */ - for(curr_dim = 0; curr_dim < rank; curr_dim++) { + /* Make certain both spans either have a down span or both don't have one */ + HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL)); - app_diminfo[(rank - curr_dim) - 1].start = diminfo[(rank - curr_dim) - 1].start = top_span_slab_info[curr_dim].start; - app_diminfo[(rank - curr_dim) - 1].stride = diminfo[(rank - curr_dim) - 1].stride = top_span_slab_info[curr_dim].stride; - app_diminfo[(rank - curr_dim) - 1].count = diminfo[(rank - curr_dim) - 1].count = top_span_slab_info[curr_dim].count; - app_diminfo[(rank - curr_dim) - 1].block = diminfo[(rank - curr_dim) - 1].block = top_span_slab_info[curr_dim].block; + /* If there are no down spans, just add the overlapping area to the a_and_b list */ + if(span_a->down == NULL) { + /* Merge/add overlapped part with/to a_and_b list */ + if(need_a_and_b) + if(H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_b->high, NULL) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + } /* end if */ + /* If there are down spans, check for the overlap in them and add to each appropriate list */ + else { + /* NULL out the temporary pointers to clipped areas in down spans */ + down_a_not_b = NULL; + down_a_and_b = NULL; + down_b_not_a = NULL; - } + /* Check for overlaps in the 'down spans' of span 'a' & 'b' */ + if(H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1, &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") - space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES; - } /* end else */ + /* Check for additions to the a_not_b list */ + if(down_a_not_b) { + HDassert(need_a_not_b == TRUE); -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_rebuild() */ + /* Merge/add overlapped part with/to a_not_b list */ + if(H5S__hyper_append_span(a_not_b, ndims, span_b->low, span_b->high, down_a_not_b) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_generate_spans - PURPOSE - Create span tree for a regular hyperslab selection - USAGE - herr_t H5S__hyper_generate_spans(space) - H5S_t *space; IN/OUT: Pointer to dataspace - RETURNS - Non-negative on success, negative on failure - DESCRIPTION - Create a span tree representation of a regular hyperslab selection and - add it to the information for the hyperslab selection. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_generate_spans(H5S_t *space) -{ - hsize_t tmp_start[H5S_MAX_RANK]; /* Temporary start information */ - hsize_t tmp_stride[H5S_MAX_RANK]; /* Temporary stride information */ - hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary count information */ - hsize_t tmp_block[H5S_MAX_RANK]; /* Temporary block information */ - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_not_b); + } /* end if */ - FUNC_ENTER_STATIC + /* Check for additions to the a_and_b list */ + if(down_a_and_b) { + HDassert(need_a_and_b == TRUE); - HDassert(space); - HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS); + /* Merge/add overlapped part with/to a_and_b list */ + if(H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_b->high, down_a_and_b) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - /* Get the diminfo */ - for(u = 0; u < space->extent.rank; u++) { - /* Check for unlimited dimension and return error */ - /* These should be able to be converted to assertions once everything - * that calls this function checks for unlimited selections first - * (especially the new hyperslab API) -NAF */ - if(space->select.sel_info.hslab->diminfo.opt[u].count == H5S_UNLIMITED) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited count") - if(space->select.sel_info.hslab->diminfo.opt[u].block == H5S_UNLIMITED) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited block") + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_and_b); + } /* end if */ - tmp_start[u] = space->select.sel_info.hslab->diminfo.opt[u].start; - tmp_stride[u] = space->select.sel_info.hslab->diminfo.opt[u].stride; - tmp_count[u] = space->select.sel_info.hslab->diminfo.opt[u].count; - tmp_block[u] = space->select.sel_info.hslab->diminfo.opt[u].block; - } /* end for */ + /* Check for additions to the b_not_a list */ + if(down_b_not_a) { + HDassert(need_b_not_a == TRUE); - /* Build the hyperslab information also */ - if(H5S__generate_hyperslab(space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count, tmp_block) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs") + /* Merge/add overlapped part with/to b_not_a list */ + if(H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_b->high, down_b_not_a) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_generate_spans() */ + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_b_not_a); + } /* end if */ + } /* end else */ -#ifndef NEW_HYPERSLAB_API - -/*------------------------------------------------------------------------- - * Function: H5S__generate_hyperlab - * - * Purpose: Generate hyperslab information from H5S_select_hyperslab() - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Tuesday, September 12, 2000 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5S__generate_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[], - const hsize_t stride[], const hsize_t count[], const hsize_t block[]) -{ - H5S_hyper_span_info_t *new_spans = NULL; /* Span tree for new hyperslab */ - H5S_hyper_span_info_t *a_not_b = NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */ - H5S_hyper_span_info_t *a_and_b = NULL; /* Span tree for hyperslab spans in both old and new span trees */ - H5S_hyper_span_info_t *b_not_a = NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */ - herr_t ret_value = SUCCEED; /* Return value */ + /* Split off upper part of span 'a' at upper span of span 'b' */ - FUNC_ENTER_STATIC + /* Allocate new span node for upper part of span 'a' */ + if(NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down, span_a->next))) + HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") - /* Check args */ - HDassert(space); - HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); - HDassert(start); - HDassert(stride); - HDassert(count); - HDassert(block); + /* Make upper part of span 'a' the new span 'a' */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span); + recover_a = TRUE; - /* Generate span tree for new hyperslab information */ - if(NULL == (new_spans = H5S__hyper_make_spans(space->extent.rank, start, stride, count, block))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information") + /* Advance span 'b' */ + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next); + } /* end if */ + /* Check if span 'a' is entirely within span 'b' */ + /* AAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + else if(span_a->low >= span_b->low && span_a->high <= span_b->high) { + /* Split off lower part of span 'b' at lower span of span 'a' */ - /* Generate list of blocks to add/remove based on selection operation */ - if(op == H5S_SELECT_SET) { - /* Add new spans to current selection */ - if(H5S__hyper_merge_spans(space,new_spans,TRUE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + /* Check if there is actually a lower part of span 'b' to split off */ + if(span_a->low > span_b->low) { + /* Merge/add lower part of span 'b' with/to b_not_a list */ + if(need_b_not_a) + if(H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_a->low - 1, span_b->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + } /* end if */ + else { + /* Keep going, nothing to split off */ + } /* end else */ - /* Set the number of elements in current selection */ - space->select.num_elem = H5S__hyper_spans_nelem(new_spans); + /* Check for overlaps between span 'a' and midle of span 'b' */ - /* Indicate that the new_spans are owned */ - new_spans = NULL; - } /* end if */ - else { - hbool_t updated_spans = FALSE; + /* Make certain both spans either have a down span or both don't have one */ + HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL)); - /* Generate lists of spans which overlap and don't overlap */ - if(H5S__hyper_clip_spans(space->select.sel_info.hslab->span_lst,new_spans,&a_not_b,&a_and_b,&b_not_a)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") + /* If there are no down spans, just add the overlapping area to the a_and_b list */ + if(span_a->down == NULL) { + /* Merge/add overlapped part with/to a_and_b list */ + if(need_a_and_b) + if(H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_a->high, NULL) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + } /* end if */ + /* If there are down spans, check for the overlap in them and add to each appropriate list */ + else { + /* NULL out the temporary pointers to clipped areas in down spans */ + down_a_not_b = NULL; + down_a_and_b = NULL; + down_b_not_a = NULL; - switch(op) { - case H5S_SELECT_OR: - /* Add any new spans from b_not_a to current selection */ - if(b_not_a!=NULL) { - if(H5S__hyper_merge_spans(space,b_not_a,FALSE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + /* Check for overlaps in the 'down spans' of span 'a' & 'b' */ + if(H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1, &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") - /* Update the number of elements in current selection */ - space->select.num_elem += H5S__hyper_spans_nelem(b_not_a); + /* Check for additions to the a_not_b list */ + if(down_a_not_b) { + HDassert(need_a_not_b == TRUE); - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* Merge/add overlapped part with/to a_not_b list */ + if(H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_a->high, down_a_not_b) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - case H5S_SELECT_AND: - /* Free the current selection */ - if(H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst)<0) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans") - space->select.sel_info.hslab->span_lst=NULL; + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_not_b); + } /* end if */ - /* Reset the number of items in selection */ - space->select.num_elem=0; + /* Check for additions to the a_and_b list */ + if(down_a_and_b) { + HDassert(need_a_and_b == TRUE); - /* Check if there are any overlapped selections */ - if(a_and_b!=NULL) { - if(H5S__hyper_merge_spans(space,a_and_b,TRUE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + /* Merge/add overlapped part with/to a_and_b list */ + if(H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_a->high, down_a_and_b) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - /* Update the number of elements in current selection */ - space->select.num_elem = H5S__hyper_spans_nelem(a_and_b); + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_and_b); + } /* end if */ - /* Indicate that the a_and_b spans are owned */ - a_and_b=NULL; + /* Check for additions to the b_not_a list */ + if(down_b_not_a) { + HDassert(need_b_not_a == TRUE); - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* Merge/add overlapped part with/to b_not_a list */ + if(H5S__hyper_append_span(b_not_a, ndims, span_a->low, span_a->high, down_b_not_a) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - case H5S_SELECT_XOR: - /* Free the current selection */ - if(H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst)<0) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans") - space->select.sel_info.hslab->span_lst=NULL; + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_b_not_a); + } /* end if */ + } /* end else */ - /* Reset the number of items in selection */ - space->select.num_elem=0; + /* Check if there is actually an upper part of span 'b' to split off */ + if(span_a->high < span_b->high) { + /* Split off upper part of span 'b' at upper span of span 'a' */ - /* Check if there are any non-overlapped selections */ - if(a_not_b!=NULL) { - if(H5S__hyper_merge_spans(space,a_not_b,FALSE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + /* Allocate new span node for upper part of spans 'a' */ + if(NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down, span_b->next))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span") - /* Update the number of elements in current selection */ - space->select.num_elem = H5S__hyper_spans_nelem(a_not_b); + /* And advance span 'a' */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next); - /* Indicate that the spans were updated */ - updated_spans = TRUE; + /* Make upper part of span 'b' the new span 'b' */ + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span); + recover_b = TRUE; + } /* end if */ + else { + /* Advance both span 'a' & span 'b' */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next); + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next); + } /* end else */ } /* end if */ - if(b_not_a!=NULL) { - if(H5S__hyper_merge_spans(space,b_not_a,FALSE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + /* Check if span 'a' overlaps only the upper bound */ + /* of span 'b' */ + /* AAAAAAAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + else if((span_a->low >= span_b->low && span_a->low <= span_b->high) && span_a->high > span_b->high) { + /* Check if there is actually a lower part of span 'b' to split off */ + if(span_a->low > span_b->low) { + /* Split off lower part of span 'b' at lower span of span 'a' */ + + /* Merge/add lower part of span 'b' with/to b_not_a list */ + if(need_b_not_a) + if(H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_a->low - 1, span_b->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + } /* end if */ + else { + /* Keep going, nothing to split off */ + } /* end else */ - /* Update the number of elements in current selection */ - space->select.num_elem += H5S__hyper_spans_nelem(b_not_a); + /* Check for overlaps between lower part of span 'a' and upper part of span 'b' */ - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* Make certain both spans either have a down span or both don't have one */ + HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL)); - case H5S_SELECT_NOTB: - /* Free the current selection */ - if(H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst)<0) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans") - space->select.sel_info.hslab->span_lst=NULL; + /* If there are no down spans, just add the overlapping area to the a_and_b list */ + if(span_a->down == NULL) { + /* Merge/add overlapped part with/to a_and_b list */ + if(need_a_and_b) + if(H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_b->high, NULL) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + } /* end if */ + /* If there are down spans, check for the overlap in them and add to each appropriate list */ + else { + /* NULL out the temporary pointers to clipped areas in down spans */ + down_a_not_b = NULL; + down_a_and_b = NULL; + down_b_not_a = NULL; - /* Reset the number of items in selection */ - space->select.num_elem=0; + /* Check for overlaps in the 'down spans' of span 'a' & 'b' */ + if(H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1, &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") - /* Check if there are any non-overlapped selections */ - if(a_not_b!=NULL) { - if(H5S__hyper_merge_spans(space,a_not_b,TRUE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + /* Check for additions to the a_not_b list */ + if(down_a_not_b) { + HDassert(need_a_not_b == TRUE); - /* Update the number of elements in current selection */ - space->select.num_elem = H5S__hyper_spans_nelem(a_not_b); + /* Merge/add overlapped part with/to a_not_b list */ + if(H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_b->high, down_a_not_b) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - /* Indicate that the a_not_b are owned */ - a_not_b=NULL; + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_not_b); + } /* end if */ - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* Check for additions to the a_and_b list */ + if(down_a_and_b) { + HDassert(need_a_and_b == TRUE); - case H5S_SELECT_NOTA: - /* Free the current selection */ - if(H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst)<0) - HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans") - space->select.sel_info.hslab->span_lst=NULL; + /* Merge/add overlapped part with/to a_and_b list */ + if(H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_b->high, down_a_and_b) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - /* Reset the number of items in selection */ - space->select.num_elem=0; + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_and_b); + } /* end if */ - /* Check if there are any non-overlapped selections */ - if(b_not_a!=NULL) { - if(H5S__hyper_merge_spans(space,b_not_a,TRUE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + /* Check for additions to the b_not_a list */ + if(down_b_not_a) { + HDassert(need_b_not_a == TRUE); - /* Update the number of elements in current selection */ - space->select.num_elem = H5S__hyper_spans_nelem(b_not_a); + /* Merge/add overlapped part with/to b_not_a list */ + if(H5S__hyper_append_span(b_not_a, ndims, span_a->low, span_b->high, down_b_not_a) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - /* Indicate that the b_not_a are owned */ - b_not_a=NULL; + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_b_not_a); + } /* end if */ + } /* end else */ - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* Split off upper part of span 'a' at upper span of span 'b' */ - case H5S_SELECT_NOOP: - case H5S_SELECT_SET: - case H5S_SELECT_APPEND: - case H5S_SELECT_PREPEND: - case H5S_SELECT_INVALID: - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ + /* Allocate new span node for upper part of span 'a' */ + if(NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down, span_a->next))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span") - /* Check if the resulting hyperslab span tree is empty */ - if(space->select.sel_info.hslab->span_lst==NULL) { - H5S_hyper_span_info_t *spans; /* Empty hyperslab span tree */ + /* Make upper part of span 'a' into new span 'a' */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span); + recover_a = TRUE; - /* Sanity check */ - HDassert(space->select.num_elem == 0); + /* Advance span 'b' */ + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next); + } /* end if */ + /* span 'a' must be entirely above span 'b' */ + /* AAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + else { + /* Copy span 'b' and add to b_not_a list */ - /* Allocate a span info node */ - if((spans = H5FL_MALLOC(H5S_hyper_span_info_t))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + /* Merge/add span 'b' with/to b_not_a list */ + if(need_b_not_a) + if(H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_b->high, span_b->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - /* Set the reference count */ - spans->count=1; + /* Advance span 'b', leave span 'a' */ + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next); + } /* end else */ + } /* end while */ - /* Reset the scratch pad space */ - spans->scratch=0; + /* Clean up 'a' spans which haven't been covered yet */ + if(span_a != NULL && span_b == NULL) { + /* Check if need to merge/add 'a' spans with/to a_not_b list */ + if(need_a_not_b) { + /* (This loop, and the similar one below for 'b' spans, + * could be replaced with an optimized routine that quickly + * appended the remaining spans to the 'not' list, but + * until it looks like it's taking a lot of time for an + * important use case, it's been left generic, and similar + * to other code above. -QAK, 2019/02/01) + */ + while(span_a != NULL) { + /* Copy span 'a' and add to a_not_b list */ + if(H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_a->high, span_a->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - /* Set to empty tree */ - spans->head=NULL; + /* Advance to the next 'a' span */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next); + } /* end while */ + } /* end if */ + else { + /* Free the span, if it's generated */ + if(recover_a) + H5S__hyper_free_span(span_a); + } /* end else */ + } /* end if */ + /* Clean up 'b' spans which haven't been covered yet */ + else if(span_a == NULL && span_b != NULL) { + /* Check if need to merge/add 'b' spans with/to b_not_a list */ + if(need_b_not_a) { + /* (This loop, and the similar one above for 'a' spans, + * could be replaced with an optimized routine that quickly + * appended the remaining spans to the 'not' list, but + * until it looks like it's taking a lot of time for an + * important use case, it's been left generic, and similar + * to other code above. -QAK, 2019/02/01) + */ + while(span_b != NULL) { + /* Copy span 'b' and add to b_not_a list */ + if(H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_b->high, span_b->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - /* Set pointer to empty span tree */ - space->select.sel_info.hslab->span_lst=spans; - } /* end if */ - else { - /* Check if we updated the spans */ - if(updated_spans) { - /* Attempt to rebuild "optimized" start/stride/count/block information. - * from resulting hyperslab span tree - */ - H5S__hyper_rebuild(space); + /* Advance to the next 'b' span */ + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next); + } /* end while */ + } /* end if */ + else { + /* Free the span, if it's generated */ + if(recover_b) + H5S__hyper_free_span(span_b); + } /* end else */ } /* end if */ + else + /* Sanity check */ + HDassert(span_a == NULL && span_b == NULL); } /* end else */ } /* end else */ done: - /* Free resources */ - if(a_not_b) - if(H5S__hyper_free_span_info(a_not_b) < 0) - HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans") - if(a_and_b) - if(H5S__hyper_free_span_info(a_and_b) < 0) - HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans") - if(b_not_a) - if(H5S__hyper_free_span_info(b_not_a) < 0) - HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans") - if(new_spans) - if(H5S__hyper_free_span_info(new_spans) < 0) - HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans") - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__generate_hyperslab() */ +} /* end H5S__hyper_clip_spans() */ -/*------------------------------------------------------------------------- - * Function: H5S_select_hyperslab - * - * Purpose: Internal version of H5Sselect_hyperslab(). - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Wednesday, January 10, 2001 - * - *------------------------------------------------------------------------- - */ -herr_t -H5S_select_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[], - const hsize_t *stride, const hsize_t count[], const hsize_t *block) +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_merge_spans_helper + PURPOSE + Merge two hyperslab span tree together + USAGE + H5S_hyper_span_info_t *H5S__hyper_merge_spans_helper(a_spans, b_spans) + H5S_hyper_span_info_t *a_spans; IN: First hyperslab spans to merge + together + H5S_hyper_span_info_t *b_spans; IN: Second hyperslab spans to merge + together + unsigned ndims; IN: Number of dimensions of this span tree + RETURNS + Pointer to span tree containing the merged spans on success, NULL on failure + DESCRIPTION + Merge two sets of hyperslab spans together and return the span tree from + the merged set. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Handles merging span trees that overlap. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static H5S_hyper_span_info_t * +H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans, + unsigned ndims) { - hsize_t int_stride[H5S_MAX_RANK]; /* Internal storage for stride information */ - hsize_t int_count[H5S_MAX_RANK]; /* Internal storage for count information */ - hsize_t int_block[H5S_MAX_RANK]; /* Internal storage for block information */ - const hsize_t *opt_stride; /* Optimized stride information */ - const hsize_t *opt_count; /* Optimized count information */ - const hsize_t *opt_block; /* Optimized block information */ - int unlim_dim = -1; /* Unlimited dimension in selection, of -1 if none */ - unsigned u; /* Local index variable */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI(FAIL) - - /* Check args */ - HDassert(space); - HDassert(start); - HDassert(count); - HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); - - /* Point to the correct stride values */ - if(stride == NULL) - stride = H5S_hyper_ones_g; - - /* Point to the correct block values */ - if(block == NULL) - block = H5S_hyper_ones_g; - - /* Check new selection */ - for(u = 0; u < space->extent.rank; u++) { - /* Check for overlapping hyperslab blocks in new selection. */ - if(count[u] > 1 && stride[u] < block[u]) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab blocks overlap") - - /* Detect zero-sized hyperslabs in new selection */ - if(count[u] == 0 || block[u] == 0) { - switch(op) { - case H5S_SELECT_SET: /* Select "set" operation */ - case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ - case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */ - /* Convert to "none" selection */ - if(H5S_select_none(space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection") - HGOTO_DONE(SUCCEED); - - case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ - case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */ - case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */ - HGOTO_DONE(SUCCEED); /* Selection stays same */ - - case H5S_SELECT_NOOP: - case H5S_SELECT_APPEND: - case H5S_SELECT_PREPEND: - case H5S_SELECT_INVALID: - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ - } /* end if */ - - /* Check for unlimited dimension */ - if((count[u] == H5S_UNLIMITED) || (block[u] == H5S_UNLIMITED)) { - if(unlim_dim >= 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot have more than one unlimited dimension in selection") - else { - if(count[u] == block[u]) /* Both are H5S_UNLIMITED */ - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "count and block cannot both be unlimited") - unlim_dim = (int)u; - } /* end else */ - } /* end if */ - } /* end for */ - - /* Optimize hyperslab parameters to merge contiguous blocks, etc. */ - if(stride == H5S_hyper_ones_g && block == H5S_hyper_ones_g) { - /* Point to existing arrays */ - opt_stride = H5S_hyper_ones_g; - opt_count = H5S_hyper_ones_g; - opt_block = count; - } /* end if */ - else { - /* Point to local arrays */ - opt_stride = int_stride; - opt_count = int_count; - opt_block = int_block; - for(u = 0; u < space->extent.rank; u++) { - /* contiguous hyperslabs have the block size equal to the stride */ - if((stride[u] == block[u]) && (count[u] != H5S_UNLIMITED)) { - int_count[u] = 1; - int_stride[u] = 1; - if(block[u] == 1) - int_block[u] = count[u]; - else - int_block[u] = block[u] * count[u]; - } /* end if */ - else { - if(count[u] == 1) - int_stride[u] = 1; - else { - HDassert((stride[u] > block[u]) || - ((stride[u] == block[u]) && (count[u] == H5S_UNLIMITED))); - int_stride[u] = stride[u]; - } /* end else */ - int_count[u] = count[u]; - int_block[u] = block[u]; - } /* end else */ - } /* end for */ - } /* end else */ + H5S_hyper_span_info_t *merged_spans = NULL; /* Pointer to the merged span tree */ + H5S_hyper_span_info_t *ret_value = NULL; /* Return value */ - /* Check for operating on unlimited selection */ - if((H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS) - && (space->select.sel_info.hslab->unlim_dim >= 0) - && (op != H5S_SELECT_SET)) { - /* Check for invalid operation */ - if(unlim_dim >= 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot modify unlimited selection with another unlimited selection") - if(!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTA))) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation on unlimited selection") - HDassert(space->select.sel_info.hslab->diminfo_valid); + FUNC_ENTER_STATIC - /* Clip unlimited selection to include new selection */ - if(H5S_hyper_clip_unlim(space, - start[space->select.sel_info.hslab->unlim_dim] - + ((opt_count[space->select.sel_info.hslab->unlim_dim] - (hsize_t)1) - * opt_stride[space->select.sel_info.hslab->unlim_dim]) - + opt_block[space->select.sel_info.hslab->unlim_dim]) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection") + /* Make certain both 'a' & 'b' spans have down span trees or neither does */ + HDassert((a_spans != NULL && b_spans != NULL) || (a_spans == NULL && b_spans == NULL)); - /* If an empty space was returned it must be "none" */ - HDassert((space->select.num_elem > (hsize_t)0) || (space->select.type->type == H5S_SEL_NONE)); + /* Check if the span trees for the 'a' span and the 'b' span are the same */ + if(H5S__hyper_cmp_spans(a_spans, b_spans)) { + if(a_spans == NULL) + merged_spans = NULL; + else { + /* Copy one of the span trees to return */ + if(NULL == (merged_spans = H5S__hyper_copy_span(a_spans, ndims))) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree") + } /* end else */ } /* end if */ + else { + H5S_hyper_span_t *span_a; /* Pointer to current span 'a' working on */ + H5S_hyper_span_t *span_b; /* Pointer to current span 'b' working on */ + hbool_t recover_a, recover_b; /* Flags to indicate when to recover temporary spans */ - /* Fixup operation for non-hyperslab selections */ - switch(H5S_GET_SELECT_TYPE(space)) { - case H5S_SEL_NONE: /* No elements selected in dataspace */ - switch(op) { - case H5S_SELECT_SET: /* Select "set" operation */ - /* Change "none" selection to hyperslab selection */ - break; + /* Get the pointers to the 'a' and 'b' span lists */ + span_a = a_spans->head; + span_b = b_spans->head; - case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ - case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */ - case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */ - op = H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */ - break; + /* No spans to recover yet */ + recover_a = recover_b = FALSE; - case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ - case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */ - HGOTO_DONE(SUCCEED); /* Selection stays "none" */ + /* Work through the list of spans in the new list */ + while(span_a != NULL && span_b != NULL) { + H5S_hyper_span_info_t *tmp_spans; /* Pointer to temporary new span tree */ + H5S_hyper_span_t *tmp_span; /* Pointer to temporary new span */ - case H5S_SELECT_NOOP: - case H5S_SELECT_APPEND: - case H5S_SELECT_PREPEND: - case H5S_SELECT_INVALID: - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ - break; + /* Check if the 'a' span is completely before 'b' span */ + /* AAAAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + if(span_a->high < span_b->low) { + /* Merge/add span 'a' with/to the merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, span_a->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - case H5S_SEL_ALL: /* All elements selected in dataspace */ - switch(op) { - case H5S_SELECT_SET: /* Select "set" operation */ - /* Change "all" selection to hyperslab selection */ - break; + /* Advance span 'a' */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next); + } /* end if */ + /* Check if span 'a' overlaps only the lower bound */ + /* of span 'b', up to the upper bound of span 'b' */ + /* AAAAAAAAAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + else if(span_a->low < span_b->low && (span_a->high >= span_b->low && span_a->high <= span_b->high)) { + /* Check if span 'a' and span 'b' down spans are equal */ + if(H5S__hyper_cmp_spans(span_a->down, span_b->down)) { + /* Merge/add copy of span 'a' with/to merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, span_a->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + } /* end if */ + else { + /* Merge/add lower part of span 'a' with/to merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->low - 1, span_a->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ - HGOTO_DONE(SUCCEED); /* Selection stays "all" */ + /* Get merged span tree for overlapped section */ + tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1); - case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ - op = H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */ - break; + /* Merge/add overlapped section to merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->high, tmp_spans) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */ - case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */ - /* Convert current "all" selection to "real" hyperslab selection */ - /* Then allow operation to proceed */ - { - const hsize_t *tmp_start; /* Temporary start information */ - const hsize_t *tmp_stride; /* Temporary stride information */ - const hsize_t *tmp_count; /* Temporary count information */ - const hsize_t *tmp_block; /* Temporary block information */ + /* Release merged span tree for overlapped section */ + H5S__hyper_free_span_info(tmp_spans); + } /* end else */ - /* Set up temporary information for the dimensions */ - tmp_start = H5S_hyper_zeros_g; - tmp_stride = tmp_count = H5S_hyper_ones_g; - tmp_block = space->extent.size; + /* Check if there is an upper part of span 'b' */ + if(span_a->high < span_b->high) { + /* Copy upper part of span 'b' as new span 'b' */ - /* Convert to hyperslab selection */ - if(H5S_select_hyperslab(space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count, tmp_block) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection") - } /* end case */ - break; + /* Allocate new span node to append to list */ + if(NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down, span_b->next))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") - case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */ - /* Convert to "none" selection */ - if(H5S_select_none(space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection") - HGOTO_DONE(SUCCEED); + /* Advance span 'a' */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next); - case H5S_SELECT_NOOP: - case H5S_SELECT_APPEND: - case H5S_SELECT_PREPEND: - case H5S_SELECT_INVALID: - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ - break; + /* Set new span 'b' to tmp_span */ + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span); + recover_b = TRUE; + } /* end if */ + else { + /* Advance both span 'a' & 'b' */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next); + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next); + } /* end else */ + } /* end if */ + /* Check if span 'a' overlaps the lower & upper bound */ + /* of span 'b' */ + /* AAAAAAAAAAAAAAAAAAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + else if(span_a->low < span_b->low && span_a->high > span_b->high) { + /* Check if span 'a' and span 'b' down spans are equal */ + if(H5S__hyper_cmp_spans(span_a->down, span_b->down)) { + /* Merge/add copy of lower & middle parts of span 'a' to merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->high, span_a->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + } /* end if */ + else { + /* Merge/add lower part of span 'a' to merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->low - 1, span_a->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - case H5S_SEL_HYPERSLABS: - /* Hyperslab operation on hyperslab selection, OK */ - break; + /* Get merged span tree for overlapped section */ + tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1); - case H5S_SEL_POINTS: /* Can't combine hyperslab operations and point selections currently */ - if(op == H5S_SELECT_SET) /* Allow only "set" operation to proceed */ - break; - /* Else fall through to error */ - H5_ATTR_FALLTHROUGH + /* Merge/add overlapped section to merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, tmp_spans) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - case H5S_SEL_ERROR: - case H5S_SEL_N: - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ + /* Release merged span tree for overlapped section */ + H5S__hyper_free_span_info(tmp_spans); + } /* end else */ - if(op == H5S_SELECT_SET) { - /* If we are setting a new selection, remove current selection first */ - if(H5S_SELECT_RELEASE(space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") + /* Copy upper part of span 'a' as new span 'a' (remember to free) */ - /* Allocate space for the hyperslab selection information */ - if(NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info") + /* Allocate new span node to append to list */ + if(NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down, span_a->next))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") - /* Save the diminfo */ - space->select.num_elem = 1; - for(u = 0; u < space->extent.rank; u++) { - space->select.sel_info.hslab->diminfo.app[u].start = start[u]; - space->select.sel_info.hslab->diminfo.app[u].stride = stride[u]; - space->select.sel_info.hslab->diminfo.app[u].count = count[u]; - space->select.sel_info.hslab->diminfo.app[u].block = block[u]; + /* Set new span 'a' to tmp_span */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span); + recover_a = TRUE; + + /* Advance span 'b' */ + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next); + } /* end if */ + /* Check if span 'a' is entirely within span 'b' */ + /* AAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + else if(span_a->low >= span_b->low && span_a->high <= span_b->high) { + /* Check if span 'a' and span 'b' down spans are equal */ + if(H5S__hyper_cmp_spans(span_a->down, span_b->down)) { + /* Merge/add copy of lower & middle parts of span 'b' to merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->high, span_a->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + } /* end if */ + else { + /* Check if there is a lower part of span 'b' */ + if(span_a->low > span_b->low) { + /* Merge/add lower part of span 'b' to merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->low - 1, span_b->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + } /* end if */ + else { + /* No lower part of span 'b' , keep going... */ + } /* end else */ - space->select.sel_info.hslab->diminfo.opt[u].start = start[u]; - space->select.sel_info.hslab->diminfo.opt[u].stride = opt_stride[u]; - space->select.sel_info.hslab->diminfo.opt[u].count = opt_count[u]; - space->select.sel_info.hslab->diminfo.opt[u].block = opt_block[u]; + /* Get merged span tree for overlapped section */ + tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1); - space->select.num_elem *= (opt_count[u] * opt_block[u]); - } /* end for */ + /* Merge/add overlapped section to merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, tmp_spans) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - /* Save unlim_dim */ - space->select.sel_info.hslab->unlim_dim = unlim_dim; + /* Release merged span tree for overlapped section */ + H5S__hyper_free_span_info(tmp_spans); + } /* end else */ - /* Indicate that the dimension information is valid */ - space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES; + /* Check if there is an upper part of span 'b' */ + if(span_a->high < span_b->high) { + /* Copy upper part of span 'b' as new span 'b' (remember to free) */ - /* Indicate that there's no slab information */ - space->select.sel_info.hslab->span_lst = NULL; + /* Allocate new span node to append to list */ + if(NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down, span_b->next))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") - /* Handle unlimited selections */ - if(unlim_dim >= 0) { - /* Calculate num_elem_non_unlim */ - space->select.sel_info.hslab->num_elem_non_unlim = (hsize_t)1; - for(u = 0; u < space->extent.rank; u++) - if((int)u != unlim_dim) - space->select.sel_info.hslab->num_elem_non_unlim *= (opt_count[u] * opt_block[u]); + /* Advance span 'a' */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next); + + /* Set new span 'b' to tmp_span */ + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span); + recover_b = TRUE; + } /* end if */ + else { + /* Advance both spans */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next); + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next); + } /* end else */ + } /* end if */ + /* Check if span 'a' overlaps only the upper bound */ + /* of span 'b' */ + /* AAAAAAAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + else if((span_a->low >= span_b->low && span_a->low <= span_b->high) && span_a->high > span_b->high) { + /* Check if span 'a' and span 'b' down spans are equal */ + if(H5S__hyper_cmp_spans(span_a->down, span_b->down)) { + /* Merge/add copy of span 'b' to merged spans if so */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, span_b->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + } /* end if */ + else { + /* Check if there is a lower part of span 'b' */ + if(span_a->low > span_b->low) { + /* Merge/add lower part of span 'b' to merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->low - 1, span_b->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + } /* end if */ + else { + /* No lower part of span 'b' , keep going... */ + } /* end else */ + + /* Get merged span tree for overlapped section */ + tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1); + + /* Merge/add overlapped section to merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->high, tmp_spans) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + + /* Release merged span tree for overlapped section */ + H5S__hyper_free_span_info(tmp_spans); + } /* end else */ - /* Set num_elem */ - if(space->select.num_elem != (hsize_t)0) - space->select.num_elem = H5S_UNLIMITED; - } /* end if */ + /* Copy upper part of span 'a' as new span 'a' */ - /* Set selection type */ - space->select.type = H5S_sel_hyper; - } /* end if */ - else if(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA) { - /* Sanity check */ - HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS); + /* Allocate new span node to append to list */ + if(NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down, span_a->next))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") - /* Handle unlimited selections */ - if(unlim_dim >= 0) { - hsize_t bounds_start[H5S_MAX_RANK]; - hsize_t bounds_end[H5S_MAX_RANK]; - hsize_t tmp_count = opt_count[unlim_dim]; - hsize_t tmp_block = opt_block[unlim_dim]; + /* Set new span 'a' to tmp_span */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span); + recover_a = TRUE; - /* Check for invalid operation */ - if(space->select.sel_info.hslab->unlim_dim >= 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot modify unlimited selection with another unlimited selection") - if(!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTB))) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation with unlimited selection") + /* Advance span 'b' */ + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next); + } /* end if */ + /* Span 'a' must be entirely above span 'b' */ + /* AAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + else { + /* Merge/add span 'b' with the merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, span_b->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - /* Get bounds of existing selection */ - if(H5S__hyper_bounds(space, bounds_start, bounds_end) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds") + /* Advance span 'b' */ + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next); + } /* end else */ + } /* end while */ - /* Patch count and block to remove unlimited and include the - * existing selection. - */ - H5S__hyper_get_clip_diminfo(start[unlim_dim], opt_stride[unlim_dim], &tmp_count, &tmp_block, bounds_end[unlim_dim] + (hsize_t)1); - HDassert((tmp_count == 1) || (opt_count != H5S_hyper_ones_g)); - HDassert((tmp_block == 1) || (opt_block != H5S_hyper_ones_g)); - if(opt_count != H5S_hyper_ones_g) { - HDassert(opt_count == int_count); - int_count[unlim_dim] = tmp_count; - } /* end if */ - if(opt_block != H5S_hyper_ones_g) { - HDassert(opt_block == int_block); - int_block[unlim_dim] = tmp_block; - } /* end if */ - } /* end if */ + /* Clean up 'a' spans which haven't been added to the list of merged spans */ + if(span_a != NULL && span_b == NULL) { + while(span_a != NULL) { + /* Merge/add all 'a' spans into the merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, span_a->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - /* Check if there's no hyperslab span information currently */ - if(NULL == space->select.sel_info.hslab->span_lst) - if(H5S__hyper_generate_spans(space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") + /* Advance to next 'a' span, until all processed */ + H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next); + } /* end while */ + } /* end if */ - /* Indicate that the regular dimensions are no longer valid */ - space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; + /* Clean up 'b' spans which haven't been added to the list of merged spans */ + if(span_a == NULL && span_b != NULL) { + while(span_b != NULL) { + /* Merge/add all 'b' spans into the merged spans */ + if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, span_b->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - /* Set selection type */ - /* (Could be overridden by resetting selection to 'none', below) */ - space->select.type = H5S_sel_hyper; + /* Advance to next 'b' span, until all processed */ + H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next); + } /* end while */ + } /* end if */ + } /* end else */ - /* Add in the new hyperslab information */ - if(H5S__generate_hyperslab(space, op, start, opt_stride, opt_count, opt_block) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs") - } /* end if */ - else - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + /* Set return value */ + ret_value = merged_spans; done: + if(ret_value == NULL) + if(merged_spans) + H5S__hyper_free_span_info(merged_spans); + FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_select_hyperslab() */ +} /* end H5S__hyper_merge_spans_helper() */ /*-------------------------------------------------------------------------- NAME - H5Sselect_hyperslab + H5S__hyper_merge_spans PURPOSE - Specify a hyperslab to combine with the current hyperslab selection + Merge new hyperslab spans to existing hyperslab selection USAGE - herr_t H5Sselect_hyperslab(dsid, op, start, stride, count, block) - hid_t dsid; IN: Dataspace ID of selection to modify - H5S_seloper_t op; IN: Operation to perform on current selection - const hsize_t *start; IN: Offset of start of hyperslab - const hsize_t *stride; IN: Hyperslab stride - const hsize_t *count; IN: Number of blocks included in hyperslab - const hsize_t *block; IN: Size of block in hyperslab + herr_t H5S__hyper_merge_spans(space, new_spans, can_own) + H5S_t *space; IN: Dataspace to add new spans to hyperslab + selection. + H5S_hyper_span_t *new_spans; IN: Span tree of new spans to add to + hyperslab selection RETURNS - Non-negative on success/Negative on failure + non-negative on success, negative on failure DESCRIPTION - Combines a hyperslab selection with the current selection for a dataspace. - If the current selection is not a hyperslab, it is freed and the hyperslab - parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a - selection composing the entire current extent). If STRIDE or BLOCK is - NULL, they are assumed to be set to all '1'. + Add a set of hyperslab spans to an existing hyperslab selection. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -herr_t -H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[], - const hsize_t stride[], const hsize_t count[], const hsize_t block[]) -{ - H5S_t *space; /* Dataspace to modify selection of */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_API(FAIL) - H5TRACE6("e", "iSs*h*h*h*h", space_id, op, start, stride, count, block); - - /* Check args */ - if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") - if(H5S_SCALAR == H5S_GET_EXTENT_TYPE(space)) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_SCALAR space") - if(H5S_NULL == H5S_GET_EXTENT_TYPE(space)) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_NULL space") - if(start == NULL || count == NULL) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified") - if(!(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID)) - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - if(stride != NULL) { - unsigned u; /* Local index variable */ - - /* Check for 0-sized strides */ - for(u = 0; u < space->extent.rank; u++) - if(stride[u] == 0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid stride==0 value") - } /* end if */ - - if(H5S_select_hyperslab(space, op, start, stride, count, block) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection") - -done: - FUNC_LEAVE_API(ret_value) -} /* end H5Sselect_hyperslab() */ -#else /* NEW_HYPERSLAB_API */ /* Works */ - -/*------------------------------------------------------------------------- - * Function: H5S_operate_hyperslab - * - * Purpose: Combines two hyperslabs with an operation, putting the - * result into a third hyperslab selection - * - * Return: non-negative on success/NULL on failure - * - * Programmer: Quincey Koziol - * Tuesday, October 30, 2001 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ static herr_t -H5S_operate_hyperslab (H5S_t *result, H5S_hyper_span_info_t *spans1, H5S_seloper_t op, H5S_hyper_span_info_t *spans2, - hbool_t can_own_span2, hbool_t *span2_owned) +H5S__hyper_merge_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans) { - H5S_hyper_span_info_t *a_not_b=NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */ - H5S_hyper_span_info_t *a_and_b=NULL; /* Span tree for hyperslab spans in both old and new span trees */ - H5S_hyper_span_info_t *b_not_a=NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */ - herr_t ret_value=SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT - - /* Check args */ - HDassert(result); - HDassert(spans2); - HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + herr_t ret_value = SUCCEED; /* Return value */ - /* Just copy the selection from spans2 if we are setting the selection */ - /* ('space1' to 'result' aliasing happens at the next layer up) */ - if(op==H5S_SELECT_SET) { - if(H5S__hyper_merge_spans(result,spans2,can_own_span2)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + FUNC_ENTER_STATIC - /* Update the number of elements in current selection */ - result->select.num_elem = H5S__hyper_spans_nelem(spans2); + /* Sanity checks */ + HDassert(space); + HDassert(new_spans); - /* Indicate that we took ownership of span2, if allowed */ - if(can_own_span2) - *span2_owned=TRUE; + /* If this is the first span tree in the hyperslab selection, just use it */ + if(space->select.sel_info.hslab->span_lst == NULL) { + space->select.sel_info.hslab->span_lst = new_spans; + space->select.sel_info.hslab->span_lst->count++; } /* end if */ else { - hbool_t updated_spans = FALSE; /* Whether the spans in the selection were modified */ - - HDassert(spans1); - - /* Generate lists of spans which overlap and don't overlap */ - if(H5S__hyper_clip_spans(spans1,spans2,&a_not_b,&a_and_b,&b_not_a)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") - - /* Switch on the operation */ - switch(op) { - case H5S_SELECT_OR: - /* Copy spans from spans1 to current selection */ - if(spans1!=NULL) { - if(H5S__hyper_merge_spans(result,spans1,FALSE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") - - /* Update the number of elements in current selection */ - result->select.num_elem = H5S__hyper_spans_nelem(spans1); - } /* end if */ - - /* Add any new spans from spans2 to current selection */ - if(b_not_a!=NULL) { - if(H5S__hyper_merge_spans(result,b_not_a,FALSE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + H5S_hyper_span_info_t *merged_spans; - /* Update the number of elements in current selection */ - result->select.num_elem += H5S__hyper_spans_nelem(b_not_a); + /* Get the merged spans */ + if(NULL == (merged_spans = H5S__hyper_merge_spans_helper(space->select.sel_info.hslab->span_lst, new_spans, space->extent.rank))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTMERGE, FAIL, "can't merge hyperslab spans") - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* Free the previous spans */ + H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst); - case H5S_SELECT_AND: - /* Check if there are any overlapped selections */ - if(a_and_b!=NULL) { - if(H5S__hyper_merge_spans(result,a_and_b,TRUE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + /* Point to the new merged spans */ + space->select.sel_info.hslab->span_lst = merged_spans; + } /* end else */ - /* Update the number of elements in current selection */ - result->select.num_elem = H5S__hyper_spans_nelem(a_and_b); +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_merge_spans() */ - /* Indicate that the result owns the a_and_b spans */ - a_and_b=NULL; + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_spans_nelem_helper + PURPOSE + Count the number of elements in a span tree + USAGE + hsize_t H5S__hyper_spans_nelem_helper(spans, op_info_i, op_gen) + const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of + unsigned op_info_i; IN: Index of op info to use + uint64_t op_gen; IN: Operation generation + RETURNS + Number of elements in span tree on success; negative on failure + DESCRIPTION + Counts the number of elements described by the spans in a span tree. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static hsize_t +H5S__hyper_spans_nelem_helper(H5S_hyper_span_info_t *spans, unsigned op_info_i, + uint64_t op_gen) +{ + hsize_t ret_value = 0; /* Return value */ - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + FUNC_ENTER_STATIC_NOERR - case H5S_SELECT_XOR: - /* Check if there are any non-overlapped selections */ - if(a_not_b!=NULL) { - if(H5S__hyper_merge_spans(result,a_not_b,FALSE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + /* Sanity check */ + HDassert(spans); - /* Update the number of elements in current selection */ - result->select.num_elem = H5S__hyper_spans_nelem(a_not_b); + /* Check if the span tree was already counted */ + if(spans->op_info[op_info_i].op_gen == op_gen) + /* Just return the # of elements in the already counted span tree */ + ret_value = spans->op_info[op_info_i].u.nelmts; + else { /* Count the number of elements in the span tree */ + const H5S_hyper_span_t *span; /* Hyperslab span */ - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - if(b_not_a!=NULL) { - if(H5S__hyper_merge_spans(result,b_not_a,FALSE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + span = spans->head; + if(NULL == span->down) { + while(span != NULL) { + /* Compute # of elements covered */ + ret_value += (span->high - span->low) + 1; - /* Update the number of elements in current selection */ - result->select.num_elem += H5S__hyper_spans_nelem(b_not_a); + /* Advance to next span */ + span = span->next; + } /* end while */ + } /* end if */ + else { + while(span != NULL) { + hsize_t nelmts; /* # of elements covered by current span */ - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* Compute # of elements covered */ + nelmts = (span->high - span->low) + 1; - case H5S_SELECT_NOTB: - /* Check if there are any non-overlapped selections */ - if(a_not_b!=NULL) { - if(H5S__hyper_merge_spans(result,a_not_b,TRUE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + /* Multiply the size of this span by the total down span elements */ + ret_value += nelmts * H5S__hyper_spans_nelem_helper(span->down, op_info_i, op_gen); - /* Update the number of elements in current selection */ - result->select.num_elem = H5S__hyper_spans_nelem(a_not_b); + /* Advance to next span */ + span = span->next; + } /* end while */ + } /* end else */ - /* Indicate that the result owns the a_not_b spans */ - a_not_b=NULL; + /* Set the operation generation for this span tree, to avoid re-computing */ + spans->op_info[op_info_i].op_gen = op_gen; - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* Hold a copy of the # of elements */ + spans->op_info[op_info_i].u.nelmts = ret_value; + } /* end else */ - case H5S_SELECT_NOTA: - /* Check if there are any non-overlapped selections */ - if(b_not_a!=NULL) { - if(H5S__hyper_merge_spans(result,b_not_a,TRUE)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_spans_nelem_helper() */ - /* Update the number of elements in current selection */ - result->select.num_elem = H5S__hyper_spans_nelem(b_not_a); + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_spans_nelem + PURPOSE + Count the number of elements in a span tree + USAGE + hsize_t H5S__hyper_spans_nelem(spans) + const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of + RETURNS + Number of elements in span tree on success; negative on failure + DESCRIPTION + Counts the number of elements described by the spans in a span tree. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static hsize_t +H5S__hyper_spans_nelem(H5S_hyper_span_info_t *spans) +{ + uint64_t op_gen; /* Operation generation value */ + hsize_t ret_value = 0; /* Return value */ - /* Indicate that the result owns the b_not_a spans */ - b_not_a=NULL; + FUNC_ENTER_STATIC_NOERR - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* Sanity check */ + HDassert(spans); - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ + /* Acquire an operation generation value for this operation */ + op_gen = H5S__hyper_get_op_gen(); - /* Free the hyperslab trees generated from the clipping algorithm */ - if(a_not_b) - H5S__hyper_free_span_info(a_not_b); - if(a_and_b) - H5S__hyper_free_span_info(a_and_b); - if(b_not_a) - H5S__hyper_free_span_info(b_not_a); + /* Count the number of elements in the span tree */ + /* Always use op_info[0] since we own this op_info, so there can be no + * simultaneous operations */ + ret_value = H5S__hyper_spans_nelem_helper(spans, 0, op_gen); - /* Check if the resulting hyperslab span tree is empty */ - if(result->select.sel_info.hslab->span_lst==NULL) { - H5S_hyper_span_info_t *spans; /* Empty hyperslab span tree */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_spans_nelem() */ - /* Sanity check */ - HDassert(result->select.num_elem == 0); - /* Allocate a span info node */ - if((spans = H5FL_MALLOC(H5S_hyper_span_info_t))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span") +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_add_disjoint_spans + PURPOSE + Add new hyperslab spans to existing hyperslab selection in the case the + new hyperslab spans don't overlap with the existing hyperslab selection + USAGE + herr_t H5S__hyper_add_disjoint_spans(space, new_spans) + H5S_t *space; IN: Dataspace to add new spans to hyperslab + selection. + H5S_hyper_span_t *new_spans; IN: Span tree of new spans to add to + hyperslab selection + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Add a set of hyperslab spans to an existing hyperslab selection. The + new spans are required not to overlap with the existing spans in the + dataspace's current hyperslab selection in terms of bound box. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_add_disjoint_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans) +{ + herr_t ret_value = SUCCEED; /* Return value */ - /* Set the reference count */ - spans->count=1; + FUNC_ENTER_STATIC - /* Reset the scratch pad space */ - spans->scratch=0; + /* Check args */ + HDassert(space); + HDassert(new_spans); - /* Set to empty tree */ - spans->head=NULL; + /* Update the number of elements in the selection */ + space->select.num_elem += H5S__hyper_spans_nelem(new_spans); - /* Set pointer to empty span tree */ - result->select.sel_info.hslab->span_lst=spans; - } /* end if */ - else { - /* Check if we updated the spans */ - if(updated_spans) { - /* Attempt to rebuild "optimized" start/stride/count/block information. - * from resulting hyperslab span tree - */ - H5S__hyper_rebuild(result); - } /* end if */ - } /* end else */ - } /* end else */ + /* Add the new spans to the existing selection in the dataspace */ + if(H5S__hyper_merge_spans(space, new_spans) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't merge hyperslabs") + + /* Free the memory space for new spans */ + H5S__hyper_free_span_info(new_spans); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_operate_hyperslab() */ +} /* end H5S__hyper_add_disjoint_spans */ -/*------------------------------------------------------------------------- - * Function: H5S_generate_hyperlab - * - * Purpose: Generate hyperslab information from H5S_select_hyperslab() - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol (split from HS_select_hyperslab()). - * Tuesday, September 12, 2000 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static herr_t -H5S__generate_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[], - const hsize_t stride[], const hsize_t count[], const hsize_t block[]) +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_make_spans + PURPOSE + Create a span tree + USAGE + H5S_hyper_span_t *H5S__hyper_make_spans(rank, start, stride, count, block) + unsigned rank; IN: # of dimensions of the space + const hsize_t *start; IN: Starting location of the hyperslabs + const hsize_t *stride; IN: Stride from the beginning of one block to + the next + const hsize_t *count; IN: Number of blocks + const hsize_t *block; IN: Size of hyperslab block + RETURNS + Pointer to new span tree on success, NULL on failure + DESCRIPTION + Generates a new span tree for the hyperslab parameters specified. + Each span tree has a list of the elements spanned in each dimension, with + each span node containing a pointer to the list of spans in the next + dimension down. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static H5S_hyper_span_info_t * +H5S__hyper_make_spans(unsigned rank, const hsize_t *start, const hsize_t *stride, + const hsize_t *count, const hsize_t *block) { - H5S_hyper_span_info_t *new_spans=NULL; /* Span tree for new hyperslab */ - H5S_hyper_span_info_t *tmp_spans=NULL; /* Temporary copy of selection */ - hbool_t span2_owned=FALSE; /* Flag to indicate that span2 was used in H5S_operate_hyperslab() */ - herr_t ret_value=SUCCEED; /* Return value */ + H5S_hyper_span_info_t *down = NULL; /* Pointer to spans in next dimension down */ + H5S_hyper_span_t *last_span; /* Current position in hyperslab span list */ + H5S_hyper_span_t *head = NULL; /* Head of new hyperslab span list */ + int i; /* Counters */ + H5S_hyper_span_info_t *ret_value = NULL; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Check args */ - HDassert(space); - HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + HDassert(rank > 0); HDassert(start); HDassert(stride); HDassert(count); HDassert(block); - /* Generate span tree for new hyperslab information */ - if(NULL == (new_spans = H5S__hyper_make_spans(space->extent.rank, start, stride, count, block))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information") + /* Start creating spans in fastest changing dimension */ + for(i = (int)(rank - 1); i >= 0; i--) { + hsize_t curr_low, curr_high; /* Current low & high values */ + hsize_t dim_stride; /* Current dim's stride */ + unsigned u; /* Local index variable */ - /* Copy the original dataspace */ - if(space->select.sel_info.hslab->span_lst!=NULL) { - /* Take ownership of the dataspace's hyperslab spans */ - /* (These are freed later) */ - tmp_spans=space->select.sel_info.hslab->span_lst; - space->select.sel_info.hslab->span_lst=NULL; + /* Sanity check */ + if(0 == count[i]) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, NULL, "count == 0 is invalid") - /* Reset the other dataspace selection information */ - if(H5S_SELECT_RELEASE(space)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") + /* Start a new list in this dimension */ + head = NULL; + last_span = NULL; - /* Allocate space for the hyperslab selection information */ - if((space->select.sel_info.hslab=H5FL_MALLOC(H5S_hyper_sel_t))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info") + /* Generate all the span segments for this dimension */ + curr_low = start[i]; + curr_high = start[i] + (block[i] - 1); + dim_stride = stride[i]; + for(u = 0; u < count[i]; u++, curr_low += dim_stride, curr_high += dim_stride) { + H5S_hyper_span_t *span; /* New hyperslab span */ - /* Set unlim_dim */ - space->select.sel_info.hslab->unlim_dim = -1; - } /* end if */ + /* Allocate a span node */ + if(NULL == (span = H5FL_MALLOC(H5S_hyper_span_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") - /* Combine tmp_space (really space) & new_space, with the result in space */ - if(H5S_operate_hyperslab(space,tmp_spans,op,new_spans,TRUE,&span2_owned)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") + /* Set the span's basic information */ + span->low = curr_low; + span->high = curr_high; + span->next = NULL; -done: - /* Free temporary data structures */ - if(tmp_spans!=NULL) - if(H5S__hyper_free_span_info(tmp_spans)<0) - HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans") - if(new_spans!=NULL && span2_owned==FALSE) - if(H5S__hyper_free_span_info(new_spans)<0) - HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans") + /* Set the information for the next dimension down's spans */ + /* (Will be NULL for fastest changing dimension) */ + span->down = down; - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__generate_hyperslab() */ + /* Append to the list of spans in this dimension */ + if(head == NULL) + head = span; + else + last_span->next = span; - -/*------------------------------------------------------------------------- - * Function: H5S_select_hyperslab - * - * Purpose: Internal version of H5Sselect_hyperslab(). - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Wednesday, January 10, 2001 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -herr_t -H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, - const hsize_t start[], - const hsize_t *stride, - const hsize_t count[], - const hsize_t *block) -{ - hsize_t int_stride[H5S_MAX_RANK]; /* Internal storage for stride information */ - hsize_t int_count[H5S_MAX_RANK]; /* Internal storage for count information */ - hsize_t int_block[H5S_MAX_RANK]; /* Internal storage for block information */ - const hsize_t *opt_stride; /* Optimized stride information */ - const hsize_t *opt_count; /* Optimized count information */ - const hsize_t *opt_block; /* Optimized block information */ - unsigned u; /* Counters */ - int unlim_dim = -1; /* Unlimited dimension in selection, of -1 if none */ - herr_t ret_value=SUCCEED; /* Return value */ + /* Move current pointer */ + last_span = span; + } /* end for */ - FUNC_ENTER_NOAPI(FAIL) + /* Increment ref. count of shared span */ + if(down != NULL) + down->count = (unsigned)count[i]; - /* Check args */ - HDassert(space); - HDassert(start); - HDassert(count); - HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + /* Allocate a span info node */ + if(NULL == (down = H5S__hyper_new_span_info(rank))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") - /* Point to the correct stride values */ - if(stride==NULL) - stride = H5S_hyper_ones_g; + /* Keep the pointer to the next dimension down's completed list */ + down->head = head; - /* Point to the correct block values */ - if(block==NULL) - block = H5S_hyper_ones_g; + /* Keep the tail pointer to the next dimension down's completed list */ + down->tail = last_span; - /* Check for unlimited dimension */ - for(u = 0; uextent.rank; u++) - if((count[u] == H5S_UNLIMITED) || (block[u] == H5S_UNLIMITED)) { - if(unlim_dim >= 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot have more than one unlimited dimension in selection") - else { - if(count[u] == block[u] /* == H5S_UNLIMITED */) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "count and block cannot both be unlimited") - unlim_dim = (int)u; - } /* end else */ + /* Set the low & high bounds for this dimension */ + down->low_bounds[0] = down->head->low; + down->high_bounds[0] = down->tail->high; + + /* Copy bounds from lower dimensions */ + /* (head & tail pointers share lower dimensions, so using either is OK) */ + if(head->down) { + H5MM_memcpy(&down->low_bounds[1], &head->down->low_bounds[0], sizeof(hsize_t) * ((rank - 1) - (unsigned)i)); + H5MM_memcpy(&down->high_bounds[1], &head->down->high_bounds[0], sizeof(hsize_t) * ((rank - 1) - (unsigned)i)); } /* end if */ + } /* end for */ - /* - * Check new selection. - */ - for(u=0; uextent.rank; u++) { - /* Check for overlapping hyperslab blocks in new selection. */ - if(count[u]>1 && stride[u]count = 1; - /* Detect zero-sized hyperslabs in new selection */ - if(count[u] == 0 || block[u] == 0) { - switch(op) { - case H5S_SELECT_SET: /* Select "set" operation */ - case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ - case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */ - /* Convert to "none" selection */ - if(H5S_select_none(space)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection") - HGOTO_DONE(SUCCEED); + /* Success! Return the head of the list in the slowest changing dimension */ + ret_value = down; - case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ - case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */ - case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */ - HGOTO_DONE(SUCCEED); /* Selection stays same */ +done: + /* cleanup if error (ret_value will be NULL) */ + if(!ret_value) { + if(head || down) { + if(head && down) + if(down->head != head) + down = NULL; - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ - } /* end if */ - } /* end for */ + do { + if(down) { + head = down->head; + down = (H5S_hyper_span_info_t *)H5FL_ARR_FREE(hbounds_t, down); + } /* end if */ + down = head->down; - /* Optimize hyperslab parameters to merge contiguous blocks, etc. */ - if(stride == H5S_hyper_ones_g && block == H5S_hyper_ones_g) { - /* Point to existing arrays */ - opt_stride = H5S_hyper_ones_g; - opt_count = H5S_hyper_ones_g; - opt_block = count; + while(head) { + last_span = head->next; + head = H5FL_FREE(H5S_hyper_span_t, head); + head = last_span; + } /* end while */ + } while(down); + } /* end if */ } /* end if */ - else { - /* Point to local arrays */ - opt_stride = int_stride; - opt_count = int_count; - opt_block = int_block; - for(u=0; uextent.rank; u++) { - /* contiguous hyperslabs have the block size equal to the stride */ - if((stride[u] == block[u]) && (count[u] != H5S_UNLIMITED)) { - int_count[u]=1; - int_stride[u]=1; - if(block[u]==1) - int_block[u]=count[u]; - else - int_block[u]=block[u]*count[u]; - } /* end if */ - else { - if(count[u]==1) - int_stride[u]=1; - else { - HDassert((stride[u] > block[u]) || ((stride[u] == block[u]) - && (count[u] == H5S_UNLIMITED))); - int_stride[u]=stride[u]; - } /* end else */ - int_count[u]=count[u]; - int_block[u]=block[u]; - } /* end else */ - } /* end for */ - } /* end else */ - /* Check for operating on unlimited selection */ - if((H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS) - && (space->select.sel_info.hslab->unlim_dim >= 0) - && (op != H5S_SELECT_SET)) - { - /* Check for invalid operation */ - if(unlim_dim >= 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot modify unlimited selection with another unlimited selection") - if(!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTA))) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation on unlimited selection") - HDassert(space->select.sel_info.hslab->diminfo_valid); + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_make_spans() */ - /* Clip unlimited selection to include new selection */ - if(H5S_hyper_clip_unlim(space, - start[space->select.sel_info.hslab->unlim_dim] - + ((opt_count[space->select.sel_info.hslab->unlim_dim] - - (hsize_t)1) - * opt_stride[space->select.sel_info.hslab->unlim_dim]) - + opt_block[space->select.sel_info.hslab->unlim_dim]) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection") - /* If an empty space was returned it must be "none" */ - HDassert((space->select.num_elem > (hsize_t)0) - || (space->select.type->type == H5S_SEL_NONE)); - } /* end if */ +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_update_diminfo + PURPOSE + Attempt to update optimized hyperslab information quickly. (It can be + recovered with regular selection). If this algorithm cannot determine + the optimized dimension info quickly, this function will simply mark it + as invalid and unknown if it can be built (H5S_DIMINFO_VALID_NO), so + H5S__hyper_rebuild can be run later to determine for sure. + USAGE + herr_t H5S__hyper_update_diminfo(space, op, new_hyper_diminfo) + H5S_t *space; IN: Dataspace to check + H5S_seloper_t op; IN: The operation being performed on the + selection + const H5S_hyper_dim_t new_hyper_diminfo; IN: The new selection that + is being combined with + the current + RETURNS + >=0 on success, <0 on failure + DESCRIPTION + Examine the span tree for a hyperslab selection and rebuild + the start/stride/count/block information for the selection, if possible. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_update_diminfo(H5S_t *space, H5S_seloper_t op, + const H5S_hyper_dim_t *new_hyper_diminfo) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check args */ + HDassert(space); + HDassert(new_hyper_diminfo); - /* Fixup operation for non-hyperslab selections */ - switch(H5S_GET_SELECT_TYPE(space)) { - case H5S_SEL_NONE: /* No elements selected in dataspace */ - switch(op) { - case H5S_SELECT_SET: /* Select "set" operation */ - /* Change "none" selection to hyperslab selection */ + /* Check for conditions that prevent us from using the fast algorithm here */ + /* (and instead require H5S__hyper_rebuild) */ + if(!((op == H5S_SELECT_OR) || (op == H5S_SELECT_XOR)) + || space->select.sel_info.hslab->diminfo_valid != H5S_DIMINFO_VALID_YES + || !space->select.sel_info.hslab->span_lst->head) + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; + else { + H5S_hyper_dim_t tmp_diminfo[H5S_MAX_RANK]; /* Temporary dimension info */ + hbool_t found_nonidentical_dim = FALSE; + unsigned curr_dim; + + /* Copy current diminfo.opt values */ + H5MM_memcpy(tmp_diminfo, space->select.sel_info.hslab->diminfo.opt, sizeof(tmp_diminfo)); + + /* Loop over dimensions */ + for(curr_dim = 0; curr_dim < space->extent.rank; curr_dim++) { + /* Check for this being identical */ + if((tmp_diminfo[curr_dim].start != new_hyper_diminfo[curr_dim].start) + || (tmp_diminfo[curr_dim].stride != new_hyper_diminfo[curr_dim].stride) + || (tmp_diminfo[curr_dim].count != new_hyper_diminfo[curr_dim].count) + || (tmp_diminfo[curr_dim].block != new_hyper_diminfo[curr_dim].block)) { + hsize_t high_start, high_count, high_block; /* The start, count & block values for the higher block */ + + /* Dimension is not identical */ + /* Check if we already found a nonidentical dim - only one is + * allowed */ + if(found_nonidentical_dim) { + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; break; + } /* end if */ - case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ - case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */ - case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */ - op=H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */ + /* Check that strides are the same, or count is 1 for one of the + * slabs */ + if((tmp_diminfo[curr_dim].stride != new_hyper_diminfo[curr_dim].stride) + && (tmp_diminfo[curr_dim].count > 1) + && (new_hyper_diminfo[curr_dim].count > 1)) { + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; break; + } /* end if */ - case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ - case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */ - HGOTO_DONE(SUCCEED); /* Selection stays "none" */ + /* Patch tmp_diminfo.stride if its count is 1 */ + if((tmp_diminfo[curr_dim].count == 1) + && (new_hyper_diminfo[curr_dim].count > 1)) + tmp_diminfo[curr_dim].stride = new_hyper_diminfo[curr_dim].stride; - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ - break; + /* Determine lowest start, and set tmp_diminfo.start, count and + * block to use the lowest, and high_start, high_count and + * high_block to use the highest + */ + if(tmp_diminfo[curr_dim].start < new_hyper_diminfo[curr_dim].start) { + high_start = new_hyper_diminfo[curr_dim].start; + high_count = new_hyper_diminfo[curr_dim].count; + high_block = new_hyper_diminfo[curr_dim].block; + } /* end if */ + else { + high_start = tmp_diminfo[curr_dim].start; + tmp_diminfo[curr_dim].start = new_hyper_diminfo[curr_dim].start; + high_count = tmp_diminfo[curr_dim].count; + tmp_diminfo[curr_dim].count = new_hyper_diminfo[curr_dim].count; + high_block = tmp_diminfo[curr_dim].block; + tmp_diminfo[curr_dim].block = new_hyper_diminfo[curr_dim].block; + } /* end else */ - case H5S_SEL_ALL: /* All elements selected in dataspace */ - switch(op) { - case H5S_SELECT_SET: /* Select "set" operation */ - /* Change "all" selection to hyperslab selection */ - break; + /* If count is 1 for both slabs, take different actions */ + if((tmp_diminfo[curr_dim].count == 1) && (high_count == 1)) { + /* Check for overlap */ + if((tmp_diminfo[curr_dim].start + tmp_diminfo[curr_dim].block) + > high_start) { + /* Check operation type */ + if(op == H5S_SELECT_OR) + /* Merge blocks */ + tmp_diminfo[curr_dim].block = ((high_start + high_block) + >= (tmp_diminfo[curr_dim].start + tmp_diminfo[curr_dim].block)) + ? (high_start + high_block - tmp_diminfo[curr_dim].start) + : tmp_diminfo[curr_dim].block; + else { + /* Block values must be the same */ + if(tmp_diminfo[curr_dim].block != high_block) { + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; + break; + } /* end if */ - case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ - HGOTO_DONE(SUCCEED); /* Selection stays "all" */ + /* XOR - overlap creates 2 blocks */ + tmp_diminfo[curr_dim].stride = high_block; + tmp_diminfo[curr_dim].count = 2; + tmp_diminfo[curr_dim].block = high_start - tmp_diminfo[curr_dim].start; + } /* end else */ + } /* end if */ + else if((tmp_diminfo[curr_dim].start + tmp_diminfo[curr_dim].block) + == high_start) + /* Blocks border, merge them */ + tmp_diminfo[curr_dim].block += high_block; + else { + /* Distinct blocks */ + /* Block values must be the same */ + if(tmp_diminfo[curr_dim].block != high_block) { + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; + break; + } /* end if */ - case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ - op=H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */ - break; + /* Create strided selection */ + tmp_diminfo[curr_dim].stride = high_start - tmp_diminfo[curr_dim].start; + tmp_diminfo[curr_dim].count = 2; + } /* end else */ + } /* end if */ + else { + /* Check if block values are the same */ + if(tmp_diminfo[curr_dim].block != new_hyper_diminfo[curr_dim].block) { + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; + break; + } /* end if */ - case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */ - case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */ - /* Convert current "all" selection to "real" hyperslab selection */ - /* Then allow operation to proceed */ - { - hsize_t tmp_start[H5S_MAX_RANK]; /* Temporary start information */ - hsize_t tmp_stride[H5S_MAX_RANK]; /* Temporary stride information */ - hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary count information */ - hsize_t tmp_block[H5S_MAX_RANK]; /* Temporary block information */ - - /* Fill in temporary information for the dimensions */ - for(u=0; uextent.rank; u++) { - tmp_start[u]=0; - tmp_stride[u]=1; - tmp_count[u]=1; - tmp_block[u]=space->extent.size[u]; - } /* end for */ + /* Check phase of strides */ + if((tmp_diminfo[curr_dim].start % tmp_diminfo[curr_dim].stride) + != (new_hyper_diminfo[curr_dim].start % tmp_diminfo[curr_dim].stride)) { + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; + break; + } /* end if */ - /* Convert to hyperslab selection */ - if(H5S_select_hyperslab(space,H5S_SELECT_SET,tmp_start,tmp_stride,tmp_count,tmp_block)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection") - } /* end case */ - break; + /* Check operation type */ + if(op == H5S_SELECT_OR) { + /* Make sure the slabs border or overlap */ + if(high_start > (tmp_diminfo[curr_dim].start + + (tmp_diminfo[curr_dim].count + * tmp_diminfo[curr_dim].stride))) { + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; + break; + } /* end if */ + } /* end if */ + else + /* XOR: Make sure the slabs border */ + if(high_start != (tmp_diminfo[curr_dim].start + + (tmp_diminfo[curr_dim].count + * tmp_diminfo[curr_dim].stride))) { + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; + break; + } /* end if */ - case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */ - /* Convert to "none" selection */ - if(H5S_select_none(space)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection") - HGOTO_DONE(SUCCEED); + /* Set count for combined selection */ + tmp_diminfo[curr_dim].count = ((high_start + - tmp_diminfo[curr_dim].start) + / tmp_diminfo[curr_dim].stride) + high_count; + } /* end else */ - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ - break; + /* Indicate that we found a nonidentical dim */ + found_nonidentical_dim = TRUE; + } /* end if */ + } /* end for */ - case H5S_SEL_HYPERSLABS: - /* Hyperslab operation on hyperslab selection, OK */ - break; + /* Check if we succeeded, if so, set the new diminfo values */ + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) + for(curr_dim = 0; curr_dim < space->extent.rank; curr_dim++) { + hsize_t tmp_high_bound; + + /* Set the new diminfo values */ + space->select.sel_info.hslab->diminfo.app[curr_dim].start = space->select.sel_info.hslab->diminfo.opt[curr_dim].start = tmp_diminfo[curr_dim].start; + HDassert(tmp_diminfo[curr_dim].stride > 0); + space->select.sel_info.hslab->diminfo.app[curr_dim].stride = space->select.sel_info.hslab->diminfo.opt[curr_dim].stride = tmp_diminfo[curr_dim].stride; + HDassert(tmp_diminfo[curr_dim].count > 0); + space->select.sel_info.hslab->diminfo.app[curr_dim].count = space->select.sel_info.hslab->diminfo.opt[curr_dim].count = tmp_diminfo[curr_dim].count; + HDassert(tmp_diminfo[curr_dim].block > 0); + space->select.sel_info.hslab->diminfo.app[curr_dim].block = space->select.sel_info.hslab->diminfo.opt[curr_dim].block = tmp_diminfo[curr_dim].block; + + /* Check for updating the low & high bounds */ + if(tmp_diminfo[curr_dim].start < space->select.sel_info.hslab->diminfo.low_bounds[curr_dim]) + space->select.sel_info.hslab->diminfo.low_bounds[curr_dim] = tmp_diminfo[curr_dim].start; + tmp_high_bound = tmp_diminfo[curr_dim].start + + (tmp_diminfo[curr_dim].block - 1) + + (tmp_diminfo[curr_dim].stride * (tmp_diminfo[curr_dim].count - 1)); + if(tmp_high_bound > space->select.sel_info.hslab->diminfo.low_bounds[curr_dim]) + space->select.sel_info.hslab->diminfo.high_bounds[curr_dim] = tmp_high_bound; + } /* end for */ + } /* end else */ - case H5S_SEL_POINTS: /* Can't combine hyperslab operations and point selections currently */ - if(op==H5S_SELECT_SET) /* Allow only "set" operation to proceed */ - break; - /* Else fall through to error */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_update_diminfo() */ - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_rebuild_helper + PURPOSE + Helper routine to rebuild optimized hyperslab information if possible. + (It can be recovered with regular selection) + USAGE + herr_t H5S__hyper_rebuild_helper(space) + const H5S_hyper_span_t *spans; IN: Portion of span tree to check + H5S_hyper_dim_t span_slab_info[]; OUT: Rebuilt section of hyperslab description + RETURNS + TRUE/FALSE for hyperslab selection rebuilt + DESCRIPTION + Examine the span tree for a hyperslab selection and rebuild + the start/stride/count/block information for the selection, if possible. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + To be able to recover the optimized information, the span tree must conform + to span tree able to be generated from a single H5S_SELECT_SET operation. + EXAMPLES + REVISION LOG + KY, 2005/9/22 +--------------------------------------------------------------------------*/ +static hbool_t +H5S__hyper_rebuild_helper(const H5S_hyper_span_info_t *spans, H5S_hyper_dim_t span_slab_info[]) +{ + const H5S_hyper_span_t *span; /* Hyperslab span */ + const H5S_hyper_span_t *prev_span; /* Previous span in list */ + hsize_t start; /* Starting element for this dimension */ + hsize_t stride; /* Stride for this dimension */ + hsize_t block; /* Block size for this dimension */ + hsize_t prev_low; /* Low bound for previous span */ + size_t spancount; /* Number of spans encountered in this dimension */ + hbool_t ret_value = TRUE; /* Return value */ + FUNC_ENTER_STATIC_NOERR - if(op==H5S_SELECT_SET) { - /* If we are setting a new selection, remove current selection first */ - if(H5S_SELECT_RELEASE(space)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release hyperslab") + /* Sanity check */ + HDassert(spans); - /* Allocate space for the hyperslab selection information */ - if(NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info") - - /* Save the diminfo */ - space->select.num_elem=1; - for(u=0; uextent.rank; u++) { - space->select.sel_info.hslab->diminfo.app[u].start = start[u]; - space->select.sel_info.hslab->diminfo.app[u].stride = stride[u]; - space->select.sel_info.hslab->diminfo.app[u].count = count[u]; - space->select.sel_info.hslab->diminfo.app[u].block = block[u]; - - space->select.sel_info.hslab->diminfo.opt[u].start = start[u]; - space->select.sel_info.hslab->diminfo.opt[u].stride = opt_stride[u]; - space->select.sel_info.hslab->diminfo.opt[u].count = opt_count[u]; - space->select.sel_info.hslab->diminfo.opt[u].block = opt_block[u]; - - space->select.num_elem*=(opt_count[u]*opt_block[u]); - } /* end for */ + /* Initialization */ + span = spans->head; + stride = 1; + prev_low = 0; + spancount = 0; - /* Save unlim_dim */ - space->select.sel_info.hslab->unlim_dim = unlim_dim; + /* Get "canonical" down span information */ + if(span->down) + /* Go to the next down span and check whether the selection can be rebuilt */ + if(!H5S__hyper_rebuild_helper(span->down, &span_slab_info[1])) + HGOTO_DONE(FALSE) - /* Indicate that the dimension information is valid */ - space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES; + /* Assign the initial starting point & block size for this dimension */ + start = span->low; + block = (span->high - span->low) + 1; - /* Indicate that there's no slab information */ - space->select.sel_info.hslab->span_lst = NULL; + /* Loop the spans */ + prev_span = NULL; + while(span) { + if(spancount > 0) { + hsize_t curr_stride; /* Current stride from previous span */ + hsize_t curr_block; /* Block size of current span */ - /* Handle unlimited selections */ - if(unlim_dim >= 0) { - /* Calculate num_elem_non_unlim */ - space->select.sel_info.hslab->num_elem_non_unlim = (hsize_t)1; - for(u = 0; u < space->extent.rank; u++) - if((int)u != unlim_dim) - space->select.sel_info.hslab->num_elem_non_unlim *= (opt_count[u] * opt_block[u]); + /* Sanity check */ + HDassert(prev_span); - /* Set num_elem */ - if(space->select.num_elem != (hsize_t)0) - space->select.num_elem = H5S_UNLIMITED; + /* Check that down spans match current slab info */ + /* (Can skip check if previous span's down pointer is same as current one) */ + if(span->down && prev_span->down != span->down) + if(!H5S__hyper_cmp_spans(span->down, prev_span->down)) + HGOTO_DONE(FALSE) + + /* Obtain values for stride and block */ + curr_stride = span->low - prev_low; + curr_block = (span->high - span->low) + 1; + + /* Compare stride and block for this span. To compare stride, + * three spans are needed. Account for the first two spans. + */ + if(curr_block != block) + HGOTO_DONE(FALSE) + if(spancount > 1) { + if(stride != curr_stride) + HGOTO_DONE(FALSE) + } /* end if */ + else + stride = curr_stride; } /* end if */ - } /* end if */ - else if(op>=H5S_SELECT_OR && op<=H5S_SELECT_NOTA) { - /* Sanity check */ - HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS); - /* Handle unlimited selections */ - if(unlim_dim >= 0) { - hsize_t bounds_start[H5S_MAX_RANK]; - hsize_t bounds_end[H5S_MAX_RANK]; - hsize_t tmp_count = opt_count[unlim_dim]; - hsize_t tmp_block = opt_block[unlim_dim]; + /* Keep current starting point */ + prev_low = span->low; - /* Check for invalid operation */ - if(space->select.sel_info.hslab->unlim_dim >= 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot modify unlimited selection with another unlimited selection") - if(!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTB))) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation with unlimited selection") + /* Advance to next span */ + prev_span = span; + span = span->next; + spancount++; + } /* end while */ - /* Get bounds of existing selection */ - if(H5S__hyper_bounds(space, bounds_start, bounds_end) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds") + /* Save the span information. */ + span_slab_info[0].start = start; + span_slab_info[0].count = spancount; + span_slab_info[0].block = block; + span_slab_info[0].stride = stride; - /* Patch count and block to remove unlimited and include the - * existing selection */ - H5S__hyper_get_clip_diminfo(start[unlim_dim], opt_stride[unlim_dim], &tmp_count, &tmp_block, bounds_end[unlim_dim] + (hsize_t)1); - HDassert((tmp_count == 1) || (opt_count != H5S_hyper_ones_g)); - HDassert((tmp_block == 1) || (opt_block != H5S_hyper_ones_g)); - if(opt_count != H5S_hyper_ones_g) { - HDassert(opt_count == int_count); - int_count[unlim_dim] = tmp_count; - } /* end if */ - if(opt_block != H5S_hyper_ones_g) { - HDassert(opt_block == int_block); - int_block[unlim_dim] = tmp_block; - } /* end if */ - } /* end if */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_rebuild_helper() */ - /* Check if there's no hyperslab span information currently */ - if(NULL == space->select.sel_info.hslab->span_lst) - if(H5S__hyper_generate_spans(space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_rebuild + PURPOSE + Rebuild optimized hyperslab information if possible. + (It can be recovered with regular selection) + USAGE + void H5S__hyper_rebuild(space) + H5S_t *space; IN: Dataspace to check + RETURNS + None + DESCRIPTION + Examine the span tree for a hyperslab selection and rebuild a regular + start/stride/count/block hyperslab selection, if possible. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + To be able to recover the optimized information, the span tree must conform + to span tree able to be generated from a single H5S_SELECT_SET operation. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +void +H5S__hyper_rebuild(H5S_t *space) +{ + H5S_hyper_dim_t rebuilt_slab_info[H5S_MAX_RANK]; - /* Indicate that the regular dimensions are no longer valid */ - space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; + FUNC_ENTER_PACKAGE_NOERR - /* Add in the new hyperslab information */ - if(H5S__generate_hyperslab (space, op, start, opt_stride, opt_count, opt_block)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs") - } /* end if */ - else - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + /* Check args */ + HDassert(space); + HDassert(space->select.sel_info.hslab->span_lst); + + /* Check whether the slab can be rebuilt */ + /* (Only regular selection can be rebuilt. If yes, fill in correct values) */ + if(FALSE == H5S__hyper_rebuild_helper(space->select.sel_info.hslab->span_lst, rebuilt_slab_info)) + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_IMPOSSIBLE; + else { + /* Set the dimension info & bounds for the dataspace, from the rebuilt info */ + H5MM_memcpy(space->select.sel_info.hslab->diminfo.app, rebuilt_slab_info, sizeof(rebuilt_slab_info)); + H5MM_memcpy(space->select.sel_info.hslab->diminfo.opt, rebuilt_slab_info, sizeof(rebuilt_slab_info)); + H5MM_memcpy(space->select.sel_info.hslab->diminfo.low_bounds, space->select.sel_info.hslab->span_lst->low_bounds, sizeof(hsize_t) * space->extent.rank); + H5MM_memcpy(space->select.sel_info.hslab->diminfo.high_bounds, space->select.sel_info.hslab->span_lst->high_bounds, sizeof(hsize_t) * space->extent.rank); + + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES; + } /* end else */ + + FUNC_LEAVE_NOAPI_VOID +} /* end H5S__hyper_rebuild() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_generate_spans + PURPOSE + Create span tree for a regular hyperslab selection + USAGE + herr_t H5S__hyper_generate_spans(space) + H5S_t *space; IN/OUT: Pointer to dataspace + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Create a span tree representation of a regular hyperslab selection and + add it to the information for the hyperslab selection. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_generate_spans(H5S_t *space) +{ + hsize_t tmp_start[H5S_MAX_RANK]; /* Temporary start information */ + hsize_t tmp_stride[H5S_MAX_RANK]; /* Temporary stride information */ + hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary count information */ + hsize_t tmp_block[H5S_MAX_RANK]; /* Temporary block information */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + HDassert(space); + HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS); + + /* Get the diminfo */ + for(u = 0; u < space->extent.rank; u++) { + /* Check for unlimited dimension and return error */ + /* These should be able to be converted to assertions once everything + * that calls this function checks for unlimited selections first + * (especially the new hyperslab API) -NAF */ + if(space->select.sel_info.hslab->diminfo.opt[u].count == H5S_UNLIMITED) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited count") + if(space->select.sel_info.hslab->diminfo.opt[u].block == H5S_UNLIMITED) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited block") + + tmp_start[u] = space->select.sel_info.hslab->diminfo.opt[u].start; + tmp_stride[u] = space->select.sel_info.hslab->diminfo.opt[u].stride; + tmp_count[u] = space->select.sel_info.hslab->diminfo.opt[u].count; + tmp_block[u] = space->select.sel_info.hslab->diminfo.opt[u].block; + } /* end for */ - /* Set selection type */ - space->select.type = H5S_sel_hyper; + /* Build the hyperslab information also */ + if(H5S__generate_hyperslab(space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count, tmp_block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs") done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_select_hyperslab() */ +} /* end H5S__hyper_generate_spans() */ /*-------------------------------------------------------------------------- NAME - H5Sselect_hyperslab + H5S__check_spans_overlap PURPOSE - Specify a hyperslab to combine with the current hyperslab selection + Check if two selections' bounds overlap. USAGE - herr_t H5Sselect_hyperslab(dsid, op, start, stride, count, block) - hid_t dsid; IN: Dataspace ID of selection to modify - H5S_seloper_t op; IN: Operation to perform on current selection - const hsize_t *start; IN: Offset of start of hyperslab - const hsize_t *stride; IN: Hyperslab stride - const hsize_t *count; IN: Number of blocks included in hyperslab - const hsize_t *block; IN: Size of block in hyperslab + hbool_t H5S__check_spans_overlap(spans1, spans2) + const H5S_hyper_span_info_t *spans1; IN: Second span list + const H5S_hyper_span_info_t *spans2; IN: Second span list RETURNS - Non-negative on success/Negative on failure - DESCRIPTION - Combines a hyperslab selection with the current selection for a dataspace. - If the current selection is not a hyperslab, it is freed and the hyperslab - parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a - selection composing the entire current extent). If STRIDE or BLOCK is - NULL, they are assumed to be set to all '1'. + TRUE for overlap, FALSE for no overlap + PROGRAMMER + Quincey Koziol - January 24, 2019 GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -herr_t -H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[], - const hsize_t stride[], const hsize_t count[], const hsize_t block[]) +static H5_ATTR_PURE hbool_t +H5S__check_spans_overlap(const H5S_hyper_span_info_t *spans1, + const H5S_hyper_span_info_t *spans2) { - H5S_t *space = NULL; /* Dataspace to modify selection of */ - herr_t ret_value=SUCCEED; /* Return value */ + hbool_t ret_value = FALSE; /* Return value */ - FUNC_ENTER_API(FAIL) - H5TRACE6("e", "iSs*h*h*h*h", space_id, op, start, stride, count, block); + FUNC_ENTER_STATIC_NOERR - /* Check args */ - if (NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") - if (H5S_SCALAR==H5S_GET_EXTENT_TYPE(space)) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_SCALAR space") - if (H5S_NULL==H5S_GET_EXTENT_TYPE(space)) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_NULL space") - if(start==NULL || count==NULL) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified") - if(!(op>H5S_SELECT_NOOP && opextent.rank; u++) { - if(stride[u]==0) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid stride==0 value") - } /* end for */ - } /* end if */ + /* Use low & high bounds to try to avoid spinning through the span lists */ + if(H5S_RANGE_OVERLAP(spans1->low_bounds[0], spans1->high_bounds[0], + spans2->low_bounds[0], spans2->high_bounds[0])) { + H5S_hyper_span_t *span1, *span2; /* Hyperslab spans */ + + /* Walk over spans, comparing them for overlap */ + span1 = spans1->head; + span2 = spans2->head; + while(span1 && span2) { + /* Check current two spans for overlap */ + if(H5S_RANGE_OVERLAP(span1->low, span1->high, span2->low, span2->high)) { + /* Check for spans in lowest dimension already */ + if(span1->down) { + /* Sanity check */ + HDassert(span2->down); - if (H5S_select_hyperslab(space, op, start, stride, count, block)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection") + /* Check lower dimensions for overlap */ + if(H5S__check_spans_overlap(span1->down, span2->down)) + HGOTO_DONE(TRUE); + } /* end if */ + else + HGOTO_DONE(TRUE); + } /* end if */ + + /* Advance one of the spans */ + if(span1->high <= span2->high) { + /* Advance span1, unless it would be off the list and span2 has more nodes */ + if(NULL == span1->next && NULL != span2->next) + span2 = span2->next; + else + span1 = span1->next; + } /* end if */ + else { + /* Advance span2, unless it would be off the list and span1 has more nodes */ + if(NULL == span2->next && NULL != span1->next) + span1 = span1->next; + else + span2 = span2->next; + } /* end else */ + } /* end while */ + + /* Make certain we've exhausted our comparisons */ + HDassert((NULL == span1 && (NULL != span2 && NULL == span2->next)) || + ((NULL != span1 && NULL == span1->next) && NULL == span2)); + } /* end of */ done: - FUNC_LEAVE_API(ret_value) -} /* end H5Sselect_hyperslab() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__check_spans_overlap() */ /*-------------------------------------------------------------------------- NAME - H5Scombine_hyperslab + H5S__fill_in_new_space PURPOSE - Specify a hyperslab to combine with the current hyperslab selection and - return a new dataspace with the combined selection as the selection in the - new dataspace. + Combine two span lists, one from an existing dataspace and the + other from input arguments, into a new selection depending on the + selection operator. The new selection is put into a resulting dataspace + which could be allocated inside the function. USAGE - hid_t H5Srefine_hyperslab(dsid, op, start, stride, count, block) - hid_t dsid; IN: Dataspace ID of selection to use - H5S_seloper_t op; IN: Operation to perform on current selection - const hsize_t *start; IN: Offset of start of hyperslab - const hsize_t *stride; IN: Hyperslab stride - const hsize_t *count; IN: Number of blocks included in hyperslab - const hsize_t *block; IN: Size of block in hyperslab + herr_t H5S__fill_in_new_space(space1, op, space2_span_lst, can_own_span2, + span2_owned, result) + H5S_t *space1; IN: Dataspace containing the first span list + H5S_seloper_t op; IN: Selection operation + H5S_hyper_span_info_t *space2_span_lst; IN: Second span list + hbool_t can_own_span2; IN: Indicates whether the 2nd span list could be + owned by the result. If not, the 2nd span list + has to be copied. + hbool_t *span2_owned; OUT: Indicates if the 2nd span list is actually owned + H5S_t **result; OUT: The dataspace containing the the new selection. It + could be same with the 1st dataspace. RETURNS - Dataspace ID on success / H5I_INVALID_HID on failure - DESCRIPTION - Combines a hyperslab selection with the current selection for a dataspace, - creating a new dataspace to return the generated selection. - If the current selection is not a hyperslab, it is freed and the hyperslab - parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a - selection composing the entire current extent). If STRIDE or BLOCK is - NULL, they are assumed to be set to all '1'. + Non-negative on success, negative on failure + PROGRAMMER + Chao Mei July 8, 2011 GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -hid_t -H5Scombine_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[], - const hsize_t stride[], const hsize_t count[], const hsize_t block[]) +static herr_t +H5S__fill_in_new_space(H5S_t *space1, H5S_seloper_t op, + H5S_hyper_span_info_t *space2_span_lst, hbool_t can_own_span2, + hbool_t *span2_owned, hbool_t *updated_spans, H5S_t **result) { - H5S_t *space; /* Dataspace to modify selection of */ - H5S_t *new_space = NULL; /* New dataspace created */ - hid_t ret_value; /* Return value */ + H5S_hyper_span_info_t *a_not_b = NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */ + H5S_hyper_span_info_t *a_and_b = NULL; /* Span tree for hyperslab spans in both old and new span trees */ + H5S_hyper_span_info_t *b_not_a = NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */ + hbool_t overlapped = FALSE; /* Whether selections overlap */ + hbool_t is_result_new = FALSE; + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_API(H5I_INVALID_HID) - H5TRACE6("i", "iSs*h*h*h*h", space_id, op, start, stride, count, block); + FUNC_ENTER_STATIC - /* Check args */ - if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a dataspace") - if(start == NULL || count == NULL) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "hyperslab not specified") - if(!(op >= H5S_SELECT_SET && op <= H5S_SELECT_NOTA)) - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, H5I_INVALID_HID, "invalid selection operation") + HDassert(space1); + HDassert(space2_span_lst); + HDassert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA); + /* The result is either a to-be-created space or an empty one */ + HDassert(*result == NULL || *result == space1); + HDassert(space1->select.sel_info.hslab->span_lst); + HDassert(span2_owned); + + /* Reset flags to return */ + *span2_owned = FALSE; + *updated_spans = FALSE; + + /* The result shares the same info from space1 */ + if(*result == NULL) { + if(NULL == ((*result) = H5S_copy(space1, TRUE, TRUE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace") + space1->select.sel_info.hslab->span_lst->count--; + (*result)->select.sel_info.hslab->span_lst = NULL; + is_result_new = TRUE; + } /* end if */ - /* Copy the first dataspace */ - if (NULL == (new_space = H5S_copy (space, TRUE, TRUE))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, H5I_INVALID_HID, "unable to copy dataspace") + /* Check both spaces to see if they overlap */ + overlapped = H5S__check_spans_overlap(space1->select.sel_info.hslab->span_lst, space2_span_lst); - /* Go modify the selection in the new dataspace */ - if (H5S_select_hyperslab(new_space, op, start, stride, count, block)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, H5I_INVALID_HID, "unable to set hyperslab selection") + if(!overlapped) { + switch(op) { + case H5S_SELECT_OR: + case H5S_SELECT_XOR: + /* Add the new disjoint spans to the space */ + /* Copy of space1's spans to *result, and another copy of space2's spans */ + if(is_result_new) + (*result)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(space1->select.sel_info.hslab->span_lst, space1->extent.rank); + if(!can_own_span2) { + b_not_a = H5S__hyper_copy_span(space2_span_lst, space1->extent.rank); + if(H5S__hyper_add_disjoint_spans(*result, b_not_a) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't append hyperslabs") + + /* The new_spans are now owned by 'space', so they should not be released */ + b_not_a = NULL; + } /* end if */ + else { + if(H5S__hyper_add_disjoint_spans(*result, space2_span_lst) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't append hyperslabs") + *span2_owned = TRUE; + } /* end else */ - /* Atomize */ - if((ret_value = H5I_register(H5I_DATASPACE, new_space, TRUE)) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register dataspace atom") + /* Indicate that the spans changed */ + *updated_spans = TRUE; + break; -done: - if(ret_value < 0 && new_space) - H5S_close(new_space); + case H5S_SELECT_AND: + /* Convert *result to "none" selection */ + if(H5S_select_none(*result) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection") + HGOTO_DONE(SUCCEED); - FUNC_LEAVE_API(ret_value) -} /* end H5Scombine_hyperslab() */ + case H5S_SELECT_NOTB: + /* Copy space1's spans to *result */ + if(is_result_new) + (*result)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(space1->select.sel_info.hslab->span_lst, space1->extent.rank); - -/*------------------------------------------------------------------------- - * Function: H5S__combine_select - * - * Purpose: Internal version of H5Scombine_select(). - * - * Return: New dataspace on success/NULL on failure - * - * Programmer: Quincey Koziol - * Tuesday, October 30, 2001 - * - *------------------------------------------------------------------------- - */ -static H5S_t * -H5S__combine_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2) -{ - H5S_t *new_space = NULL; /* New dataspace generated */ - hbool_t span2_owned=FALSE; /* Flag to indicate that span2 was used in H5S_operate_hyperslab() */ - H5S_t *ret_value = NULL; /* Return value */ + /* Indicate that the spans changed */ + *updated_spans = TRUE; + break; - FUNC_ENTER_STATIC + case H5S_SELECT_NOTA: + if(!is_result_new) { + HDassert(space1 == *result); - /* Check args */ - HDassert(space1); - HDassert(space2); - HDassert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA); + /* Free the current selection */ + H5S__hyper_free_span_info(space1->select.sel_info.hslab->span_lst); + space1->select.sel_info.hslab->span_lst = NULL; + } /* end if */ - /* Check that the space selections both have span trees */ - if(space1->select.sel_info.hslab->span_lst==NULL) - if(H5S__hyper_generate_spans(space1)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, NULL, "dataspace does not have span tree") - if(space2->select.sel_info.hslab->span_lst==NULL) - if(H5S__hyper_generate_spans(space2)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, NULL, "dataspace does not have span tree") + /* Copy space2's spans to *result */ + if(!can_own_span2) + (*result)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(space2_span_lst, space1->extent.rank); + else { + (*result)->select.sel_info.hslab->span_lst = space2_span_lst; + *span2_owned = TRUE; + } /* end else */ - /* Copy the first dataspace */ - if (NULL == (new_space = H5S_copy (space1, TRUE, TRUE))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to copy dataspace") + /* Reset the number of items in selection */ + (*result)->select.num_elem = H5S__hyper_spans_nelem(space2_span_lst); - /* Free the current selection for the new dataspace */ - if(H5S_SELECT_RELEASE(new_space)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, NULL, "can't release selection") + /* Indicate that the spans changed */ + *updated_spans = TRUE; + break; - /* Allocate space for the hyperslab selection information */ - if((new_space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)) == NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab info") - new_space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; + case H5S_SELECT_NOOP: + case H5S_SELECT_SET: + case H5S_SELECT_APPEND: + case H5S_SELECT_PREPEND: + case H5S_SELECT_INVALID: + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ + } /* end if */ + else { + unsigned selector = 0; /* Select which clipping spans to generate */ - /* Set unlim_dim */ - new_space->select.sel_info.hslab->unlim_dim = -1; + /* Generate mask for clip operation depending on the op */ + switch(op) { + case H5S_SELECT_OR: /* a + b_not_a */ + selector = H5S_HYPER_COMPUTE_B_NOT_A; + break; - /* Combine space1 & space2, with the result in new_space */ - if(H5S_operate_hyperslab(new_space,space1->select.sel_info.hslab->span_lst,op,space2->select.sel_info.hslab->span_lst,FALSE,&span2_owned)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, NULL, "can't clip hyperslab information") + case H5S_SELECT_XOR: /* a_not_b + b_not_a */ + selector = H5S_HYPER_COMPUTE_A_NOT_B | H5S_HYPER_COMPUTE_B_NOT_A; + break; - /* Set return value */ - ret_value = new_space; + case H5S_SELECT_AND: /* a_and_b */ + selector = H5S_HYPER_COMPUTE_A_AND_B; + break; -done: - if(ret_value == NULL && new_space) - H5S_close(new_space); + case H5S_SELECT_NOTB: /* a_not_b */ + selector = H5S_HYPER_COMPUTE_A_NOT_B; + break; - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__combine_select() */ + case H5S_SELECT_NOTA: /* b_not_a */ + selector = H5S_HYPER_COMPUTE_B_NOT_A; + break; - -/*-------------------------------------------------------------------------- - NAME - H5Scombine_select - PURPOSE - Combine two hyperslab selections with an operation, returning a dataspace - with the resulting selection. - USAGE - hid_t H5Scombine_select(space1, op, space2) - hid_t space1; IN: First Dataspace ID - H5S_seloper_t op; IN: Selection operation - hid_t space2; IN: Second Dataspace ID - RETURNS - Dataspace ID on success / H5I_INVALID_HID on failure - DESCRIPTION - Combine two existing hyperslab selections with an operation, returning - a new dataspace with the resulting selection. The dataspace extent from - space1 is copied for the dataspace extent of the newly created dataspace. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -hid_t -H5Scombine_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id) -{ - H5S_t *space1; /* First Dataspace */ - H5S_t *space2; /* Second Dataspace */ - H5S_t *new_space = NULL; /* New Dataspace */ - hid_t ret_value; /* Return value */ + case H5S_SELECT_NOOP: + case H5S_SELECT_SET: + case H5S_SELECT_APPEND: + case H5S_SELECT_PREPEND: + case H5S_SELECT_INVALID: + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ - FUNC_ENTER_API(FAIL) - H5TRACE3("i", "iSsi", space1_id, op, space2_id); + /* Generate lists of spans which overlap and don't overlap */ + if(H5S__hyper_clip_spans(space1->select.sel_info.hslab->span_lst, + space2_span_lst, selector, space1->extent.rank, + &a_not_b, &a_and_b, &b_not_a) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") + switch(op) { + case H5S_SELECT_OR: + if(is_result_new) + (*result)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(space1->select.sel_info.hslab->span_lst, space1->extent.rank); + break; - /* Check args */ - if(NULL == (space1 = (H5S_t *)H5I_object_verify(space1_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") - if(NULL == (space2 = (H5S_t *)H5I_object_verify(space2_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") - if(!(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA)) - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + case H5S_SELECT_AND: + case H5S_SELECT_XOR: + case H5S_SELECT_NOTB: + case H5S_SELECT_NOTA: + if(!is_result_new) { + HDassert(space1 == *result); + + /* Free the current selection */ + H5S__hyper_free_span_info(space1->select.sel_info.hslab->span_lst); + space1->select.sel_info.hslab->span_lst = NULL; + } /* end if */ + + /* Reset the number of items in selection */ + /* (Will be set below) */ + (*result)->select.num_elem = 0; + break; + + case H5S_SELECT_NOOP: + case H5S_SELECT_SET: + case H5S_SELECT_APPEND: + case H5S_SELECT_PREPEND: + case H5S_SELECT_INVALID: + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ + + /* Check if there are any non-overlapped selections */ + if(a_not_b) { + /* Other than OR, the span_lst is set to NULL. And in OR, + * a_not_b is not needed + */ + HDassert(NULL == (*result)->select.sel_info.hslab->span_lst); + + /* The results dataspace takes ownership of the spans */ + /* (Since it must be NULL) */ + (*result)->select.sel_info.hslab->span_lst = a_not_b; + + /* Update the number of elements in current selection */ + (*result)->select.num_elem = H5S__hyper_spans_nelem(a_not_b); + + /* Indicate that the spans were updated */ + *updated_spans = TRUE; + + /* Indicate that the a_not_b spans are owned */ + a_not_b = NULL; + } /* end if */ - /* Check that both dataspaces have the same rank */ - if(space1->extent.rank != space2->extent.rank) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same rank") + if(a_and_b) { + /** + * 1. Other than OR, the span_lst is set to NULL. And in OR, + * a_and_b is not needed + * 2. a_not_b will never be computed together with a_and_b + * because merging these two equals to a. + */ + HDassert(NULL == (*result)->select.sel_info.hslab->span_lst); - /* Check that both dataspaces have hyperslab selections */ - if(H5S_GET_SELECT_TYPE(space1) != H5S_SEL_HYPERSLABS || H5S_GET_SELECT_TYPE(space2) != H5S_SEL_HYPERSLABS) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces don't have hyperslab selections") + /* The results dataspace takes ownership of the spans */ + /* (Since it must be NULL) */ + (*result)->select.sel_info.hslab->span_lst = a_and_b; - /* Go combine the dataspaces */ - if(NULL == (new_space = H5S__combine_select(space1, op, space2))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to create hyperslab selection") + /* Update the number of elements in current selection */ + (*result)->select.num_elem = H5S__hyper_spans_nelem(a_and_b); - /* Atomize */ - if((ret_value = H5I_register(H5I_DATASPACE, new_space, TRUE)) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom") + /* Indicate that the spans were updated */ + *updated_spans = TRUE; + + /* Indicate that the a_and_b spans are owned */ + a_and_b = NULL; + } /* end if */ + + if(b_not_a) { + /* Merge the b_not_a spans into the result dataspace */ + if(H5S__hyper_merge_spans(*result, b_not_a) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + + /* Update the number of elements in current selection */ + (*result)->select.num_elem += H5S__hyper_spans_nelem(b_not_a); + + /* Indicate that the spans were updated */ + *updated_spans = TRUE; + } /* end if */ + } /* end else for the case the new span overlaps with the old (i.e. space) */ + + /* Check if the spans weren't updated, and reset selection if so */ + if(!*updated_spans) { + /* If updated_spans remains FALSE as in this branch, it means the + * result has been cleared in XOR / AND / NOTB / NOTA cases, and the + * result is a copy of the dataspace in the OR case. + * + * If two dataspaces have generated any of the three clipped + * span trees (i.e. a_not_b, a_and_b, and b_not_a), the + * updated_spans must be TRUE. + */ + if(H5S_SELECT_OR != op) { + /* Convert *result to "none" selection */ + if(H5S_select_none(*result) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection") + } /* end else */ + } /* end if */ done: - if(ret_value < 0 && new_space) - H5S_close(new_space); + /* Free resources */ + if(a_not_b) + H5S__hyper_free_span_info(a_not_b); + if(a_and_b) + H5S__hyper_free_span_info(a_and_b); + if(b_not_a) + H5S__hyper_free_span_info(b_not_a); - FUNC_LEAVE_API(ret_value) -} /* end H5Scombine_select() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__fill_in_new_space() */ /*------------------------------------------------------------------------- - * Function: H5S__modify_select + * Function: H5S__generate_hyperlab * - * Purpose: Internal version of H5Sselect_select(). + * Purpose: Generate hyperslab information from H5S_select_hyperslab() * - * Return: New dataspace on success/NULL on failure + * Return: Non-negative on success/Negative on failure * * Programmer: Quincey Koziol - * Tuesday, October 30, 2001 + * Tuesday, September 12, 2000 * *------------------------------------------------------------------------- */ -herr_t -H5S__modify_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2) +static herr_t +H5S__generate_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[], + const hsize_t stride[], const hsize_t count[], const hsize_t block[]) { - H5S_hyper_span_info_t *tmp_spans = NULL; /* Temporary copy of selection */ - hbool_t span2_owned=FALSE; /* Flag to indicate that span2 was used in H5S_operate_hyperslab() */ - herr_t ret_value = SUCCEED; /* Return value */ + H5S_hyper_span_info_t *new_spans = NULL; /* Span tree for new hyperslab */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_PACKAGE + FUNC_ENTER_STATIC /* Check args */ - HDassert(space1); - HDassert(space2); + HDassert(space); HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + HDassert(start); + HDassert(stride); + HDassert(count); + HDassert(block); - /* Check that the space selections both have span trees */ - if(space1->select.sel_info.hslab->span_lst==NULL) - if(H5S__hyper_generate_spans(space1)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") - if(space2->select.sel_info.hslab->span_lst==NULL) - if(H5S__hyper_generate_spans(space2)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") - - /* Take ownership of the dataspace's hyperslab spans */ - /* (These are freed later) */ - tmp_spans=space1->select.sel_info.hslab->span_lst; - space1->select.sel_info.hslab->span_lst=NULL; - - /* Reset the other dataspace selection information */ - if(H5S_SELECT_RELEASE(space1)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") - - /* Allocate space for the hyperslab selection information */ - if((space1->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)) == NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info") - space1->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; - - /* Set unlim_dim */ - space1->select.sel_info.hslab->unlim_dim = -1; + /* Generate span tree for new hyperslab information */ + if(NULL == (new_spans = H5S__hyper_make_spans(space->extent.rank, start, stride, count, block))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information") - /* Combine tmp_spans (from space1) & spans from space2, with the result in space1 */ - if(H5S_operate_hyperslab(space1,tmp_spans,op,space2->select.sel_info.hslab->span_lst,FALSE,&span2_owned)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") + /* Generate list of blocks to add/remove based on selection operation */ + if(op == H5S_SELECT_SET) { + /* Free current selection */ + if(NULL != space->select.sel_info.hslab->span_lst) + H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst); -done: - if(tmp_spans!=NULL) - H5S__hyper_free_span_info(tmp_spans); + /* Set the hyperslab selection to the new span tree */ + space->select.sel_info.hslab->span_lst = new_spans; - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__modify_select() */ + /* Set the number of elements in current selection */ + space->select.num_elem = H5S__hyper_spans_nelem(new_spans); - -/*-------------------------------------------------------------------------- - NAME - H5Sselect_select - PURPOSE - Refine a hyperslab selection with an operation using a second hyperslab - to modify it - USAGE - herr_t H5Sselect_select(space1, op, space2) - hid_t space1; IN/OUT: First Dataspace ID - H5S_seloper_t op; IN: Selection operation - hid_t space2; IN: Second Dataspace ID - RETURNS - Non-negative on success/Negative on failure - DESCRIPTION - Refine an existing hyperslab selection with an operation, using a second - hyperslab. The first selection is modified to contain the result of - space1 operated on by space2. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -herr_t -H5Sselect_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id) -{ - H5S_t *space1; /* First Dataspace */ - H5S_t *space2; /* Second Dataspace */ - herr_t ret_value = SUCCEED; /* Return value */ + /* Indicate that the new_spans are owned */ + new_spans = NULL; + } /* end if */ + else { + hbool_t new_spans_owned = FALSE; + hbool_t updated_spans = FALSE; - FUNC_ENTER_API(FAIL) - H5TRACE3("e", "iSsi", space1_id, op, space2_id); + /* Generate new spans for space */ + if(H5S__fill_in_new_space(space, op, new_spans, TRUE, &new_spans_owned, &updated_spans, &space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't generate the specified hyperslab") - /* Check args */ - if(NULL == (space1 = (H5S_t *)H5I_object_verify(space1_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") - if(NULL == (space2 = (H5S_t *)H5I_object_verify(space2_id, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") - if(!(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA)) - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + /* Check if the spans were updated by H5S__fill_in_new_space */ + if(updated_spans) { + H5S_hyper_dim_t new_hyper_diminfo[H5S_MAX_RANK]; + unsigned u; /* Local index variable */ - /* Check that both dataspaces have the same rank */ - if(space1->extent.rank != space2->extent.rank) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same rank") + /* Sanity check */ + HDassert(space->select.sel_info.hslab->span_lst->head); + + /* Build diminfo struct */ + for(u = 0; u extent.rank; u++) { + new_hyper_diminfo[u].start = start[u]; + new_hyper_diminfo[u].stride = stride[u]; + new_hyper_diminfo[u].count = count[u]; + new_hyper_diminfo[u].block = block[u]; + } /* end for */ - /* Check that both dataspaces have hyperslab selections */ - if(H5S_GET_SELECT_TYPE(space1) != H5S_SEL_HYPERSLABS || H5S_GET_SELECT_TYPE(space2) != H5S_SEL_HYPERSLABS) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces don't have hyperslab selections") + /* Update space's dim info */ + if(H5S__hyper_update_diminfo(space, op, new_hyper_diminfo) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't update hyperslab info") + } /* end if */ - /* Go refine the first selection */ - if(H5S__modify_select(space1, op, space2) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to modify hyperslab selection") + /* Indicate that the new_spans are owned, there's no need to free */ + if(new_spans_owned) + new_spans = NULL; + } /* end else */ done: - FUNC_LEAVE_API(ret_value) -} /* end H5Sselect_select() */ -#endif /* NEW_HYPERSLAB_API */ /* Works */ + if(new_spans) + H5S__hyper_free_span_info(new_spans); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__generate_hyperslab() */ -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_get_seq_list_gen - PURPOSE - Create a list of offsets & lengths for a selection - USAGE - herr_t H5S_select_hyper_get_file_list_gen(space,iter,maxseq,maxelem,nseq,nelem,off,len) - H5S_t *space; IN: Dataspace containing selection to use. - H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last - position of interest in selection. - size_t maxseq; IN: Maximum number of sequences to generate - size_t maxelem; IN: Maximum number of elements to include in the - generated sequences - size_t *nseq; OUT: Actual number of sequences generated - size_t *nelem; OUT: Actual number of elements in sequences generated - hsize_t *off; OUT: Array of offsets - size_t *len; OUT: Array of lengths - RETURNS - Non-negative on success/Negative on failure. - DESCRIPTION - Use the selection in the dataspace to generate a list of byte offsets and - lengths for the region(s) selected. Start/Restart from the position in the - ITER parameter. The number of sequences generated is limited by the MAXSEQ - parameter and the number of sequences actually generated is stored in the - NSEQ parameter. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_get_seq_list_gen(const H5S_t *space, H5S_sel_iter_t *iter, - size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem, - hsize_t *off, size_t *len) +/*------------------------------------------------------------------------- + * Function: H5S__set_regular_hyperslab + * + * Purpose: Set a regular hyperslab + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Thursday, October 2, 2014 + * + *------------------------------------------------------------------------- + */ +herr_t +H5S__set_regular_hyperslab(H5S_t *space, const hsize_t start[], + const hsize_t *app_stride, const hsize_t app_count[], const hsize_t *app_block, + const hsize_t *opt_stride, const hsize_t opt_count[], const hsize_t *opt_block) { - H5S_hyper_span_t *curr_span; /* Current hyperslab span node */ - H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */ - hsize_t slab[H5S_MAX_RANK]; /* Cumulative size of each dimension in bytes */ - hsize_t acc; /* Accumulator for computing cumulative sizes */ - hsize_t loc_off; /* Element offset in the dataspace */ - hsize_t last_span_end = 0; /* The offset of the end of the last span */ - hsize_t *abs_arr; /* Absolute hyperslab span position */ - const hssize_t *off_arr; /* Offset within the dataspace extent */ - size_t span_size = 0; /* Number of bytes in current span to actually process */ - size_t io_left; /* Number of elements left to process */ - size_t io_bytes_left; /* Number of bytes left to process */ - size_t io_used; /* Number of elements processed */ - size_t curr_seq = 0; /* Number of sequence/offsets stored in the arrays */ - size_t elem_size; /* Size of each element iterating over */ - unsigned ndims; /* Number of dimensions of dataset */ - unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ - int curr_dim; /* Current dimension being operated on */ - unsigned u; /* Index variable */ - int i; /* Index variable */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_STATIC_NOERR + FUNC_ENTER_STATIC /* Check args */ HDassert(space); - HDassert(iter); - HDassert(maxseq > 0); - HDassert(maxelem > 0); - HDassert(nseq); - HDassert(nelem); - HDassert(off); - HDassert(len); - - /* Set the rank of the fastest changing dimension */ - ndims = space->extent.rank; - fast_dim = (ndims - 1); - - /* Get the pointers to the current span info and span nodes */ - curr_span = iter->u.hyp.span[fast_dim]; - abs_arr = iter->u.hyp.off; - off_arr = space->select.offset; - ispan = iter->u.hyp.span; - elem_size = iter->elmt_size; + HDassert(start); + HDassert(app_stride); + HDassert(app_count); + HDassert(app_block); + HDassert(opt_stride); + HDassert(opt_count); + HDassert(opt_block); + + /* If we are setting a new selection, remove current selection first */ + if(H5S_SELECT_RELEASE(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") - /* Set the amount of elements to perform I/O on, etc. */ - H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t); - io_left = MIN(maxelem, (size_t)iter->elmt_left); - io_bytes_left = io_left * elem_size; + /* Allocate space for the hyperslab selection information */ + if(NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info") - /* Compute the cumulative size of dataspace dimensions */ - for(i = (int)fast_dim, acc = elem_size; i >= 0; i--) { - slab[i] = acc; - acc *= space->extent.size[i]; + /* Set the diminfo */ + space->select.num_elem = 1; + space->select.sel_info.hslab->unlim_dim = -1; + for(u = 0; u < space->extent.rank; u++) { + /* Set application and optimized hyperslab info */ + space->select.sel_info.hslab->diminfo.app[u].start = start[u]; + space->select.sel_info.hslab->diminfo.app[u].stride = app_stride[u]; + space->select.sel_info.hslab->diminfo.app[u].count = app_count[u]; + space->select.sel_info.hslab->diminfo.app[u].block = app_block[u]; + + space->select.sel_info.hslab->diminfo.opt[u].start = start[u]; + space->select.sel_info.hslab->diminfo.opt[u].stride = opt_stride[u]; + space->select.sel_info.hslab->diminfo.opt[u].count = opt_count[u]; + space->select.sel_info.hslab->diminfo.opt[u].block = opt_block[u]; + + /* Update # of elements selected */ + space->select.num_elem *= (opt_count[u] * opt_block[u]); + + /* Set low bound of bounding box for the hyperslab selection */ + space->select.sel_info.hslab->diminfo.low_bounds[u] = start[u]; + + /* Check for unlimited dimension & set high bound */ + if((app_count[u] == H5S_UNLIMITED) || (app_block[u] == H5S_UNLIMITED)) { + space->select.sel_info.hslab->unlim_dim = (int)u; + space->select.sel_info.hslab->diminfo.high_bounds[u] = H5S_UNLIMITED; + } /* end if */ + else + space->select.sel_info.hslab->diminfo.high_bounds[u] = start[u] + opt_stride[u] * (opt_count[u] - 1) + (opt_block[u] - 1); } /* end for */ - /* Set the offset of the first element iterated on */ - for(u = 0, loc_off = 0; u < ndims; u++) - /* Compute the sequential element offset */ - loc_off += ((hsize_t)((hssize_t)abs_arr[u] + off_arr[u])) * slab[u]; - - /* Range check against number of elements left in selection */ - HDassert(io_bytes_left <= (iter->elmt_left * elem_size)); - - /* Take care of any partial spans leftover from previous I/Os */ - if(abs_arr[fast_dim]!=curr_span->low) { + /* Handle unlimited selections */ + if(space->select.sel_info.hslab->unlim_dim >= 0) { + /* Calculate num_elem_non_unlim */ + space->select.sel_info.hslab->num_elem_non_unlim = (hsize_t)1; + for(u = 0; u < space->extent.rank; u++) + if((int)u != space->select.sel_info.hslab->unlim_dim) + space->select.sel_info.hslab->num_elem_non_unlim *= (opt_count[u] * opt_block[u]); - /* Finish the span in the fastest changing dimension */ + /* Update num_elem */ + space->select.num_elem = H5S_UNLIMITED; + } /* end if */ - /* Compute the number of bytes to attempt in this span */ - H5_CHECKED_ASSIGN(span_size, size_t, ((curr_span->high-abs_arr[fast_dim])+1)*elem_size, hsize_t); + /* Indicate that the dimension information is valid */ + space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES; - /* Check number of bytes against upper bounds allowed */ - if(span_size>io_bytes_left) - span_size=io_bytes_left; + /* Indicate that there's no slab information */ + space->select.sel_info.hslab->span_lst = NULL; - /* Add the partial span to the list of sequences */ - off[curr_seq]=loc_off; - len[curr_seq]=span_size; + /* Set selection type */ + space->select.type = H5S_sel_hyper; - /* Increment sequence count */ - curr_seq++; +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__set_regular_hyperslab() */ - /* Set the location of the last span's end */ - last_span_end=loc_off+span_size; - /* Decrement I/O left to perform */ - io_bytes_left-=span_size; +/*------------------------------------------------------------------------- + * Function: H5S__hyper_regular_and_single_block + * + * Purpose: Optimized routine to perform "AND" operation of a single + * block against a regular hyperslab selection. + * + * Note: This algorithm is invoked when constructing the chunk map + * and a regular hyperslab is selected in the file's dataspace. + * + * Return: Non-negative on success / Negative on failure + * + * Programmer: Quincey Koziol + * Saturday, February 9, 2019 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S__hyper_regular_and_single_block(H5S_t *space, const hsize_t start[], + const hsize_t block[]) +{ + hsize_t select_end, block_end; /* End of block & selection */ + hbool_t single_block; /* Whether the selection is a single block */ + hbool_t overlap; /* Whether block & selection overlap */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Advance the hyperslab iterator */ - /* Check if we are done */ - if(io_bytes_left > 0) { - /* Move to next span in fastest changing dimension */ - curr_span = curr_span->next; + FUNC_ENTER_NOAPI(FAIL) - if(NULL != curr_span) { - /* Move location offset of destination */ - loc_off += (curr_span->low - abs_arr[fast_dim]) * elem_size; + /* Check args */ + HDassert(space); + HDassert(start); + HDassert(block); - /* Move iterator for fastest changing dimension */ - abs_arr[fast_dim] = curr_span->low; - } /* end if */ + /* Check for single block selection in dataspace */ + single_block = TRUE; + for(u = 0; u < space->extent.rank; u++) + if(1 != space->select.sel_info.hslab->diminfo.opt[u].count) { + single_block = FALSE; + break; } /* end if */ - else { - abs_arr[fast_dim] += span_size / elem_size; - /* Check if we are still within the span */ - if(abs_arr[fast_dim] <= curr_span->high) { - iter->u.hyp.span[fast_dim] = curr_span; + /* Perform different optimizations, based on type of regular selection */ + if(single_block) { + hsize_t new_start[H5S_MAX_RANK]; /* New starting coordinate */ + hsize_t new_block[H5S_MAX_RANK]; /* New block size */ + + /* Check for overlap and compute new start offset & block sizes */ + overlap = TRUE; + for(u = 0; u < space->extent.rank; u++) { + /* Compute the end of the selection & block in this dimension */ + select_end = space->select.sel_info.hslab->diminfo.high_bounds[u]; + block_end = (start[u] + block[u]) - 1; + + /* Check for overlap */ + if(!H5S_RANGE_OVERLAP(space->select.sel_info.hslab->diminfo.opt[u].start, select_end, start[u], block_end)) { + overlap = FALSE; + break; } /* end if */ - /* If we walked off that span, advance to the next span */ - else { - /* Advance span in this dimension */ - curr_span = curr_span->next; - /* Check if we have a valid span in this dimension still */ - if(NULL != curr_span) { - /* Reset absolute position */ - abs_arr[fast_dim] = curr_span->low; - iter->u.hyp.span[fast_dim] = curr_span; - } /* end if */ - } /* end else */ - } /* end else */ + /* Set new start & block size in this dimension */ + new_start[u] = MAX(space->select.sel_info.hslab->diminfo.opt[u].start, start[u]); + new_block[u] = (MIN(select_end, block_end) - new_start[u]) + 1; + } /* end for */ - /* Adjust iterator pointers */ + /* Check for overlap of selection & block */ + if(overlap) { + /* Set selection to regular hyperslab */ + if(H5S__set_regular_hyperslab(space, new_start, H5S_hyper_ones_g, H5S_hyper_ones_g, new_block, + H5S_hyper_ones_g, H5S_hyper_ones_g, new_block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular hyperslab selection") + } /* end if */ + else + /* Selection & block don't overlap, set to "none" selection */ + if(H5S_select_none(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection") + } /* end if */ + else { + hsize_t new_start[H5S_MAX_RANK]; /* New start for hyperslab selection */ + hsize_t new_count[H5S_MAX_RANK]; /* New count for hyperslab selection */ + hsize_t stride[H5S_MAX_RANK]; /* Stride for hyperslab selection */ + hsize_t new_block[H5S_MAX_RANK]; /* New block for hyperslab selection */ + hbool_t partial_first_span; /* Whether first span in intersection is partial */ + hbool_t partial_last_span; /* Whether last span in intersection is partial */ + + /* Iterate over selection, checking for overlap and computing first / last + * span that intersects with the block. + */ + overlap = TRUE; + partial_first_span = FALSE; + partial_last_span = FALSE; + for(u = 0; u < space->extent.rank; u++) { + hsize_t first_span_start, first_span_end; /* Start / end of first span */ + hsize_t last_span_start, last_span_end; /* Start / end of last span */ + hsize_t nstride; /* Number of strides into the selection */ - if(NULL == curr_span) { -/* Same as code in main loop */ - /* Start at the next fastest dim */ - curr_dim = (int)(fast_dim - 1); + /* Compute the end of the selection & block in this dimension */ + select_end = space->select.sel_info.hslab->diminfo.high_bounds[u]; + block_end = (start[u] + block[u]) - 1; - /* Work back up through the dimensions */ - while(curr_dim >= 0) { - /* Reset the current span */ - curr_span = iter->u.hyp.span[curr_dim]; + /* Check for overlap */ + if(!H5S_RANGE_OVERLAP(space->select.sel_info.hslab->diminfo.opt[u].start, select_end, start[u], block_end)) { + overlap = FALSE; + break; + } /* end if */ - /* Increment absolute position */ - abs_arr[curr_dim]++; + /* Find first span that is before or overlaps with start of block */ + if(space->select.sel_info.hslab->diminfo.opt[u].start >= start[u]) { + /* Calculate start & end of first span */ + first_span_start = space->select.sel_info.hslab->diminfo.opt[u].start; + first_span_end = (first_span_start + + space->select.sel_info.hslab->diminfo.opt[u].block) - 1; - /* Check if we are still within the span */ - if(abs_arr[curr_dim] <= curr_span->high) { - break; - } /* end if */ - /* If we walked off that span, advance to the next span */ - else { - /* Advance span in this dimension */ - curr_span = curr_span->next; + /* Check if first span overlaps _end_ of block */ + if(block_end >= first_span_start && block_end <= first_span_end) + partial_first_span = TRUE; + } /* end if */ + else { + hsize_t adj_start; /* Start coord, adjusted for hyperslab selection parameters */ - /* Check if we have a valid span in this dimension still */ - if(NULL != curr_span) { - /* Reset the span in the current dimension */ - ispan[curr_dim] = curr_span; + /* Adjust start coord for selection's 'start' offset */ + adj_start = start[u] - space->select.sel_info.hslab->diminfo.opt[u].start; - /* Reset absolute position */ - abs_arr[curr_dim] = curr_span->low; + /* Compute # of strides into the selection */ + if(space->select.sel_info.hslab->diminfo.opt[u].count > 1) + nstride = adj_start / space->select.sel_info.hslab->diminfo.opt[u].stride; + else + nstride = 0; - break; - } /* end if */ - else { - /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */ - curr_dim--; - } /* end else */ - } /* end else */ - } /* end while */ + /* Calculate start & end of first span */ + first_span_start = space->select.sel_info.hslab->diminfo.opt[u].start + + (nstride * space->select.sel_info.hslab->diminfo.opt[u].stride); + first_span_end = (first_span_start + + space->select.sel_info.hslab->diminfo.opt[u].block) - 1; - /* Check if we have more spans in the tree */ - if(curr_dim >= 0) { - /* Walk back down the iterator positions, resetting them */ - while((unsigned)curr_dim < fast_dim) { - HDassert(curr_span); - HDassert(curr_span->down); - HDassert(curr_span->down->head); + /* Check if first span overlaps start of block */ + if(first_span_start < start[u] && first_span_end >= start[u]) + partial_first_span = TRUE; - /* Increment current dimension */ - curr_dim++; + /* Advance first span to start higher than block's start, + * if it's not partial. + */ + if(first_span_end < start[u]) { + first_span_start += space->select.sel_info.hslab->diminfo.opt[u].stride; + first_span_end += space->select.sel_info.hslab->diminfo.opt[u].stride; + } /* end if */ + } /* end else */ - /* Set the new span_info & span for this dimension */ - iter->u.hyp.span[curr_dim] = curr_span->down->head; + /* Find last span that is before or overlaps with end of block */ + if(select_end < block_end) { + /* Calculate start & end of last span */ + last_span_start = (select_end - + space->select.sel_info.hslab->diminfo.opt[u].block) + 1; + last_span_end = select_end; - /* Advance span down the tree */ - curr_span = curr_span->down->head; + /* Check if last span overlaps _start_ of block */ + if(start[u] >= last_span_start && start[u] <= last_span_end) + partial_last_span = TRUE; + } /* end if */ + else { + hsize_t adj_end; /* End coord, adjusted for hyperslab selection parameters */ - /* Reset the absolute offset for the dim */ - abs_arr[curr_dim] = curr_span->low; - } /* end while */ + /* Adjust end coord for selection's 'start' offset */ + adj_end = block_end - space->select.sel_info.hslab->diminfo.opt[u].start; - /* Verify that the curr_span points to the fastest dim */ - HDassert(curr_span == iter->u.hyp.span[fast_dim]); + /* Compute # of strides into the selection */ + if(space->select.sel_info.hslab->diminfo.opt[u].count > 1) + nstride = adj_end / space->select.sel_info.hslab->diminfo.opt[u].stride; + else + nstride = 0; - /* Reset the buffer offset */ - for(u = 0, loc_off = 0; u < ndims; u++) - loc_off += ((hsize_t)((hssize_t)abs_arr[u] + off_arr[u])) * slab[u]; + /* Calculate start & end of last span */ + last_span_start = space->select.sel_info.hslab->diminfo.opt[u].start + + (nstride * space->select.sel_info.hslab->diminfo.opt[u].stride); + last_span_end = (last_span_start + + space->select.sel_info.hslab->diminfo.opt[u].block) - 1; + + /* Check if last span overlaps end of block */ + if(block_end >= last_span_start && block_end <= last_span_end) + partial_last_span = TRUE; } /* end else */ - else - /* We had better be done with I/O or bad things are going to happen... */ - HDassert(io_bytes_left == 0); - } /* end if */ - } /* end if */ - /* Perform the I/O on the elements, based on the position of the iterator */ - while(io_bytes_left > 0 && curr_seq < maxseq) { - /* Sanity check */ - HDassert(curr_span); + /* Check if no spans are inside block */ + /* (Can happen when block falls in "gap" between spans) */ + if(last_span_end < start[u]) { + overlap = FALSE; + break; + } /* end if */ - /* Adjust location offset of destination to compensate for initial increment below */ - loc_off -= curr_span->pstride; + /* Sanity check */ + HDassert(first_span_start <= last_span_start); - /* Loop over all the spans in the fastest changing dimension */ - while(curr_span != NULL) { - /* Move location offset of destination */ - loc_off += curr_span->pstride; + /* Compute new start / count / block values */ + new_start[u] = first_span_start; + if(last_span_start != first_span_start) + new_count[u] = ((last_span_start - first_span_start) / + space->select.sel_info.hslab->diminfo.opt[u].stride) + 1; + else + new_count[u] = 1; + new_block[u] = space->select.sel_info.hslab->diminfo.opt[u].block; - /* Compute the number of elements to attempt in this span */ - H5_CHECKED_ASSIGN(span_size, size_t, curr_span->nelem, hsize_t); + /* Keep same stride */ + stride[u] = space->select.sel_info.hslab->diminfo.opt[u].stride; + } /* end for */ - /* Check number of elements against upper bounds allowed */ - if(span_size >= io_bytes_left) { - /* Trim the number of bytes to output */ - span_size = io_bytes_left; - io_bytes_left = 0; + /* Check for overlap of selection & block */ + if(overlap) { + /* Set selection to regular hyperslab */ + if(H5S__set_regular_hyperslab(space, new_start, stride, new_count, new_block, + stride, new_count, new_block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular hyperslab selection") -/* COMMON */ - /* Store the I/O information for the span */ + /* If there's a partial first or last span, have to 'AND' against selection */ + if(partial_first_span || partial_last_span) { + /* Generate span tree for regular selection */ + if(H5S__hyper_generate_spans(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") - /* Check if this is appending onto previous sequence */ - if(curr_seq > 0 && last_span_end == loc_off) - len[curr_seq - 1] += span_size; - else { - off[curr_seq] = loc_off; - len[curr_seq] = span_size; + /* 'AND' against block */ + if(H5S__generate_hyperslab(space, H5S_SELECT_AND, start, H5S_hyper_ones_g, H5S_hyper_ones_g, block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs") + } /* end if */ + } /* end if */ + else { + /* Selection & block don't overlap, set to "none" selection */ + if(H5S_select_none(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection") + } /* end else */ + } /* end else */ - /* Increment the number of sequences in arrays */ - curr_seq++; - } /* end else */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_regular_and_single_block() */ - /* Set the location of the last span's end */ - last_span_end = loc_off + span_size; -/* end COMMON */ + +/*------------------------------------------------------------------------- + * Function: H5S_select_hyperslab + * + * Purpose: Internal version of H5Sselect_hyperslab(). + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, January 10, 2001 + * + *------------------------------------------------------------------------- + */ +herr_t +H5S_select_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[], + const hsize_t *stride, const hsize_t count[], const hsize_t *block) +{ + hsize_t int_stride[H5S_MAX_RANK]; /* Internal storage for stride information */ + hsize_t int_count[H5S_MAX_RANK]; /* Internal storage for count information */ + hsize_t int_block[H5S_MAX_RANK]; /* Internal storage for block information */ + const hsize_t *opt_stride; /* Optimized stride information */ + const hsize_t *opt_count; /* Optimized count information */ + const hsize_t *opt_block; /* Optimized block information */ + int unlim_dim = -1; /* Unlimited dimension in selection, of -1 if none */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Break out now, we are finished with I/O */ - break; - } /* end if */ - else { - /* Decrement I/O left to perform */ - io_bytes_left -= span_size; + FUNC_ENTER_NOAPI(FAIL) -/* COMMON */ - /* Store the I/O information for the span */ + /* Check args */ + HDassert(space); + HDassert(start); + HDassert(count); + HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); - /* Check if this is appending onto previous sequence */ - if(curr_seq > 0 && last_span_end == loc_off) - len[curr_seq-1]+=span_size; - else { - off[curr_seq] = loc_off; - len[curr_seq] = span_size; + /* Point to the correct stride values */ + if(stride == NULL) + stride = H5S_hyper_ones_g; - /* Increment the number of sequences in arrays */ - curr_seq++; - } /* end else */ + /* Point to the correct block values */ + if(block == NULL) + block = H5S_hyper_ones_g; - /* Set the location of the last span's end */ - last_span_end = loc_off + span_size; -/* end COMMON */ + /* Check new selection */ + for(u = 0; u < space->extent.rank; u++) { + /* Check for overlapping hyperslab blocks in new selection. */ + if(count[u] > 1 && stride[u] < block[u]) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab blocks overlap") - /* If the sequence & offset arrays are full, do what? */ - if(curr_seq >= maxseq) { - /* Break out now, we are finished with sequences */ - break; - } /* end else */ - } /* end else */ + /* Detect zero-sized hyperslabs in new selection */ + if(count[u] == 0 || block[u] == 0) { + switch(op) { + case H5S_SELECT_SET: /* Select "set" operation */ + case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ + case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */ + /* Convert to "none" selection */ + if(H5S_select_none(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection") + HGOTO_DONE(SUCCEED); - /* Move to next span in fastest changing dimension */ - curr_span=curr_span->next; - } /* end while */ + case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ + case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */ + case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */ + HGOTO_DONE(SUCCEED); /* Selection stays same */ - /* Check if we are done */ - if(io_bytes_left==0 || curr_seq>=maxseq) { - HDassert(curr_span); - abs_arr[fast_dim]=curr_span->low+(span_size/elem_size); + case H5S_SELECT_NOOP: + case H5S_SELECT_APPEND: + case H5S_SELECT_PREPEND: + case H5S_SELECT_INVALID: + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ + } /* end if */ - /* Check if we are still within the span */ - if(abs_arr[fast_dim]<=curr_span->high) { - iter->u.hyp.span[fast_dim]=curr_span; - break; - } /* end if */ - /* If we walked off that span, advance to the next span */ + /* Check for unlimited dimension */ + if((count[u] == H5S_UNLIMITED) || (block[u] == H5S_UNLIMITED)) { + if(unlim_dim >= 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot have more than one unlimited dimension in selection") else { - /* Advance span in this dimension */ - curr_span=curr_span->next; - - /* Check if we have a valid span in this dimension still */ - if(curr_span!=NULL) { - /* Reset absolute position */ - abs_arr[fast_dim]=curr_span->low; - iter->u.hyp.span[fast_dim]=curr_span; - break; - } /* end if */ + if(count[u] == block[u]) /* Both are H5S_UNLIMITED */ + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "count and block cannot both be unlimited") + unlim_dim = (int)u; } /* end else */ } /* end if */ + } /* end for */ - /* Adjust iterator pointers */ - - /* Start at the next fastest dim */ - curr_dim = (int)(fast_dim - 1); - - /* Work back up through the dimensions */ - while(curr_dim >= 0) { - /* Reset the current span */ - curr_span=iter->u.hyp.span[curr_dim]; - - /* Increment absolute position */ - abs_arr[curr_dim]++; - - /* Check if we are still within the span */ - if(abs_arr[curr_dim]<=curr_span->high) { - break; + /* Optimize hyperslab parameters to merge contiguous blocks, etc. */ + if(stride == H5S_hyper_ones_g && block == H5S_hyper_ones_g) { + /* Point to existing arrays */ + opt_stride = H5S_hyper_ones_g; + opt_count = H5S_hyper_ones_g; + opt_block = count; + } /* end if */ + else { + /* Point to local arrays */ + opt_stride = int_stride; + opt_count = int_count; + opt_block = int_block; + for(u = 0; u < space->extent.rank; u++) { + /* contiguous hyperslabs have the block size equal to the stride */ + if((stride[u] == block[u]) && (count[u] != H5S_UNLIMITED)) { + int_count[u] = 1; + int_stride[u] = 1; + if(block[u] == 1) + int_block[u] = count[u]; + else + int_block[u] = block[u] * count[u]; } /* end if */ - /* If we walked off that span, advance to the next span */ else { - /* Advance span in this dimension */ - curr_span=curr_span->next; - - /* Check if we have a valid span in this dimension still */ - if(curr_span!=NULL) { - /* Reset the span in the current dimension */ - ispan[curr_dim]=curr_span; - - /* Reset absolute position */ - abs_arr[curr_dim]=curr_span->low; - - break; - } /* end if */ + if(count[u] == 1) + int_stride[u] = 1; else { - /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */ - curr_dim--; + HDassert((stride[u] > block[u]) || + ((stride[u] == block[u]) && (count[u] == H5S_UNLIMITED))); + int_stride[u] = stride[u]; } /* end else */ + int_count[u] = count[u]; + int_block[u] = block[u]; } /* end else */ - } /* end while */ - - /* Check if we are finished with the spans in the tree */ - if(curr_dim < 0) { - /* We had better be done with I/O or bad things are going to happen... */ - HDassert(io_bytes_left == 0); - break; - } /* end if */ - else { - /* Walk back down the iterator positions, resetting them */ - while((unsigned)curr_dim < fast_dim) { - HDassert(curr_span); - HDassert(curr_span->down); - HDassert(curr_span->down->head); - - /* Increment current dimension to the next dimension down */ - curr_dim++; - - /* Set the new span for the next dimension down */ - iter->u.hyp.span[curr_dim] = curr_span->down->head; - - /* Advance span down the tree */ - curr_span = curr_span->down->head; - - /* Reset the absolute offset for the dim */ - abs_arr[curr_dim] = curr_span->low; - } /* end while */ - - /* Verify that the curr_span points to the fastest dim */ - HDassert(curr_span == iter->u.hyp.span[fast_dim]); - } /* end else */ - - /* Reset the buffer offset */ - for(u = 0, loc_off = 0; u < ndims; u++) - loc_off += ((hsize_t)((hssize_t)abs_arr[u] + off_arr[u])) * slab[u]; - } /* end while */ - - /* Decrement number of elements left in iterator */ - io_used = (io_left - (io_bytes_left / elem_size)); - iter->elmt_left -= io_used; - - /* Set the number of sequences generated */ - *nseq = curr_seq; + } /* end for */ + } /* end else */ - /* Set the number of elements used */ - *nelem = io_used; + /* Check for operating on unlimited selection */ + if((H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS) + && (space->select.sel_info.hslab->unlim_dim >= 0) + && (op != H5S_SELECT_SET)) { + /* Check for invalid operation */ + if(unlim_dim >= 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot modify unlimited selection with another unlimited selection") + if(!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTA))) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation on unlimited selection") + HDassert(space->select.sel_info.hslab->diminfo_valid); - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_get_seq_list_gen() */ + /* Clip unlimited selection to include new selection */ + if(H5S_hyper_clip_unlim(space, + start[space->select.sel_info.hslab->unlim_dim] + + ((opt_count[space->select.sel_info.hslab->unlim_dim] - (hsize_t)1) + * opt_stride[space->select.sel_info.hslab->unlim_dim]) + + opt_block[space->select.sel_info.hslab->unlim_dim]) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "failed to clip unlimited selection") - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_get_seq_list_opt - PURPOSE - Create a list of offsets & lengths for a selection - USAGE - herr_t H5S_select_hyper_get_file_list_opt(space,iter,maxseq,maxelem,nseq,nelem,off,len) - H5S_t *space; IN: Dataspace containing selection to use. - H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last - position of interest in selection. - size_t maxseq; IN: Maximum number of sequences to generate - size_t maxelem; IN: Maximum number of elements to include in the - generated sequences - size_t *nseq; OUT: Actual number of sequences generated - size_t *nelem; OUT: Actual number of elements in sequences generated - hsize_t *off; OUT: Array of offsets - size_t *len; OUT: Array of lengths - RETURNS - Non-negative on success/Negative on failure. - DESCRIPTION - Use the selection in the dataspace to generate a list of byte offsets and - lengths for the region(s) selected. Start/Restart from the position in the - ITER parameter. The number of sequences generated is limited by the MAXSEQ - parameter and the number of sequences actually generated is stored in the - NSEQ parameter. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_get_seq_list_opt(const H5S_t *space, H5S_sel_iter_t *iter, - size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem, - hsize_t *off, size_t *len) -{ - hsize_t *mem_size; /* Size of the source buffer */ - hsize_t slab[H5S_MAX_RANK]; /* Hyperslab size */ - const hssize_t *sel_off; /* Selection offset in dataspace */ - hsize_t offset[H5S_MAX_RANK]; /* Coordinate offset in dataspace */ - hsize_t tmp_count[H5S_MAX_RANK];/* Temporary block count */ - hsize_t tmp_block[H5S_MAX_RANK];/* Temporary block offset */ - hsize_t wrap[H5S_MAX_RANK]; /* Bytes to wrap around at the end of a row */ - hsize_t skip[H5S_MAX_RANK]; /* Bytes to skip between blocks */ - const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ - hsize_t fast_dim_start, /* Local copies of fastest changing dimension info */ - fast_dim_stride, - fast_dim_block, - fast_dim_offset; - size_t fast_dim_buf_off; /* Local copy of amount to move fastest dimension buffer offset */ - size_t fast_dim_count; /* Number of blocks left in fastest changing dimension */ - size_t tot_blk_count; /* Total number of blocks left to output */ - size_t act_blk_count; /* Actual number of blocks to output */ - size_t total_rows; /* Total number of entire rows to output */ - size_t curr_rows; /* Current number of entire rows to output */ - unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ - unsigned ndims; /* Number of dimensions of dataset */ - int temp_dim; /* Temporary rank holder */ - hsize_t acc; /* Accumulator */ - hsize_t loc; /* Coordinate offset */ - size_t curr_seq = 0; /* Current sequence being operated on */ - size_t actual_elem; /* The actual number of elements to count */ - size_t actual_bytes;/* The actual number of bytes to copy */ - size_t io_left; /* The number of elements left in I/O operation */ - size_t start_io_left; /* The initial number of elements left in I/O operation */ - size_t elem_size; /* Size of each element iterating over */ - unsigned u; /* Local index variable */ - int i; /* Local index variable */ + /* If an empty space was returned it must be "none" */ + HDassert((space->select.num_elem > (hsize_t)0) || (space->select.type->type == H5S_SEL_NONE)); + } /* end if */ - FUNC_ENTER_STATIC_NOERR + /* Fixup operation for non-hyperslab selections */ + switch(H5S_GET_SELECT_TYPE(space)) { + case H5S_SEL_NONE: /* No elements selected in dataspace */ + switch(op) { + case H5S_SELECT_SET: /* Select "set" operation */ + /* Change "none" selection to hyperslab selection */ + break; - /* Check args */ - HDassert(space); - HDassert(iter); - HDassert(maxseq > 0); - HDassert(maxelem > 0); - HDassert(nseq); - HDassert(nelem); - HDassert(off); - HDassert(len); + case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ + case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */ + case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */ + op = H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */ + break; - /* Set the local copy of the diminfo pointer */ - tdiminfo = iter->u.hyp.diminfo; + case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ + case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */ + HGOTO_DONE(SUCCEED); /* Selection stays "none" */ - /* Check if this is a "flattened" regular hyperslab selection */ - if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < space->extent.rank) { - /* Set the aliases for a few important dimension ranks */ - ndims = iter->u.hyp.iter_rank; - fast_dim = ndims - 1; + case H5S_SELECT_NOOP: + case H5S_SELECT_APPEND: + case H5S_SELECT_PREPEND: + case H5S_SELECT_INVALID: + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ + break; - /* Set the local copy of the selection offset */ - sel_off = iter->u.hyp.sel_off; + case H5S_SEL_ALL: /* All elements selected in dataspace */ + switch(op) { + case H5S_SELECT_SET: /* Select "set" operation */ + /* Change "all" selection to hyperslab selection */ + break; - /* Set up the pointer to the size of the memory space */ - mem_size = iter->u.hyp.size; - } /* end if */ - else { - /* Set the aliases for a few important dimension ranks */ - ndims = space->extent.rank; - fast_dim = ndims - 1; + case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ + HGOTO_DONE(SUCCEED); /* Selection stays "all" */ - /* Set the local copy of the selection offset */ - sel_off = space->select.offset; + case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ + op = H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */ + break; - /* Set up the pointer to the size of the memory space */ - mem_size = space->extent.size; - } /* end else */ + case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */ + case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */ + /* Convert current "all" selection to "real" hyperslab selection */ + /* Then allow operation to proceed */ + { + const hsize_t *tmp_start; /* Temporary start information */ + const hsize_t *tmp_stride; /* Temporary stride information */ + const hsize_t *tmp_count; /* Temporary count information */ + const hsize_t *tmp_block; /* Temporary block information */ - /* initialize row sizes for each dimension */ - elem_size = iter->elmt_size; - for(i = (int)fast_dim, acc = elem_size; i >= 0; i--) { - slab[i] = acc; - acc *= mem_size[i]; - } /* end for */ + /* Set up temporary information for the dimensions */ + tmp_start = H5S_hyper_zeros_g; + tmp_stride = tmp_count = H5S_hyper_ones_g; + tmp_block = space->extent.size; - /* Calculate the number of elements to sequence through */ - H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t); - io_left = MIN((size_t)iter->elmt_left, maxelem); + /* Convert to hyperslab selection */ + if(H5S_select_hyperslab(space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count, tmp_block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection") + } /* end case */ + break; - /* Sanity check that there aren't any "remainder" sequences in process */ - HDassert(!((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride != 0 || - ((iter->u.hyp.off[fast_dim] != tdiminfo[fast_dim].start) && tdiminfo[fast_dim].count == 1))); + case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */ + /* Convert to "none" selection */ + if(H5S_select_none(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection") + HGOTO_DONE(SUCCEED); - /* We've cleared the "remainder" of the previous fastest dimension - * sequence before calling this routine, so we must be at the beginning of - * a sequence. Use the fancy algorithm to compute the offsets and run - * through as many as possible, until the buffer fills up. - */ + case H5S_SELECT_NOOP: + case H5S_SELECT_APPEND: + case H5S_SELECT_PREPEND: + case H5S_SELECT_INVALID: + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ + break; - /* Keep the number of elements we started with */ - start_io_left = io_left; + case H5S_SEL_HYPERSLABS: + /* Hyperslab operation on hyperslab selection, OK */ + break; - /* Compute the arrays to perform I/O on */ + case H5S_SEL_POINTS: /* Can't combine hyperslab operations and point selections currently */ + if(op == H5S_SELECT_SET) /* Allow only "set" operation to proceed */ + break; + /* Else fall through to error */ + H5_ATTR_FALLTHROUGH - /* Copy the location of the point to get */ - /* (Add in the selection offset) */ - for(u = 0; u < ndims; u++) - offset[u] = (hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u]); + case H5S_SEL_ERROR: + case H5S_SEL_N: + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ - /* Compute the current "counts" for this location */ - for(u = 0; u < ndims; u++) { - if(tdiminfo[u].count == 1) { - tmp_count[u] = 0; - tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start; - } /* end if */ - else { - tmp_count[u] = (iter->u.hyp.off[u] - tdiminfo[u].start) / tdiminfo[u].stride; - tmp_block[u] = (iter->u.hyp.off[u] - tdiminfo[u].start) % tdiminfo[u].stride; - } /* end else */ - } /* end for */ + if(op == H5S_SELECT_SET) { + /* Set selection to regular hyperslab */ + if(H5S__set_regular_hyperslab(space, start, stride, count, block, opt_stride, opt_count, opt_block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular hyperslab selection") + } /* end if */ + else if(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA) { + hbool_t single_block; /* Whether the selection is a single block */ - /* Compute the initial buffer offset */ - for(u = 0, loc = 0; u < ndims; u++) - loc += offset[u] * slab[u]; + /* Sanity check */ + HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS); - /* Set the number of elements to write each time */ - H5_CHECKED_ASSIGN(actual_elem, size_t, tdiminfo[fast_dim].block, hsize_t); + /* Handle unlimited selections */ + if(unlim_dim >= 0) { + hsize_t bounds_start[H5S_MAX_RANK]; + hsize_t bounds_end[H5S_MAX_RANK]; + hsize_t tmp_count = opt_count[unlim_dim]; + hsize_t tmp_block = opt_block[unlim_dim]; - /* Set the number of actual bytes */ - actual_bytes = actual_elem * elem_size; + /* Check for invalid operation */ + if(space->select.sel_info.hslab->unlim_dim >= 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot modify unlimited selection with another unlimited selection") + if(!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTB))) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation with unlimited selection") - /* Set local copies of information for the fastest changing dimension */ - fast_dim_start = tdiminfo[fast_dim].start; - fast_dim_stride = tdiminfo[fast_dim].stride; - fast_dim_block = tdiminfo[fast_dim].block; - H5_CHECKED_ASSIGN(fast_dim_buf_off, size_t, slab[fast_dim] * fast_dim_stride, hsize_t); - fast_dim_offset = (hsize_t)((hssize_t)fast_dim_start + sel_off[fast_dim]); + /* Get bounds of existing selection */ + if(H5S__hyper_bounds(space, bounds_start, bounds_end) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds") - /* Compute the number of blocks which would fit into the buffer */ - H5_CHECK_OVERFLOW(io_left / fast_dim_block, hsize_t, size_t); - tot_blk_count = (size_t)(io_left / fast_dim_block); + /* Patch count and block to remove unlimited and include the + * existing selection. + */ + H5S__hyper_get_clip_diminfo(start[unlim_dim], opt_stride[unlim_dim], &tmp_count, &tmp_block, bounds_end[unlim_dim] + (hsize_t)1); + HDassert((tmp_count == 1) || (opt_count != H5S_hyper_ones_g)); + HDassert((tmp_block == 1) || (opt_block != H5S_hyper_ones_g)); + if(opt_count != H5S_hyper_ones_g) { + HDassert(opt_count == int_count); + int_count[unlim_dim] = tmp_count; + } /* end if */ + if(opt_block != H5S_hyper_ones_g) { + HDassert(opt_block == int_block); + int_block[unlim_dim] = tmp_block; + } /* end if */ + } /* end if */ - /* Don't go over the maximum number of sequences allowed */ - tot_blk_count = MIN(tot_blk_count, (maxseq - curr_seq)); + /* Check for a single block selected */ + single_block = TRUE; + for(u = 0; u < space->extent.rank; u++) + if(1 != opt_count[u]) { + single_block = FALSE; + break; + } /* end if */ - /* Compute the amount to wrap at the end of each row */ - for(u = 0; u < ndims; u++) - wrap[u] = (mem_size[u] - (tdiminfo[u].stride * tdiminfo[u].count)) * slab[u]; + /* Check for single block "AND" operation on a regular hyperslab, which + * is used for constructing chunk maps and can be optimized for. + */ + if(H5S_SELECT_AND == op && single_block && + space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + if(H5S__hyper_regular_and_single_block(space, start, opt_block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTOPERATE, FAIL, "can't 'AND' single block against regular hyperslab") + } /* end if */ + else { + /* Check if there's no hyperslab span information currently */ + if(NULL == space->select.sel_info.hslab->span_lst) + if(H5S__hyper_generate_spans(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") - /* Compute the amount to skip between blocks */ - for(u = 0; u < ndims; u++) - skip[u] = (tdiminfo[u].stride - tdiminfo[u].block) * slab[u]; + /* Set selection type */ + space->select.type = H5S_sel_hyper; - /* Check if there is a partial row left (with full blocks) */ - if(tmp_count[fast_dim] > 0) { - /* Get number of blocks in fastest dimension */ - H5_CHECKED_ASSIGN(fast_dim_count, size_t, tdiminfo[fast_dim].count - tmp_count[fast_dim], hsize_t); + /* Add in the new hyperslab information */ + if(H5S__generate_hyperslab(space, op, start, opt_stride, opt_count, opt_block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs") + } /* end else */ + } /* end if */ + else + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - /* Make certain this entire row will fit into buffer */ - fast_dim_count = MIN(fast_dim_count, tot_blk_count); +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_select_hyperslab() */ - /* Number of blocks to sequence over */ - act_blk_count = fast_dim_count; + +/*-------------------------------------------------------------------------- + NAME + H5Sselect_hyperslab + PURPOSE + Specify a hyperslab to combine with the current hyperslab selection + USAGE + herr_t H5Sselect_hyperslab(dsid, op, start, stride, count, block) + hid_t dsid; IN: Dataspace ID of selection to modify + H5S_seloper_t op; IN: Operation to perform on current selection + const hsize_t *start; IN: Offset of start of hyperslab + const hsize_t *stride; IN: Hyperslab stride + const hsize_t *count; IN: Number of blocks included in hyperslab + const hsize_t *block; IN: Size of block in hyperslab + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Combines a hyperslab selection with the current selection for a dataspace. + If the current selection is not a hyperslab, it is freed and the hyperslab + parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a + selection composing the entire current extent). If STRIDE or BLOCK is + NULL, they are assumed to be set to all '1'. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[], + const hsize_t stride[], const hsize_t count[], const hsize_t block[]) +{ + H5S_t *space; /* Dataspace to modify selection of */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Loop over all the blocks in the fastest changing dimension */ - while(fast_dim_count > 0) { - /* Store the sequence information */ - off[curr_seq] = loc; - len[curr_seq] = actual_bytes; + FUNC_ENTER_API(FAIL) + H5TRACE6("e", "iSs*h*h*h*h", space_id, op, start, stride, count, block); - /* Increment sequence count */ - curr_seq++; + /* Check args */ + if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + if(H5S_SCALAR == H5S_GET_EXTENT_TYPE(space)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_SCALAR space") + if(H5S_NULL == H5S_GET_EXTENT_TYPE(space)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_NULL space") + if(start == NULL || count == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified") + if(!(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID)) + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + if(stride != NULL) { + unsigned u; /* Local index variable */ - /* Increment information to reflect block just processed */ - loc += fast_dim_buf_off; + /* Check for 0-sized strides */ + for(u = 0; u < space->extent.rank; u++) + if(stride[u] == 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid stride==0 value") + } /* end if */ - /* Decrement number of blocks */ - fast_dim_count--; - } /* end while */ + if(H5S_select_hyperslab(space, op, start, stride, count, block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection") - /* Decrement number of elements left */ - io_left -= actual_elem * act_blk_count; +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Sselect_hyperslab() */ - /* Decrement number of blocks left */ - tot_blk_count -= act_blk_count; + +/*-------------------------------------------------------------------------- + NAME + H5S_combine_hyperslab + PURPOSE + Specify a hyperslab to combine with the current hyperslab selection, and + store the result in the new hyperslab selection. + USAGE + herr_t H5S_combine_hyperslab(new_space, old_space, op, start, stride, count, block) + H5S_t *old_space; IN: The old space the selection is performed on + H5S_seloper_t op; IN: Operation to perform on current selection + const hsize_t start[]; IN: Offset of start of hyperslab + const hsize_t *stride; IN: Hyperslab stride + const hsize_t count[]; IN: Number of blocks included in hyperslab + const hsize_t *block; IN: Size of block in hyperslab + H5S_t **new_space; OUT: The new dataspace to store the selection result + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Combines a hyperslab selection with the current selection for a dataspace. + If STRIDE or BLOCK is NULL, they are assumed to be set to all '1'. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + In some cases, copying the whole span tree from old_space to new_space + can be avoided. Deal with such cases directly, otherwise this function + is equivalent to: + 1. Copy the whole span tree from old_space into new_space + 2. Call H5S_select_hyperslab with the new_space. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5S_combine_hyperslab(H5S_t *old_space, H5S_seloper_t op, const hsize_t start[], + const hsize_t *stride, const hsize_t count[], const hsize_t *block, + H5S_t **new_space) +{ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Increment information to reflect block just processed */ - tmp_count[fast_dim] += act_blk_count; + FUNC_ENTER_NOAPI(FAIL) - /* Check if we finished the entire row of blocks */ - if(tmp_count[fast_dim] >= tdiminfo[fast_dim].count) { - /* Increment offset in destination buffer */ - loc += wrap[fast_dim]; + /* Check args */ + HDassert(old_space); + HDassert(start); + HDassert(count); + HDassert(op >= H5S_SELECT_SET && op <= H5S_SELECT_NOTA); + HDassert(new_space); + HDassert(*new_space == NULL); - /* Increment information to reflect block just processed */ - offset[fast_dim] = fast_dim_offset; /* reset the offset in the fastest dimension */ - tmp_count[fast_dim] = 0; + /* Point to the correct stride values */ + if(stride == NULL) + stride = H5S_hyper_ones_g; - /* Increment the offset and count for the other dimensions */ - temp_dim = (int)fast_dim - 1; - while(temp_dim >= 0) { - /* Move to the next row in the curent dimension */ - offset[temp_dim]++; - tmp_block[temp_dim]++; + /* Point to the correct block values */ + if(block == NULL) + block = H5S_hyper_ones_g; - /* If this block is still in the range of blocks to output for the dimension, break out of loop */ - if(tmp_block[temp_dim] < tdiminfo[temp_dim].block) - break; - else { - /* Move to the next block in the current dimension */ - offset[temp_dim] += (tdiminfo[temp_dim].stride - tdiminfo[temp_dim].block); - loc += skip[temp_dim]; - tmp_block[temp_dim] = 0; - tmp_count[temp_dim]++; + /* Check new selection. */ + for(u = 0; u < old_space->extent.rank; u++) { + /* Check for overlapping hyperslab blocks in new selection. */ + if(count[u] > 1 && stride[u] < block[u]) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab blocks overlap") - /* If this block is still in the range of blocks to output for the dimension, break out of loop */ - if(tmp_count[temp_dim] < tdiminfo[temp_dim].count) - break; - else { - offset[temp_dim] = (hsize_t)((hssize_t)tdiminfo[temp_dim].start + sel_off[temp_dim]); - loc += wrap[temp_dim]; - tmp_count[temp_dim] = 0; /* reset back to the beginning of the line */ - tmp_block[temp_dim] = 0; - } /* end else */ - } /* end else */ + /* Detect zero-sized hyperslabs in new selection */ + if(count[u] == 0 || block[u] == 0) { + switch(op) { + case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ + case H5S_SELECT_NOTA: /* Binary "B not A" operation for hyperslabs */ + /* Convert to "none" selection */ + /* Copy the first dataspace without sharing the list of spans */ + if(NULL == ((*new_space) = H5S_copy(old_space, TRUE, TRUE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace") + if(H5S_select_none((*new_space)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection") + HGOTO_DONE(SUCCEED); - /* Decrement dimension count */ - temp_dim--; - } /* end while */ + case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ + case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */ + case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */ + /* Copy the first dataspace with sharing the list of spans */ + if(NULL == ((*new_space) = H5S_copy(old_space, FALSE, TRUE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace") + HGOTO_DONE(SUCCEED); /* Selection stays same */ + + case H5S_SELECT_NOOP: + case H5S_SELECT_SET: + case H5S_SELECT_APPEND: + case H5S_SELECT_PREPEND: + case H5S_SELECT_INVALID: + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ + } /* end if */ + } /* end for */ + + if(H5S_GET_SELECT_TYPE(old_space) == H5S_SEL_HYPERSLABS) { + hsize_t *old_low_bounds; /* Pointer to old space's low & high bounds */ + hsize_t *old_high_bounds; + hsize_t new_low_bounds[H5S_MAX_RANK]; /* New space's low & high bounds */ + hsize_t new_high_bounds[H5S_MAX_RANK]; + hbool_t overlapped = FALSE; + + /* Set up old space's low & high bounds */ + if(old_space->select.sel_info.hslab->span_lst) { + old_low_bounds = old_space->select.sel_info.hslab->span_lst->low_bounds; + old_high_bounds = old_space->select.sel_info.hslab->span_lst->high_bounds; } /* end if */ else { - /* Update the offset in the fastest dimension */ - offset[fast_dim] += (fast_dim_stride * act_blk_count); + old_low_bounds = old_space->select.sel_info.hslab->diminfo.low_bounds; + old_high_bounds = old_space->select.sel_info.hslab->diminfo.high_bounds; } /* end else */ - } /* end if */ - /* Compute the number of entire rows to read in */ - H5_CHECK_OVERFLOW(tot_blk_count / tdiminfo[fast_dim].count, hsize_t, size_t); - curr_rows = total_rows = (size_t)(tot_blk_count / tdiminfo[fast_dim].count); + /* Generate bounding box for hyperslab parameters */ + for(u = 0; u < old_space->extent.rank; u++) { + new_low_bounds[u] = start[u]; + new_high_bounds[u] = start[u] + stride[u] * (count[u] - 1) + (block[u] - 1); + } /* end for */ - /* Reset copy of number of blocks in fastest dimension */ - H5_CHECKED_ASSIGN(fast_dim_count, size_t, tdiminfo[fast_dim].count, hsize_t); + /* Check bound box of both spaces to see if they overlap */ + if(H5S_RANGE_OVERLAP(old_low_bounds[0], old_high_bounds[0], + new_low_bounds[0], new_high_bounds[0])) + overlapped = TRUE; + + /* Non-overlapping situations can be handled in special ways */ + if(!overlapped) { + H5S_hyper_span_info_t *new_spans = NULL; + H5S_hyper_dim_t new_hyper_diminfo[H5S_MAX_RANK]; + + if(NULL == ((*new_space) = H5S_copy(old_space, TRUE, TRUE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy dataspace") + if(NULL != (*new_space)->select.sel_info.hslab->span_lst) { + old_space->select.sel_info.hslab->span_lst->count--; + (*new_space)->select.sel_info.hslab->span_lst = NULL; + } /* end if */ - /* Read in data until an entire sequence can't be written out any longer */ - while(curr_rows > 0) { + /* Generate hyperslab info for new space */ + switch(op) { + case H5S_SELECT_OR: + case H5S_SELECT_XOR: + /* Add the new space to the space */ + if(NULL == (new_spans = H5S__hyper_make_spans(old_space->extent.rank, start, stride, count, block))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information") + if(NULL != old_space->select.sel_info.hslab->span_lst) + (*new_space)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(old_space->select.sel_info.hslab->span_lst, old_space->extent.rank); + if(H5S__hyper_add_disjoint_spans(*new_space, new_spans) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't append hyperslabs") + + /* Build diminfo struct */ + for(u = 0; u < (*new_space)->extent.rank; u++) { + new_hyper_diminfo[u].start = start[u]; + new_hyper_diminfo[u].stride = stride[u]; + new_hyper_diminfo[u].count = count[u]; + new_hyper_diminfo[u].block = block[u]; + } /* end for */ -#define DUFF_GUTS \ -/* Store the sequence information */ \ -off[curr_seq] = loc; \ -len[curr_seq] = actual_bytes; \ - \ -/* Increment sequence count */ \ -curr_seq++; \ - \ -/* Increment information to reflect block just processed */ \ -loc += fast_dim_buf_off; + /* Update space's dim info */ + if(H5S__hyper_update_diminfo(*new_space, op, new_hyper_diminfo) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't update hyperslab info") + break; -#ifdef NO_DUFFS_DEVICE - /* Loop over all the blocks in the fastest changing dimension */ - while(fast_dim_count > 0) { - DUFF_GUTS + case H5S_SELECT_AND: + if(H5S_select_none((*new_space)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection") + break; - /* Decrement number of blocks */ - fast_dim_count--; - } /* end while */ -#else /* NO_DUFFS_DEVICE */ - { - size_t duffs_index; /* Counting index for Duff's device */ + case H5S_SELECT_NOTB: + if(NULL != old_space->select.sel_info.hslab->span_lst) { + if(NULL == ((*new_space)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(old_space->select.sel_info.hslab->span_lst, old_space->extent.rank))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy dataspace") + } /* end if */ + else { + if(H5S_select_none((*new_space)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection") + } /* end else */ + break; - duffs_index = (fast_dim_count + 7) / 8; - switch (fast_dim_count % 8) { - default: - HDassert(0 && "This Should never be executed!"); + case H5S_SELECT_NOTA: + if(H5S__set_regular_hyperslab(*new_space, start, stride, count, block, stride, count, block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular selection") break; - case 0: - do - { - DUFF_GUTS - H5_ATTR_FALLTHROUGH - case 7: - DUFF_GUTS - H5_ATTR_FALLTHROUGH - case 6: - DUFF_GUTS - H5_ATTR_FALLTHROUGH - case 5: - DUFF_GUTS - H5_ATTR_FALLTHROUGH - case 4: - DUFF_GUTS - H5_ATTR_FALLTHROUGH - case 3: - DUFF_GUTS - H5_ATTR_FALLTHROUGH - case 2: - DUFF_GUTS - H5_ATTR_FALLTHROUGH - case 1: - DUFF_GUTS - } while (--duffs_index > 0); - } /* end switch */ - } -#endif /* NO_DUFFS_DEVICE */ -#undef DUFF_GUTS - /* Increment offset in destination buffer */ - loc += wrap[fast_dim]; + case H5S_SELECT_NOOP: + case H5S_SELECT_SET: + case H5S_SELECT_APPEND: + case H5S_SELECT_PREPEND: + case H5S_SELECT_INVALID: + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ - /* Increment the offset and count for the other dimensions */ - temp_dim = (int)fast_dim - 1; - while(temp_dim >= 0) { - /* Move to the next row in the curent dimension */ - offset[temp_dim]++; - tmp_block[temp_dim]++; + HGOTO_DONE(SUCCEED); + } /* end if(!overlapped) */ + } /* end if the selection of old space is H5S_SEL_HYPERSLABS */ - /* If this block is still in the range of blocks to output for the dimension, break out of loop */ - if(tmp_block[temp_dim] < tdiminfo[temp_dim].block) - break; - else { - /* Move to the next block in the current dimension */ - offset[temp_dim] += (tdiminfo[temp_dim].stride - tdiminfo[temp_dim].block); - loc += skip[temp_dim]; - tmp_block[temp_dim] = 0; - tmp_count[temp_dim]++; + /* Copy the first dataspace with sharing the list of spans */ + if(NULL == ((*new_space) = H5S_copy(old_space, TRUE, TRUE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace") - /* If this block is still in the range of blocks to output for the dimension, break out of loop */ - if(tmp_count[temp_dim] < tdiminfo[temp_dim].count) - break; - else { - offset[temp_dim] = (hsize_t)((hssize_t)tdiminfo[temp_dim].start + sel_off[temp_dim]); - loc += wrap[temp_dim]; - tmp_count[temp_dim] = 0; /* reset back to the beginning of the line */ - tmp_block[temp_dim] = 0; - } /* end else */ - } /* end else */ + /* Note: a little overhead in calling the function as some conditions are checked again */ + if(H5S_select_hyperslab(*new_space, op, start, stride, count, block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection") - /* Decrement dimension count */ - temp_dim--; - } /* end while */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_combine_hyperslab() */ - /* Decrement the number of rows left */ - curr_rows--; - } /* end while */ + +/*------------------------------------------------------------------------- + * Function: H5S__fill_in_select + * + * Purpose: Combines two hyperslabs with an operation, putting the + * result into a third hyperslab selection + * + * Return: Non-negative on success/negative on failure + * + * Programmer: Chao Mei + * Tuesday, July 5, 2011 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S__fill_in_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2, H5S_t **result) +{ + hbool_t span2_owned; + hbool_t updated_spans; + herr_t ret_value = SUCCEED; /* Return value */ - /* Adjust the number of blocks & elements left to transfer */ + FUNC_ENTER_STATIC - /* Decrement number of elements left */ - H5_CHECK_OVERFLOW(actual_elem * (total_rows * tdiminfo[fast_dim].count), hsize_t, size_t); - io_left -= (size_t)(actual_elem * (total_rows * tdiminfo[fast_dim].count)); + /* Sanity check */ + HDassert(space1); + HDassert(space2); + HDassert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA); + HDassert(space1->extent.rank == space2->extent.rank); + /* The result is either a to-be-created space or an empty one */ + HDassert(NULL == *result || *result == space1); + HDassert(space1->select.sel_info.hslab->span_lst); + HDassert(space2->select.sel_info.hslab->span_lst); + + /* Note: the offset of space2 is not considered here for bounding box */ + if(H5S__fill_in_new_space(space1, op, space2->select.sel_info.hslab->span_lst, FALSE, &span2_owned, &updated_spans, result) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't create the specified selection") + + /* Update diminfo if space2's diminfo was valid, otherwise just mark it as + * invalid if the spans were updated */ + HDassert(result); + if(updated_spans) { + if(space2->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + if(H5S__hyper_update_diminfo(*result, op, space2->select.sel_info.hslab->diminfo.opt) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't update hyperslab info") + } /* end if */ + else + (*result)->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; + } /* end if */ - /* Decrement number of blocks left */ - H5_CHECK_OVERFLOW((total_rows * tdiminfo[fast_dim].count), hsize_t, size_t); - tot_blk_count -= (size_t)(total_rows * tdiminfo[fast_dim].count); +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__fill_in_select() */ - /* Read in partial row of blocks */ - if(io_left > 0 && curr_seq < maxseq) { - /* Get remaining number of blocks left to output */ - fast_dim_count = tot_blk_count; + +/*-------------------------------------------------------------------------- + NAME + H5Scombine_hyperslab + PURPOSE + Specify a hyperslab to combine with the current hyperslab selection and + return a new dataspace with the combined selection as the selection in the + new dataspace. + USAGE + hid_t H5Scombine_hyperslab(dsid, op, start, stride, count, block) + hid_t dsid; IN: Dataspace ID of selection to use + H5S_seloper_t op; IN: Operation to perform on current selection + const hsize_t *start; IN: Offset of start of hyperslab + const hsize_t *stride; IN: Hyperslab stride + const hsize_t *count; IN: Number of blocks included in hyperslab + const hsize_t *block; IN: Size of block in hyperslab + RETURNS + Dataspace ID on success / H5I_INVALID_HID on failure + DESCRIPTION + Combines a hyperslab selection with the current selection for a dataspace, + creating a new dataspace to return the generated selection. + If the current selection is not a hyperslab, it is freed and the hyperslab + parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a + selection composing the entire current extent). If STRIDE or BLOCK is + NULL, they are assumed to be set to all '1'. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +hid_t +H5Scombine_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[], + const hsize_t stride[], const hsize_t count[], const hsize_t block[]) +{ + H5S_t *space; /* Dataspace to modify selection of */ + H5S_t *new_space = NULL; /* New dataspace created */ + hid_t ret_value; /* Return value */ - /* Loop over all the blocks in the fastest changing dimension */ - while(fast_dim_count > 0) { - /* Store the sequence information */ - off[curr_seq] = loc; - len[curr_seq] = actual_bytes; + FUNC_ENTER_API(H5I_INVALID_HID) + H5TRACE6("i", "iSs*h*h*h*h", space_id, op, start, stride, count, block); - /* Increment sequence count */ - curr_seq++; + /* Check args */ + if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a dataspace") + if(start == NULL || count == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "hyperslab not specified") + if(!(op >= H5S_SELECT_SET && op <= H5S_SELECT_NOTA)) + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, H5I_INVALID_HID, "invalid selection operation") - /* Increment information to reflect block just processed */ - loc += fast_dim_buf_off; + /* Generate new space, with combination of selections */ + if(H5S_combine_hyperslab(space, op, start, stride, count, block, &new_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, H5I_INVALID_HID, "unable to set hyperslab selection") - /* Decrement number of blocks */ - fast_dim_count--; - } /* end while */ + /* Atomize */ + if((ret_value = H5I_register(H5I_DATASPACE, new_space, TRUE)) < 0) + HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register dataspace atom") - /* Decrement number of elements left */ - io_left -= actual_elem * tot_blk_count; +done: + if(ret_value < 0 && new_space) + H5S_close(new_space); - /* Increment information to reflect block just processed */ - offset[fast_dim] += (fast_dim_stride * tot_blk_count); /* move the offset in the fastest dimension */ + FUNC_LEAVE_API(ret_value) +} /* end H5Scombine_hyperslab() */ - /* Handle any leftover, partial blocks in this row */ - if(io_left > 0 && curr_seq < maxseq) { - actual_elem = io_left; - actual_bytes = actual_elem * elem_size; + +/*------------------------------------------------------------------------- + * Function: H5S__combine_select + * + * Purpose: Internal version of H5Scombine_select(). + * + * Return: New dataspace on success/NULL on failure + * + * Programmer: Quincey Koziol + * Tuesday, October 30, 2001 + * + *------------------------------------------------------------------------- + */ +static H5S_t * +H5S__combine_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2) +{ + H5S_t *new_space = NULL; /* New dataspace generated */ + H5S_t *ret_value = NULL; /* Return value */ - /* Store the sequence information */ - off[curr_seq] = loc; - len[curr_seq] = actual_bytes; + FUNC_ENTER_STATIC - /* Increment sequence count */ - curr_seq++; + /* Check args */ + HDassert(space1); + HDassert(space2); + HDassert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA); - /* Decrement the number of elements left */ - io_left -= actual_elem; + /* Check if space1 selections has span trees */ + if(NULL == space1->select.sel_info.hslab->span_lst) + if(H5S__hyper_generate_spans(space1) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, NULL, "dataspace does not have span tree") - /* Increment buffer correctly */ - offset[fast_dim] += actual_elem; - } /* end if */ + if(NULL == space2->select.sel_info.hslab->span_lst) { + hsize_t tmp_start[H5S_MAX_RANK]; + hsize_t tmp_stride[H5S_MAX_RANK]; + hsize_t tmp_count[H5S_MAX_RANK]; + hsize_t tmp_block[H5S_MAX_RANK]; + unsigned u; + + for(u = 0; u < space2->extent.rank; u++) { + tmp_start[u] = space2->select.sel_info.hslab->diminfo.opt[u].start; + tmp_stride[u] = space2->select.sel_info.hslab->diminfo.opt[u].stride; + tmp_count[u] = space2->select.sel_info.hslab->diminfo.opt[u].count; + tmp_block[u] = space2->select.sel_info.hslab->diminfo.opt[u].block; + } /* end for */ - /* don't bother checking slower dimensions */ - HDassert(io_left == 0 || curr_seq == maxseq); + /* Combine hyperslab selection with regular selection directly */ + if(H5S_combine_hyperslab(space1, op, tmp_start, tmp_stride, tmp_count, tmp_block, &new_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to set hyperslab selection") } /* end if */ + else{ + /* Combine new_space (a copy of space 1) & space2, with the result in new_space */ + if(H5S__fill_in_select(space1, op, space2, &new_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, NULL, "can't clip hyperslab information") + } /* end else */ - /* Update the iterator */ - - /* Update the iterator with the location we stopped */ - /* (Subtract out the selection offset) */ - for(u = 0; u < ndims; u++) - iter->u.hyp.off[u] = (hsize_t)((hssize_t)offset[u] - sel_off[u]); - - /* Decrement the number of elements left in selection */ - iter->elmt_left -= (start_io_left - io_left); + /* Set unlim_dim */ + new_space->select.sel_info.hslab->unlim_dim = -1; - /* Increment the number of sequences generated */ - *nseq += curr_seq; + /* Set return value */ + ret_value = new_space; - /* Increment the number of elements used */ - *nelem += start_io_left - io_left; +done: + if(ret_value == NULL && new_space) + H5S_close(new_space); - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_get_seq_list_opt() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__combine_select() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_get_seq_list_single + H5Scombine_select PURPOSE - Create a list of offsets & lengths for a selection + Combine two hyperslab selections with an operation, returning a dataspace + with the resulting selection. USAGE - herr_t H5S__hyper_get_seq_list_single(space, flags, iter, maxseq, maxelem, nseq, nelem, off, len) - H5S_t *space; IN: Dataspace containing selection to use. - unsigned flags; IN: Flags for extra information about operation - H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last - position of interest in selection. - size_t maxseq; IN: Maximum number of sequences to generate - size_t maxelem; IN: Maximum number of elements to include in the - generated sequences - size_t *nseq; OUT: Actual number of sequences generated - size_t *nelem; OUT: Actual number of elements in sequences generated - hsize_t *off; OUT: Array of offsets - size_t *len; OUT: Array of lengths + hid_t H5Scombine_select(space1, op, space2) + hid_t space1; IN: First Dataspace ID + H5S_seloper_t op; IN: Selection operation + hid_t space2; IN: Second Dataspace ID RETURNS - Non-negative on success/Negative on failure. + Dataspace ID on success / H5I_INVALID_HID on failure DESCRIPTION - Use the selection in the dataspace to generate a list of byte offsets and - lengths for the region(s) selected. Start/Restart from the position in the - ITER parameter. The number of sequences generated is limited by the MAXSEQ - parameter and the number of sequences actually generated is stored in the - NSEQ parameter. + Combine two existing hyperslab selections with an operation, returning + a new dataspace with the resulting selection. The dataspace extent from + space1 is copied for the dataspace extent of the newly created dataspace. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_get_seq_list_single(const H5S_t *space, H5S_sel_iter_t *iter, - size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem, - hsize_t *off, size_t *len) +hid_t +H5Scombine_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id) { - const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ - const hssize_t *sel_off; /* Selection offset in dataspace */ - hsize_t *mem_size; /* Size of the source buffer */ - hsize_t base_offset[H5S_MAX_RANK]; /* Base coordinate offset in dataspace */ - hsize_t offset[H5S_MAX_RANK]; /* Coordinate offset in dataspace */ - hsize_t slab[H5S_MAX_RANK]; /* Hyperslab size */ - hsize_t fast_dim_block; /* Local copies of fastest changing dimension info */ - hsize_t acc; /* Accumulator */ - hsize_t loc; /* Coordinate offset */ - size_t tot_blk_count; /* Total number of blocks left to output */ - size_t elem_size; /* Size of each element iterating over */ - size_t io_left; /* The number of elements left in I/O operation */ - size_t actual_elem; /* The actual number of elements to count */ - unsigned ndims; /* Number of dimensions of dataset */ - unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ - unsigned skip_dim; /* Rank of the dimension to skip along */ - unsigned u; /* Local index variable */ - int i; /* Local index variable */ + H5S_t *space1; /* First Dataspace */ + H5S_t *space2; /* Second Dataspace */ + H5S_t *new_space = NULL; /* New Dataspace */ + hid_t ret_value; /* Return value */ - FUNC_ENTER_STATIC_NOERR + FUNC_ENTER_API(H5I_INVALID_HID) + H5TRACE3("i", "iSsi", space1_id, op, space2_id); /* Check args */ - HDassert(space); - HDassert(iter); - HDassert(maxseq > 0); - HDassert(maxelem > 0); - HDassert(nseq); - HDassert(nelem); - HDassert(off); - HDassert(len); - - /* Set a local copy of the diminfo pointer */ - tdiminfo = iter->u.hyp.diminfo; - - /* Check if this is a "flattened" regular hyperslab selection */ - if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < space->extent.rank) { - /* Set the aliases for a few important dimension ranks */ - ndims = iter->u.hyp.iter_rank; - - /* Set the local copy of the selection offset */ - sel_off = iter->u.hyp.sel_off; - - /* Set up the pointer to the size of the memory space */ - mem_size = iter->u.hyp.size; - } /* end if */ - else { - /* Set the aliases for a few important dimension ranks */ - ndims = space->extent.rank; - - /* Set the local copy of the selection offset */ - sel_off = space->select.offset; - - /* Set up the pointer to the size of the memory space */ - mem_size = space->extent.size; - } /* end else */ - fast_dim = ndims - 1; + if(NULL == (space1 = (H5S_t *)H5I_object_verify(space1_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a dataspace") + if(NULL == (space2 = (H5S_t *)H5I_object_verify(space2_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a dataspace") + if(!(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA)) + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, H5I_INVALID_HID, "invalid selection operation") - /* initialize row sizes for each dimension */ - elem_size = iter->elmt_size; - for(i = (int)fast_dim, acc = elem_size; i >= 0; i--) { - slab[i] = acc; - acc *= mem_size[i]; + /* Check that both dataspaces have the same rank */ + if(space1->extent.rank != space2->extent.rank) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "dataspaces not same rank") + + /* Note: currently, the offset of each dataspace is ignored */ +#if 0 + /* Check that both dataspaces have the same offset */ + /* Same note as in H5Smodify_select */ + for(u=0; uextent.rank; u++) { + if(space1->select.offset[u] != space2->select.offset[u]) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "dataspaces not same offset") } /* end for */ +#endif - /* Copy the base location of the block */ - /* (Add in the selection offset) */ - for(u = 0; u < ndims; u++) - base_offset[u] = (hsize_t)((hssize_t)tdiminfo[u].start + sel_off[u]); - - /* Copy the location of the point to get */ - /* (Add in the selection offset) */ - for(u = 0; u < ndims; u++) - offset[u] = (hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u]); - - /* Compute the initial buffer offset */ - for(u = 0, loc = 0; u < ndims; u++) - loc += offset[u] * slab[u]; - - /* Set local copies of information for the fastest changing dimension */ - fast_dim_block = tdiminfo[fast_dim].block; - - /* Calculate the number of elements to sequence through */ - H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t); - io_left = MIN((size_t)iter->elmt_left, maxelem); - - /* Compute the number of blocks which would fit into the buffer */ - H5_CHECK_OVERFLOW(io_left / fast_dim_block, hsize_t, size_t); - tot_blk_count = (size_t)(io_left / fast_dim_block); - - /* Don't go over the maximum number of sequences allowed */ - tot_blk_count = MIN(tot_blk_count, maxseq); - - /* Set the number of elements to write each time */ - H5_CHECKED_ASSIGN(actual_elem, size_t, fast_dim_block, hsize_t); - - /* Check for blocks to operate on */ - if(tot_blk_count > 0) { - size_t actual_bytes; /* The actual number of bytes to copy */ - - /* Set the number of actual bytes */ - actual_bytes = actual_elem * elem_size; - - /* Check for 1-dim selection */ - if(0 == fast_dim) { - /* Sanity checks */ - HDassert(1 == tot_blk_count); - HDassert(io_left == actual_elem); - - /* Store the sequence information */ - *off++ = loc; - *len++ = actual_bytes; - } /* end if */ - else { - hsize_t skip_slab; /* Temporary copy of slab[fast_dim - 1] */ - size_t blk_count; /* Total number of blocks left to output */ - - /* Find first dimension w/block >1 */ - skip_dim = fast_dim; - for(i = (int)(fast_dim - 1); i >= 0; i--) - if(tdiminfo[i].block > 1) { - skip_dim = (unsigned)i; - break; - } /* end if */ - skip_slab = slab[skip_dim]; - - /* Check for being able to use fast algorithm for 1-D */ - if(0 == skip_dim) { - /* Create sequences until an entire row can't be used */ - blk_count = tot_blk_count; - while(blk_count > 0) { - /* Store the sequence information */ - *off++ = loc; - *len++ = actual_bytes; - - /* Increment offset in destination buffer */ - loc += skip_slab; - - /* Decrement block count */ - blk_count--; - } /* end while */ - - /* Move to the next location */ - offset[skip_dim] += tot_blk_count; - } /* end if */ - else { - hsize_t tmp_block[H5S_MAX_RANK];/* Temporary block offset */ - hsize_t skip[H5S_MAX_RANK]; /* Bytes to skip between blocks */ - int temp_dim; /* Temporary rank holder */ - - /* Set the starting block location */ - for(u = 0; u < ndims; u++) - tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start; - - /* Compute the amount to skip between sequences */ - for(u = 0; u < ndims; u++) - skip[u] = (mem_size[u] - tdiminfo[u].block) * slab[u]; - - /* Create sequences until an entire row can't be used */ - blk_count = tot_blk_count; - while(blk_count > 0) { - /* Store the sequence information */ - *off++ = loc; - *len++ = actual_bytes; - - /* Set temporary dimension for advancing offsets */ - temp_dim = (int)skip_dim; - - /* Increment offset in destination buffer */ - loc += skip_slab; + /* Check that both dataspaces have hyperslab selections */ + if(H5S_GET_SELECT_TYPE(space1) != H5S_SEL_HYPERSLABS || H5S_GET_SELECT_TYPE(space2) != H5S_SEL_HYPERSLABS) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "dataspaces don't have hyperslab selections") - /* Increment the offset and count for the other dimensions */ - while(temp_dim >= 0) { - /* Move to the next row in the curent dimension */ - offset[temp_dim]++; - tmp_block[temp_dim]++; + /* Go combine the dataspaces */ + if(NULL == (new_space = H5S__combine_select(space1, op, space2))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, H5I_INVALID_HID, "unable to create hyperslab selection") - /* If this block is still in the range of blocks to output for the dimension, break out of loop */ - if(tmp_block[temp_dim] < tdiminfo[temp_dim].block) - break; - else { - offset[temp_dim] = base_offset[temp_dim]; - loc += skip[temp_dim]; - tmp_block[temp_dim] = 0; - } /* end else */ + /* Atomize */ + if((ret_value = H5I_register(H5I_DATASPACE, new_space, TRUE)) < 0) + HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register dataspace atom") - /* Decrement dimension count */ - temp_dim--; - } /* end while */ +done: + if(ret_value < 0 && new_space) + H5S_close(new_space); - /* Decrement block count */ - blk_count--; - } /* end while */ - } /* end else */ - } /* end else */ + FUNC_LEAVE_API(ret_value) +} /* end H5Scombine_select() */ - /* Update the iterator, if there were any blocks used */ + +/*------------------------------------------------------------------------- + * Function: H5S__modify_select + * + * Purpose: Internal version of H5Smodify_select(). + * + * Return: New dataspace on success/NULL on failure + * + * Programmer: Quincey Koziol + * Tuesday, October 30, 2001 + * + *------------------------------------------------------------------------- + */ +herr_t +H5S__modify_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2) +{ + herr_t ret_value = SUCCEED; /* Return value */ - /* Decrement the number of elements left in selection */ - iter->elmt_left -= tot_blk_count * actual_elem; + FUNC_ENTER_PACKAGE - /* Check if there are elements left in iterator */ - if(iter->elmt_left > 0) { - /* Update the iterator with the location we stopped */ - /* (Subtract out the selection offset) */ - for(u = 0; u < ndims; u++) - iter->u.hyp.off[u] = (hsize_t)((hssize_t)offset[u] - sel_off[u]); - } /* end if */ + /* Check args */ + HDassert(space1); + HDassert(space2); + HDassert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA); - /* Increment the number of sequences generated */ - *nseq += tot_blk_count; + /* Check that the space selections both have span trees */ + if(NULL == space1->select.sel_info.hslab->span_lst) + if(H5S__hyper_generate_spans(space1) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") - /* Increment the number of elements used */ - *nelem += tot_blk_count * actual_elem; + /* Set unlim_dim */ + space1->select.sel_info.hslab->unlim_dim = -1; + + if(NULL == space2->select.sel_info.hslab->span_lst) { + hsize_t tmp_start[H5S_MAX_RANK]; + hsize_t tmp_stride[H5S_MAX_RANK]; + hsize_t tmp_count[H5S_MAX_RANK]; + hsize_t tmp_block[H5S_MAX_RANK]; + unsigned u; + + for(u = 0; u < space2->extent.rank; u++) { + tmp_start[u] = space2->select.sel_info.hslab->diminfo.opt[u].start; + tmp_stride[u] = space2->select.sel_info.hslab->diminfo.opt[u].stride; + tmp_count[u] = space2->select.sel_info.hslab->diminfo.opt[u].count; + tmp_block[u] = space2->select.sel_info.hslab->diminfo.opt[u].block; + } /* end for */ + + /* Call H5S_select_hyperslab directly */ + if(H5S_select_hyperslab(space1, op, tmp_start, tmp_stride, tmp_count, tmp_block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection") } /* end if */ + else + /* Combine spans from space1 & spans from space2, with the result in space1 */ + if(H5S__fill_in_select(space1, op, space2, &space1) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't perform operation on two selections") - /* Check for partial block, with room for another sequence */ - if(io_left > (tot_blk_count * actual_elem) && tot_blk_count < maxseq) { - size_t elmt_remainder; /* Elements remaining */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__modify_select() */ - /* Compute elements left */ - elmt_remainder = io_left - (tot_blk_count * actual_elem); - HDassert(elmt_remainder < fast_dim_block); - HDassert(elmt_remainder > 0); + +/*-------------------------------------------------------------------------- + NAME + H5Smodify_select + PURPOSE + Refine a hyperslab selection with an operation using a second hyperslab + to modify it + USAGE + herr_t H5Smodify_select(space1, op, space2) + hid_t space1; IN/OUT: First Dataspace ID + H5S_seloper_t op; IN: Selection operation + hid_t space2; IN: Second Dataspace ID + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Refine an existing hyperslab selection with an operation, using a second + hyperslab. The first selection is modified to contain the result of + space1 operated on by space2. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5Smodify_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id) +{ + H5S_t *space1; /* First Dataspace */ + H5S_t *space2; /* Second Dataspace */ + herr_t ret_value = SUCCEED; /* Return value */ - /* Store the sequence information */ - *off++ = loc; - *len++ = elmt_remainder * elem_size; + FUNC_ENTER_API(FAIL) + H5TRACE3("e", "iSsi", space1_id, op, space2_id); - /* Update the iterator with the location we stopped */ - iter->u.hyp.off[fast_dim] += (hsize_t)elmt_remainder; + /* Check args */ + if(NULL == (space1 = (H5S_t *)H5I_object_verify(space1_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + if(NULL == (space2 = (H5S_t *)H5I_object_verify(space2_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + if(!(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA)) + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - /* Decrement the number of elements left in selection */ - iter->elmt_left -= elmt_remainder; + /* Check that both dataspaces have the same rank */ + if(space1->extent.rank != space2->extent.rank) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same rank") - /* Increment the number of sequences generated */ - (*nseq)++; + /* Check that both dataspaces have the same offset */ + /** Note that this is a tricky part of this function. It's + * possible that two dataspaces have different "offset". If the + * space2 has smaller offset value than that of space1 in a + * dimension, then the span elements of this dimension in + * space2 could have negative "low" and "high" values relative + * to the offset in space1. In other words, if the bounds of + * span elements in space2 are adjusted relative to the offset + * in space1, then every span element's bound is computed as + * "origin_bound+offset2-offset1". Therefore, if offset2 (the + * offset of space2) is smaller, then + * "origin_bound+offset2-offset1" could be negative which is + * not allowed by the bound type declaration as hsize_t! + * As a result, if the op is an OR selection, then the final + * result may contain span elements that have negative bound! + * So right now, the difference in the offset is totally + * ignored!! + */ +#if 0 + for(u=0; uextent.rank; u++) { + if(space1->select.offset[u] != space2->select.offset[u]) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same offset") + } /* end for */ +#endif - /* Increment the number of elements used */ - *nelem += elmt_remainder; - } /* end if */ + /* Check that both dataspaces have hyperslab selections */ + if(H5S_GET_SELECT_TYPE(space1) != H5S_SEL_HYPERSLABS || H5S_GET_SELECT_TYPE(space2) != H5S_SEL_HYPERSLABS) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces don't have hyperslab selections") - /* Sanity check */ - HDassert(*nseq > 0); - HDassert(*nelem > 0); + /* Go refine the first selection */ + if(H5S__modify_select(space1, op, space2) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to modify hyperslab selection") - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_get_seq_list_single() */ +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Smodify_select() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_get_seq_list + H5S__hyper_proj_int_build_proj PURPOSE - Create a list of offsets & lengths for a selection + Secondary iteration routine for H5S__hyper_project_intersection USAGE - herr_t H5S__hyper_get_seq_list(space,flags,iter,maxseq,maxelem,nseq,nelem,off,len) - H5S_t *space; IN: Dataspace containing selection to use. - unsigned flags; IN: Flags for extra information about operation - H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last - position of interest in selection. - size_t maxseq; IN: Maximum number of sequences to generate - size_t maxelem; IN: Maximum number of elements to include in the - generated sequences - size_t *nseq; OUT: Actual number of sequences generated - size_t *nelem; OUT: Actual number of elements in sequences generated - hsize_t *off; OUT: Array of offsets - size_t *len; OUT: Array of lengths + herr_t H5S__hyper_proj_int_build_proj(udata) + H5S_hyper_project_intersect_ud_t *udata; IN/OUT: Persistent shared data for iteration RETURNS Non-negative on success/Negative on failure. DESCRIPTION - Use the selection in the dataspace to generate a list of byte offsets and - lengths for the region(s) selected. Start/Restart from the position in the - ITER parameter. The number of sequences generated is limited by the MAXSEQ - parameter and the number of sequences actually generated is stored in the - NSEQ parameter. + Takes the skip and nelem amounts listed in udata and converts them to + span trees in the projected space, using the destination space. This + is a non-recursive algorithm by necessity, it saves the current state + of iteration in udata and resumes in the same location on subsequent + calls. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ static herr_t -H5S__hyper_get_seq_list(const H5S_t *space, unsigned H5_ATTR_UNUSED flags, H5S_sel_iter_t *iter, - size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem, - hsize_t *off, size_t *len) -{ - herr_t ret_value = FAIL; /* return value */ +H5S__hyper_proj_int_build_proj(H5S_hyper_project_intersect_ud_t *udata) { + H5S_hyper_span_info_t *copied_span_info = NULL; /* Temporary span info pointer */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_STATIC_NOERR + FUNC_ENTER_STATIC - /* Check args */ - HDassert(space); - HDassert(iter); - HDassert(iter->elmt_left > 0); - HDassert(maxseq > 0); - HDassert(maxelem > 0); - HDassert(nseq); - HDassert(nelem); - HDassert(off); - HDassert(len); - HDassert(space->select.sel_info.hslab->unlim_dim < 0); + HDassert(udata->nelem > 0); - /* Check for the special case of just one H5Sselect_hyperslab call made */ - if(H5S_DIMINFO_VALID_YES == space->select.sel_info.hslab->diminfo_valid) { - const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ - const hssize_t *sel_off; /* Selection offset in dataspace */ - hsize_t *mem_size; /* Size of the source buffer */ - unsigned ndims; /* Number of dimensions of dataset */ - unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ - hbool_t single_block; /* Whether the selection is a single block */ - unsigned u; /* Local index variable */ + /* + * Skip over skipped elements + */ + if(udata->skip > 0) { + /* Work upwards, finishing each span tree before moving up */ + HDassert(udata->ds_span[udata->depth]); + do { + /* Check for lowest dimension */ + if(udata->ds_span[udata->depth]->down) { + if(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high) { + /* If we will run out of elements to skip in this span, + * advance to the first not fully skipped span and break + * out of this loop (start moving downwards) */ + if(udata->skip < H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen) + * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) { + udata->ds_low[udata->depth] += udata->skip / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts; + udata->skip %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts; + break; + } /* end if */ - /* Set a local copy of the diminfo pointer */ - tdiminfo = iter->u.hyp.diminfo; + /* Skip over this entire span */ + udata->skip -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts + * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1); + } /* end if */ + } /* end if */ + else { + HDassert(udata->ds_rank - udata->depth == 1); + + /* If we will run out of elements to skip in this span, + * skip the remainder of the skipped elements and break out */ + HDassert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high); + if(udata->skip < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) { + udata->ds_low[udata->depth] += udata->skip; + udata->skip = 0; + break; + } /* end if */ + + /* Skip over this entire span */ + udata->skip -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1; + } /* end else */ + + /* Advance to next span */ + udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next; + if(udata->ds_span[udata->depth]) + udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low; + else if(udata->depth > 0) { + /* If present, append this span tree to the higher dimension's, + * and release ownership of it */ + if(udata->ps_span_info[udata->depth]) { + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth - 1], + udata->ds_rank - udata->depth + 1, udata->ds_low[udata->depth - 1], + udata->ds_low[udata->depth - 1], + udata->ps_span_info[udata->depth]) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + H5S__hyper_free_span_info(udata->ps_span_info[udata->depth]); + udata->ps_span_info[udata->depth] = NULL; + } /* end if */ + + /* Ran out of spans, move up one dimension */ + udata->depth--; + HDassert(udata->ds_span[udata->depth]); + udata->ds_low[udata->depth]++; + } /* end if */ + else + HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "insufficient elements in destination selection") + } while((udata->skip > 0) + || (udata->ds_low[udata->depth] > udata->ds_span[udata->depth]->high)); + + /* Work downwards until skip is 0 */ + HDassert(udata->ds_span[udata->depth]); + while(udata->skip > 0) { + HDassert(udata->ds_span[udata->depth]->down); + udata->depth++; + udata->ds_span[udata->depth] = udata->ds_span[udata->depth - 1]->down->head; + udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low; + if(udata->ds_span[udata->depth]->down) { + do { + /* If we will run out of elements to skip in this span, + * advance to the first not fully skipped span and + * continue down */ + if(udata->skip < H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen) + * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) { + udata->ds_low[udata->depth] += udata->skip / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts; + udata->skip %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts; + break; + } /* end if */ + + /* Skip over this entire span */ + udata->skip -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts + * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1); + + /* Advance to next span */ + udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next; + HDassert(udata->ds_span[udata->depth]); + udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low; + } while(udata->skip > 0); + } /* end if */ + else { + do { + /* If we will run out of elements to skip in this span, + * skip the remainder of the skipped elements */ + if(udata->skip < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) { + udata->ds_low[udata->depth] += udata->skip; + udata->skip = 0; + break; + } /* end if */ + + /* Skip over this entire span */ + udata->skip -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1; + + /* Advance to next span */ + udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next; + HDassert(udata->ds_span[udata->depth]); + udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low; + } while(udata->skip > 0); + } /* end else */ + } /* end while */ + } /* end if */ + + /* + * Add requested number of elements to projected space + */ + /* Work upwards, adding all elements of each span tree until it can't fit + * all elements */ + HDassert(udata->ds_span[udata->depth]); + do { + /* Check for lowest dimension */ + if(udata->ds_span[udata->depth]->down) { + if(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high) { + /* If we will run out of elements to add in this span, add + * any complete spans, advance to the first not fully added + * span, and break out of this loop (start moving downwards) + */ + if(udata->nelem < H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen) + * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) { + if(udata->nelem >= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) { + if(udata->share_selection) { + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], + udata->ds_rank - udata->depth, udata->ds_low[udata->depth], + udata->ds_low[udata->depth] + (udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) - 1, + udata->ds_span[udata->depth]->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + } /* end if */ + else { + /* If we're not sharing the destination space's + * spans, we must copy it first (then release it + * afterwards) */ + if(NULL == (copied_span_info = H5S__hyper_copy_span_helper(udata->ds_span[udata->depth]->down, udata->ds_rank - udata->depth, 1, udata->op_gen))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination spans") + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], + udata->ds_rank - udata->depth, udata->ds_low[udata->depth], + udata->ds_low[udata->depth] + (udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) - 1, + copied_span_info) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + H5S__hyper_free_span_info(copied_span_info); + copied_span_info = NULL; + } /* end else */ + udata->ds_low[udata->depth] += udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts; + udata->nelem %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts; + } /* end if */ + break; + } /* end if */ + + /* Append span tree for entire span */ + if(udata->share_selection) { + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], + udata->ds_rank - udata->depth, udata->ds_low[udata->depth], + udata->ds_span[udata->depth]->high, + udata->ds_span[udata->depth]->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + } /* end if */ + else { + /* If we're not sharing the destination space's + * spans, we must copy it first (then release it + * afterwards) */ + if(NULL == (copied_span_info = H5S__hyper_copy_span_helper(udata->ds_span[udata->depth]->down, udata->ds_rank - udata->depth, 1, udata->op_gen))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination spans") + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], + udata->ds_rank - udata->depth, udata->ds_low[udata->depth], + udata->ds_span[udata->depth]->high, + copied_span_info) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + H5S__hyper_free_span_info(copied_span_info); + copied_span_info = NULL; + } /* end else */ + udata->nelem -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts + * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1); + } /* end if */ + } /* end if */ + else { + HDassert(udata->ds_rank - udata->depth == 1); + + /* If we will run out of elements to add in this span, add the + * remainder of the elements and break out */ + HDassert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high); + if(udata->nelem < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) { + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1, + udata->ds_low[udata->depth], udata->ds_low[udata->depth] + udata->nelem - 1, NULL) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + udata->ds_low[udata->depth] += udata->nelem; + udata->nelem = 0; + break; + } /* end if */ + + /* Append span tree for entire span */ + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1, + udata->ds_low[udata->depth], udata->ds_span[udata->depth]->high, NULL) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + udata->nelem -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1; + } /* end else */ + + /* Advance to next span */ + udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next; + if(udata->ds_span[udata->depth]) + udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low; + else if(udata->depth > 0) { + /* Append this span tree to the higher dimension's, and release + * ownership of it */ + HDassert(udata->ps_span_info[udata->depth]); + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth - 1], + udata->ds_rank - udata->depth + 1, udata->ds_low[udata->depth - 1], + udata->ds_low[udata->depth - 1], + udata->ps_span_info[udata->depth]) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + H5S__hyper_free_span_info(udata->ps_span_info[udata->depth]); + udata->ps_span_info[udata->depth] = NULL; + + /* Ran out of spans, move up one dimension */ + udata->depth--; + HDassert(udata->ds_span[udata->depth]); + udata->ds_low[udata->depth]++; + } /* end if */ + else { + /* We have finished the entire destination span tree. If there are + * still elements to add, issue an error. */ + if(udata->nelem > 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "insufficient elements in destination selection") + break; + } /* end else */ + } while((udata->nelem > 0) + || (udata->ds_low[udata->depth] > udata->ds_span[udata->depth]->high)); + + /* Work downwards until nelem is 0 */ + HDassert(udata->ds_span[udata->depth] || (udata->nelem == 0)); + while(udata->nelem > 0) { + HDassert(udata->ds_span[udata->depth]->down); + udata->depth++; + udata->ds_span[udata->depth] = udata->ds_span[udata->depth - 1]->down->head; + udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low; + if(udata->ds_span[udata->depth]->down) { + do { + /* If we will run out of elements to add in this span, add + * any complete spans, advance to the first not fully added + * span and continue down + */ + HDassert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high); + if(udata->nelem < H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen) + * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) { + if(udata->nelem >= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) { + if(udata->share_selection) { + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], + udata->ds_rank - udata->depth, udata->ds_low[udata->depth], + udata->ds_low[udata->depth] + (udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) - 1, + udata->ds_span[udata->depth]->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + } /* end if */ + else { + /* If we're not sharing the destination space's + * spans, we must copy it first (then release it + * afterwards) */ + if(NULL == (copied_span_info = H5S__hyper_copy_span_helper(udata->ds_span[udata->depth]->down, udata->ds_rank - udata->depth, 1, udata->op_gen))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination spans") + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], + udata->ds_rank - udata->depth, udata->ds_low[udata->depth], + udata->ds_low[udata->depth] + (udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) - 1, + copied_span_info) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + H5S__hyper_free_span_info(copied_span_info); + copied_span_info = NULL; + } /* end else */ + udata->ds_low[udata->depth] += udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts; + udata->nelem %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts; + } /* end if */ + break; + } /* end if */ + + /* Append span tree for entire span */ + if(udata->share_selection) { + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], + udata->ds_rank - udata->depth, udata->ds_low[udata->depth], + udata->ds_span[udata->depth]->high, + udata->ds_span[udata->depth]->down) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + } /* end if */ + else { + /* If we're not sharing the destination space's + * spans, we must copy it first (then release it + * afterwards) */ + if(NULL == (copied_span_info = H5S__hyper_copy_span_helper(udata->ds_span[udata->depth]->down, udata->ds_rank - udata->depth, 1, udata->op_gen))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination spans") + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], + udata->ds_rank - udata->depth, udata->ds_low[udata->depth], + udata->ds_span[udata->depth]->high, + copied_span_info) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + H5S__hyper_free_span_info(copied_span_info); + copied_span_info = NULL; + } /* end else */ + udata->nelem -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts + * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1); + + /* Advance to next span */ + udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next; + HDassert(udata->ds_span[udata->depth]); + udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low; + } while(udata->nelem > 0); + } /* end if */ + else { + HDassert(udata->ds_rank - udata->depth == 1); + do { + /* If we will run out of elements to add in this span, add + * the remainder of the elements and break out */ + HDassert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high); + if(udata->nelem < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) { + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1, + udata->ds_low[udata->depth], udata->ds_low[udata->depth] + udata->nelem - 1, NULL) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + udata->ds_low[udata->depth] += udata->nelem; + udata->nelem = 0; + break; + } /* end if */ - /* Check if this is a "flattened" regular hyperslab selection */ - if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < space->extent.rank) { - /* Set the aliases for a few important dimension ranks */ - ndims = iter->u.hyp.iter_rank; + /* Append span tree for entire span */ + if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1, + udata->ds_low[udata->depth], udata->ds_span[udata->depth]->high, NULL) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + udata->nelem -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1; + + /* Advance to next span */ + udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next; + HDassert(udata->ds_span[udata->depth]); + udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low; + } while(udata->nelem > 0); + } /* end else */ + } /* end while */ - /* Set the local copy of the selection offset */ - sel_off = iter->u.hyp.sel_off; + HDassert(udata->skip == 0); + HDassert(udata->nelem == 0); - /* Set up the pointer to the size of the memory space */ - mem_size = iter->u.hyp.size; - } /* end if */ - else { - /* Set the aliases for a few important dimension ranks */ - ndims = space->extent.rank; + /* Mark projected space as changed (for all ranks) */ + udata->ps_clean_bitmap = 0; - /* Set the local copy of the selection offset */ - sel_off = space->select.offset; +done: + /* Cleanup on failure */ + if(copied_span_info) { + HDassert(ret_value < 0); + H5S__hyper_free_span_info(copied_span_info); + copied_span_info = NULL; + } /* end if */ - /* Set up the pointer to the size of the memory space */ - mem_size = space->extent.size; - } /* end else */ - fast_dim = ndims - 1; + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_proj_int_build_proj() */ - /* Check if we stopped in the middle of a sequence of elements */ - if((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride != 0 || - ((iter->u.hyp.off[fast_dim] != tdiminfo[fast_dim].start) && tdiminfo[fast_dim].count == 1)) { - hsize_t slab[H5S_MAX_RANK]; /* Hyperslab size */ - hsize_t loc; /* Coordinate offset */ - hsize_t acc; /* Accumulator */ - size_t leftover; /* The number of elements left over from the last sequence */ - size_t actual_elem; /* The actual number of elements to count */ - size_t elem_size; /* Size of each element iterating over */ - int i; /* Local index variable */ + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_proj_int_iterate + PURPOSE + Main iteration routine for H5S__hyper_project_intersection + USAGE + herr_t H5S__hyper_proj_int_iterate(ss_span_info,sis_span_info,count,depth,udata) + const H5S_hyper_span_info_t *ss_span_info; IN: Span tree for source selection + const H5S_hyper_span_info_t *sis_span_info; IN: Span tree for source intersect selection + hsize_t count; IN: Number of times to compute the intersection of ss_span_info and sis_span_info + unsigned depth; IN: Depth of iteration (in terms of rank) + H5S_hyper_project_intersect_ud_t *udata; IN/OUT: Persistent shared data for iteration + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + Computes the intersection of ss_span_info and sis_span_info and projects it + to the projected space (held in udata). It accomplishes this by iterating + over both spaces and computing the number of elements to skip (in + ss_span_info) and the number of elements to add (the intersection) in a + sequential fashion (similar to run length encoding). As necessary, this + function both recurses into lower dimensions and calls + H5S__hyper_proj_int_build_proj to convert the skip/nelem pairs to the + projected span tree. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_proj_int_iterate(const H5S_hyper_span_info_t *ss_span_info, + const H5S_hyper_span_info_t *sis_span_info, hsize_t count, unsigned depth, + H5S_hyper_project_intersect_ud_t *udata) +{ + const H5S_hyper_span_t *ss_span; /* Current span in source space */ + const H5S_hyper_span_t *sis_span; /* Current span in source intersect space */ + hsize_t ss_low; /* Current low bounds of source span */ + hsize_t sis_low; /* Current low bounds of source intersect span */ + hsize_t high; /* High bounds of current intersection */ + hsize_t low; /* Low bounds of current intersection */ + hsize_t old_skip; /* Value of udata->skip before main loop */ + hsize_t old_nelem; /* Value of udata->nelem before main loop */ + hbool_t check_intersect; /* Whether to check for intersecting elements */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + FUNC_ENTER_STATIC - /* Calculate the number of elements left in the sequence */ - if(tdiminfo[fast_dim].count == 1) { - H5_CHECKED_ASSIGN(leftover, size_t, tdiminfo[fast_dim].block - (iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start), hsize_t); - } /* end if */ - else { - H5_CHECKED_ASSIGN(leftover, size_t, tdiminfo[fast_dim].block - ((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride), hsize_t); - } /* end else */ + /* Check for non-overlapping bounds */ + check_intersect = TRUE; + for(u = 0; u < (udata->ss_rank - depth); u++) + if(!H5S_RANGE_OVERLAP(ss_span_info->low_bounds[u], + ss_span_info->high_bounds[u], + sis_span_info->low_bounds[u], + sis_span_info->high_bounds[u])) { + check_intersect = FALSE; + break; + } /* end if */ - /* Make certain that we don't write too many */ - actual_elem = MIN3(leftover, (size_t)iter->elmt_left, maxelem); + /* Only enter main loop if there's something to do */ + if(check_intersect) { + /* Set ps_clean_bitmap */ + udata->ps_clean_bitmap |= (((uint32_t)1) << depth); - /* Initialize row sizes for each dimension */ - elem_size = iter->elmt_size; - for(i = (int)fast_dim, acc = elem_size; i >= 0; i--) { - slab[i] = acc; - acc *= mem_size[i]; - } /* end for */ + /* Save old skip and nelem */ + old_skip = udata->skip; + old_nelem = udata->nelem; - /* Compute the initial buffer offset */ - for(u = 0, loc = 0; u < ndims; u++) - loc += ((hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u])) * slab[u]; + /* Intersect spaces once per count */ + for(u = 0; u < count; u++) { + ss_span = ss_span_info->head; + sis_span = sis_span_info->head; + HDassert(ss_span && sis_span); + ss_low = ss_span->low; + sis_low = sis_span->low; - /* Add a new sequence */ - off[0] = loc; - H5_CHECKED_ASSIGN(len[0], size_t, actual_elem * elem_size, hsize_t); + /* Main loop */ + do { + /* Check if spans overlap */ + if(H5S_RANGE_OVERLAP(ss_low, ss_span->high, + sis_low, sis_span->high)) { + high = MIN(ss_span->high, sis_span->high); + if(ss_span->down) { + /* Add skipped elements if there's a pre-gap */ + if(ss_low < sis_low) { + low = sis_low; + H5S_HYPER_PROJ_INT_ADD_SKIP(udata, H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) * (sis_low - ss_low), FAIL); + } /* end if */ + else + low = ss_low; - /* Increment sequence array locations */ - off++; - len++; + /* Recurse into next dimension down */ + if(H5S__hyper_proj_int_iterate(ss_span->down, sis_span->down, high - low + 1, depth + 1, udata) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "can't iterate over source selections") + } /* end if */ + else { + HDassert(depth == udata->ss_rank - 1); - /* Advance the hyperslab iterator */ - H5S__hyper_iter_next(iter, actual_elem); + /* Add skipped elements if there's a pre-gap */ + if(ss_low < sis_low) { + low = sis_low; + H5S_HYPER_PROJ_INT_ADD_SKIP(udata, sis_low - ss_low, FAIL); + } /* end if */ + else + low = ss_low; - /* Decrement the number of elements left in selection */ - iter->elmt_left -= actual_elem; + /* Add overlapping elements */ + udata->nelem += high - low + 1; + } /* end else */ - /* Decrement element/sequence limits */ - maxelem -= actual_elem; - maxseq--; + /* Advance spans */ + if(ss_span->high == sis_span->high) { + /* Advance both spans */ + ss_span = ss_span->next; + if(ss_span) + ss_low = ss_span->low; + sis_span = sis_span->next; + if(sis_span) + sis_low = sis_span->low; + } /* end if */ + else if(ss_span->high == high) { + /* Advance source span */ + HDassert(ss_span->high < sis_span->high); + sis_low = high + 1; + ss_span = ss_span->next; + if(ss_span) + ss_low = ss_span->low; + } /* end if */ + else { + /* Advance source intersect span */ + HDassert(ss_span->high > sis_span->high); + ss_low = high + 1; + sis_span = sis_span->next; + if(sis_span) + sis_low = sis_span->low; + } /* end else */ + } /* end if */ + else { + /* Advance spans */ + if(ss_span->high < sis_low) { + /* Add skipped elements */ + if(ss_span->down) + H5S_HYPER_PROJ_INT_ADD_SKIP(udata, H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) * (ss_span->high - ss_low + 1), FAIL); + else + H5S_HYPER_PROJ_INT_ADD_SKIP(udata, ss_span->high - ss_low + 1, FAIL); - /* Set the number of sequences generated and elements used */ - *nseq = 1; - *nelem = actual_elem; + /* Advance source span */ + ss_span = ss_span->next; + if(ss_span) + ss_low = ss_span->low; + } /* end if */ + else { + /* Advance source intersect span */ + HDassert(ss_low > sis_span->high); + sis_span = sis_span->next; + if(sis_span) + sis_low = sis_span->low; + } /* end else */ + } /* end else */ + } while(ss_span && sis_span); + + if(ss_span && !((depth == 0) && (u == count - 1))) { + /* Count remaining elements in ss_span_info */ + if(ss_span->down) { + H5S_HYPER_PROJ_INT_ADD_SKIP(udata, H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) * (ss_span->high - ss_low + 1), FAIL); + ss_span = ss_span->next; + while(ss_span) { + H5S_HYPER_PROJ_INT_ADD_SKIP(udata, H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) * (ss_span->high - ss_span->low + 1), FAIL); + ss_span = ss_span->next; + } /* end while */ + } /* end if */ + else { + H5S_HYPER_PROJ_INT_ADD_SKIP(udata, ss_span->high - ss_low + 1, FAIL); + ss_span = ss_span->next; + while(ss_span) { + H5S_HYPER_PROJ_INT_ADD_SKIP(udata, ss_span->high - ss_span->low + 1, FAIL); + ss_span = ss_span->next; + } /* end while */ + } /* end else */ + } /* end if */ - /* Check for using up all the sequences/elements */ - if(0 == iter->elmt_left || 0 == maxelem || 0 == maxseq) - return(SUCCEED); - } /* end if */ - else { - /* Reset the number of sequences generated and elements used */ - *nseq = 0; - *nelem = 0; - } /* end else */ + /* Check if the projected space was not changed since we started the + * first iteration of the loop, if so we do not need to continue + * looping and can just copy the result */ + if(udata->ps_clean_bitmap & (((uint32_t)1) << depth)) { + HDassert(u == 0); + if(udata->skip == old_skip) { + /* First case: algorithm added only elements */ + HDassert(udata->nelem >= old_nelem); + udata->nelem += (count - 1) * (udata->nelem - old_nelem); + } /* end if */ + else if(udata->nelem == 0) { + /* Second case: algorithm added only skip. In this case, + * nelem must be 0 since otherwise adding skip would have + * triggered a change in the projected space */ + HDassert(old_nelem == 0); + HDassert(udata->skip > old_skip); + udata->skip += (count - 1) * (udata->skip - old_skip); + } /* end if */ + else { + /* Third case: agorithm added skip and nelem (in that + * order). Add the same skip and nelem once for each item + * remaining in count. */ + hsize_t skip_add; + hsize_t nelem_add; + + HDassert(udata->nelem > 0); + HDassert(udata->skip > old_skip); + HDassert(old_nelem == 0); + + skip_add = udata->skip - old_skip; + nelem_add = udata->nelem - old_nelem; + for(u = 1; u < count; u++) { + H5S_HYPER_PROJ_INT_ADD_SKIP(udata, skip_add, FAIL); + udata->nelem += nelem_add; + } /* end for */ + } /* end else */ - /* Check for a single block selected */ - single_block = TRUE; - for(u = 0; u < ndims; u++) - if(1 != tdiminfo[u].count) { - single_block = FALSE; + /* End loop since we already took care of it */ break; } /* end if */ - - /* Check for single block selection */ - if(single_block) - /* Use single-block optimized call to generate sequence list */ - ret_value = H5S__hyper_get_seq_list_single(space, iter, maxseq, maxelem, nseq, nelem, off, len); - else - /* Use optimized call to generate sequence list */ - ret_value = H5S__hyper_get_seq_list_opt(space, iter, maxseq, maxelem, nseq, nelem, off, len); + } /* end for */ + } /* end if */ + else if(depth > 0) + /* Just count skipped elements */ + H5S_HYPER_PROJ_INT_ADD_SKIP(udata, H5S__hyper_spans_nelem_helper((H5S_hyper_span_info_t *)ss_span_info, 0, udata->op_gen) * count, FAIL); /* Casting away const OK -NAF */ + + /* Clean up if we are done */ + if(depth == 0) { + /* Add remaining elements */ + if(udata->nelem > 0) + if(H5S__hyper_proj_int_build_proj(udata) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't add elements to projected selection") + + /* Append remaining span trees */ + for(u = udata->ds_rank - 1; u > 0; u--) + if(udata->ps_span_info[u]) { + if(H5S__hyper_append_span(&udata->ps_span_info[u - 1], + udata->ds_rank - u + 1, udata->ds_low[u - 1], + udata->ds_low[u - 1], + udata->ps_span_info[u]) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + H5S__hyper_free_span_info(udata->ps_span_info[u]); + udata->ps_span_info[u] = NULL; + } /* end if */ } /* end if */ - else - /* Call the general sequence generator routine */ - ret_value = H5S__hyper_get_seq_list_gen(space, iter, maxseq, maxelem, nseq, nelem, off, len); +done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_get_seq_list() */ +} /* end H5S__hyper_proj_int_iterate() */ /*-------------------------------------------------------------------------- @@ -9320,21 +11281,23 @@ H5S__hyper_get_seq_list(const H5S_t *space, unsigned H5_ATTR_UNUSED flags, H5S_s src_intersect_space within the selection of src_space as a selection within the selection of dst_space USAGE - herr_t H5S__hyper_project_intersection(src_space,dst_space,src_intersect_space,proj_space) + herr_t H5S__hyper_project_intersection(src_space,dst_space,src_intersect_space,proj_space,share_selection) H5S_t *src_space; IN: Selection that is mapped to dst_space, and intersected with src_intersect_space H5S_t *dst_space; IN: Selection that is mapped to src_space, and which contains the result H5S_t *src_intersect_space; IN: Selection whose intersection with src_space is projected to dst_space to obtain the result H5S_t *proj_space; OUT: Will contain the result (intersection of src_intersect_space and src_space projected from src_space to dst_space) after the operation + hbool_t share_selection; IN: Whether we are allowed to share structures inside dst_space with proj_space RETURNS Non-negative on success/Negative on failure. DESCRIPTION Projects the intersection of of the selections of src_space and src_intersect_space within the selection of src_space as a selection - within the selection of dst_space. The result is placed in the - selection of proj_space. Note src_space, dst_space, and - src_intersect_space do not need to use hyperslab selections, but they - cannot use point selections. The result is always a hyperslab - selection. + within the selection of dst_space. The result is placed in the selection + of proj_space. Note src_space, dst_space, and src_intersect_space do not + need to use hyperslab selections, but they cannot use point selections. + The result is always a hyperslab or none selection. Note also that + proj_space can share some span trees with dst_space, so proj_space + must not be subsequently modified if dst_space must be preserved. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES @@ -9342,48 +11305,14 @@ H5S__hyper_get_seq_list(const H5S_t *space, unsigned H5_ATTR_UNUSED flags, H5S_s --------------------------------------------------------------------------*/ herr_t H5S__hyper_project_intersection(const H5S_t *src_space, const H5S_t *dst_space, - const H5S_t *src_intersect_space, H5S_t *proj_space) + const H5S_t *src_intersect_space, H5S_t *proj_space, + hbool_t share_selection) { - hsize_t ss_off[H5S_PROJECT_INTERSECT_NSEQS]; /* Offset array for src_space */ - size_t ss_len[H5S_PROJECT_INTERSECT_NSEQS]; /* Length array for src_space */ - size_t ss_nseq; /* Number of sequences for src_space */ - size_t ss_nelem; /* Number of elements for src_space */ - size_t ss_i = (size_t)0; /* Index into offset/length arrays for src_space */ - hbool_t advance_ss = FALSE; /* Whether to advance ss_i on the next iteration */ - H5S_sel_iter_t *ss_iter = NULL; /* Selection iterator for src_space */ - hbool_t ss_iter_init = FALSE; /* Whether ss_iter is initialized */ - hsize_t ss_sel_off = (hsize_t)0; /* Offset within src_space selection */ - hsize_t ds_off[H5S_PROJECT_INTERSECT_NSEQS]; /* Offset array for dst_space */ - size_t ds_len[H5S_PROJECT_INTERSECT_NSEQS]; /* Length array for dst_space */ - size_t ds_nseq; /* Number of sequences for dst_space */ - size_t ds_nelem; /* Number of elements for dst_space */ - size_t ds_i = (size_t)0; /* Index into offset/length arrays for dst_space */ - H5S_sel_iter_t *ds_iter = NULL; /* Selection iterator for dst_space */ - hbool_t ds_iter_init = FALSE; /* Whether ds_iter is initialized */ - hsize_t ds_sel_off = (hsize_t)0; /* Offset within dst_space selection */ - hsize_t sis_off[H5S_PROJECT_INTERSECT_NSEQS]; /* Offset array for src_intersect_space */ - size_t sis_len[H5S_PROJECT_INTERSECT_NSEQS]; /* Length array for src_intersect_space */ - size_t sis_nseq; /* Number of sequences for src_intersect_space */ - size_t sis_nelem; /* Number of elements for src_intersect_space */ - size_t sis_i = (size_t)0; /* Index into offset/length arrays for src_intersect_space */ - hbool_t advance_sis = FALSE; /* Whether to advance sis_i on the next iteration */ - H5S_sel_iter_t *sis_iter = NULL; /* Selection iterator for src_intersect_space */ - hbool_t sis_iter_init = FALSE; /* Whether sis_iter is initialized */ - hsize_t int_sel_off; /* Offset within intersected selections (ss/sis and ds/ps) */ - size_t int_len; /* Length of segment in intersected selections */ - hsize_t proj_off; /* Segment offset in proj_space */ - size_t proj_len; /* Segment length in proj_space */ - size_t proj_len_rem; /* Remaining length in proj_space for segment */ - hsize_t proj_down_dims[H5S_MAX_RANK]; /* "Down" dimensions in proj_space */ - H5S_hyper_span_info_t *curr_span_tree[H5S_MAX_RANK]; /* Current span tree being built (in each dimension) */ - H5S_hyper_span_t *prev_span[H5S_MAX_RANK]; /* Previous span in tree (in each dimension) */ - hsize_t curr_span_up_dim[H5S_MAX_RANK]; /* "Up" dimensions for current span */ - unsigned proj_rank; /* Rank of proj_space */ - hsize_t low; /* Low value of span */ - hsize_t high; /* High value of span */ - size_t span_len; /* Length of span */ - size_t nelem; /* Number of elements returned for get_seq_list op */ - unsigned i; /* Local index variable */ + H5S_hyper_project_intersect_ud_t udata; /* User data for subroutines */ + const H5S_hyper_span_info_t *ss_span_info; + const H5S_hyper_span_info_t *ds_span_info; + H5S_hyper_span_info_t *ss_span_info_buf = NULL; + H5S_hyper_span_info_t *ds_span_info_buf = NULL; herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_PACKAGE @@ -9394,303 +11323,100 @@ H5S__hyper_project_intersection(const H5S_t *src_space, const H5S_t *dst_space, HDassert(src_intersect_space); HDassert(proj_space); - /* Assert that src_space and src_intersect_space have same extent and there + /* Assert that src_space and src_intersect_space have same rank and there * are no point selections */ - HDassert(H5S_GET_EXTENT_NDIMS(src_space) - == H5S_GET_EXTENT_NDIMS(src_intersect_space)); - HDassert(!HDmemcmp(src_space->extent.size, src_intersect_space->extent.size, - (size_t)H5S_GET_EXTENT_NDIMS(src_space) - * sizeof(src_space->extent.size[0]))); + HDassert(H5S_GET_EXTENT_NDIMS(src_space) == H5S_GET_EXTENT_NDIMS(src_intersect_space)); + HDassert(H5S_GET_SELECT_NPOINTS(src_space) == H5S_GET_SELECT_NPOINTS(dst_space)); HDassert(H5S_GET_SELECT_TYPE(src_space) != H5S_SEL_POINTS); HDassert(H5S_GET_SELECT_TYPE(dst_space) != H5S_SEL_POINTS); - HDassert(H5S_GET_SELECT_TYPE(src_intersect_space) != H5S_SEL_POINTS); - - /* Initialize prev_space, curr_span_tree, and curr_span_up_dim */ - for(i = 0; i < H5S_MAX_RANK; i++) { - curr_span_tree[i] = NULL; - prev_span[i] = NULL; - curr_span_up_dim[i] = (hsize_t)0; - } /* end for */ - - /* Save rank of projected space */ - proj_rank = proj_space->extent.rank; - HDassert(proj_rank > 0); - - /* Get numbers of elements */ - ss_nelem = (size_t)H5S_GET_SELECT_NPOINTS(src_space); - ds_nelem = (size_t)H5S_GET_SELECT_NPOINTS(dst_space); - sis_nelem = (size_t)H5S_GET_SELECT_NPOINTS(src_intersect_space); - HDassert(ss_nelem == ds_nelem); - - /* Calculate proj_down_dims (note loop relies on unsigned i wrapping around) - */ - if(H5VM_array_down(proj_rank, proj_space->extent.size, proj_down_dims) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't compute 'down' chunk size value") - - /* Remove current selection from proj_space */ - if(H5S_SELECT_RELEASE(proj_space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") - - /* If any selections are empty, skip to the end so "none" is selected */ - if((ss_nelem == 0) || (ds_nelem == 0) || (sis_nelem == 0)) - goto loop_end; - - /* Allocate space for the hyperslab selection information (note this sets - * diminfo arrays to 0, and span list to NULL) - */ - if((proj_space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)) == NULL) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info") - proj_space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; - - /* Set selection type */ - proj_space->select.type = H5S_sel_hyper; - - /* Set unlim_dim */ - proj_space->select.sel_info.hslab->unlim_dim = -1; - - /* Allocate the source space iterator */ - if(NULL == (ss_iter = H5FL_MALLOC(H5S_sel_iter_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate source space iterator") - - /* Initialize source space iterator */ - if(H5S_select_iter_init(ss_iter, src_space, (size_t)1) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") - ss_iter_init = TRUE; - - /* Get sequence list for source space */ - if(H5S_SELECT_GET_SEQ_LIST(src_space, 0u, ss_iter, H5S_PROJECT_INTERSECT_NSEQS, ss_nelem, &ss_nseq, &nelem, ss_off, ss_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") - ss_nelem -= nelem; - HDassert(ss_nseq > 0); - - /* Allocate the destination space iterator */ - if(NULL == (ds_iter = H5FL_MALLOC(H5S_sel_iter_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate destination space iterator") - - /* Initialize destination space iterator */ - if(H5S_select_iter_init(ds_iter, dst_space, (size_t)1) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") - ds_iter_init = TRUE; - - /* Get sequence list for destination space */ - if(H5S_SELECT_GET_SEQ_LIST(dst_space, 0u, ds_iter, H5S_PROJECT_INTERSECT_NSEQS, ds_nelem, &ds_nseq, &nelem, ds_off, ds_len) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") - ds_nelem -= nelem; - HDassert(ds_nseq > 0); - - /* Allocate the source intersect space iterator */ - if(NULL == (sis_iter = H5FL_MALLOC(H5S_sel_iter_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate source intersect space iterator") - - /* Initialize source intersect space iterator */ - if(H5S_select_iter_init(sis_iter, src_intersect_space, (size_t)1) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") - sis_iter_init = TRUE; - - /* Get sequence list for source intersect space */ - if(H5S_SELECT_GET_SEQ_LIST(src_intersect_space, 0u, sis_iter, H5S_PROJECT_INTERSECT_NSEQS, sis_nelem, &sis_nseq, &nelem, sis_off, sis_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") - sis_nelem -= nelem; - HDassert(sis_nseq > 0); - - /* Loop until we run out of sequences in either the source or source - * intersect space */ - while(1) { - while(advance_ss || (ss_off[ss_i] + ss_len[ss_i] <= sis_off[sis_i])) { - /* Either we finished the current source sequence or the - * sequences do not intersect. Advance source space. */ - ss_sel_off += (hsize_t)ss_len[ss_i]; - if(++ss_i == ss_nseq) { - if(ss_nelem > 0) { - /* Try to grab more sequences from src_space */ - if(H5S_SELECT_GET_SEQ_LIST(src_space, 0u, ss_iter, H5S_PROJECT_INTERSECT_NSEQS, ss_nelem, &ss_nseq, &nelem, ss_off, ss_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") - HDassert(ss_len[0] > 0); - - /* Update ss_nelem */ - HDassert(nelem > 0); - HDassert(nelem <= ss_nelem); - ss_nelem -= nelem; - - /* Reset source space index */ - ss_i = 0; - } /* end if */ - else - /* There are no more sequences in src_space, so we can exit - * the loop. Use goto instead of break so we exit the outer - * loop. */ - goto loop_end; - } /* end if */ - - /* Reset advance_ss */ - advance_ss = FALSE; - } /* end if */ - if(advance_sis - || (sis_off[sis_i] + sis_len[sis_i] <= ss_off[ss_i])) { - do { - /* Either we finished the current source intersect sequence or - * the sequences do not intersect. Advance source intersect - * space. */ - if(++sis_i == sis_nseq) { - if(sis_nelem > 0) { - /* Try to grab more sequences from src_intersect_space - */ - if(H5S_SELECT_GET_SEQ_LIST(src_intersect_space, 0u, sis_iter, H5S_PROJECT_INTERSECT_NSEQS, sis_nelem, &sis_nseq, &nelem, sis_off, sis_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") - HDassert(sis_len[0] > 0); - - /* Update ss_nelem */ - HDassert(nelem > 0); - HDassert(nelem <= sis_nelem); - sis_nelem -= nelem; - - /* Reset source space index */ - sis_i = 0; - } /* end if */ - else - /* There are no more sequences in src_intersect_space, - * so we can exit the loop. Use goto instead of break - * so we exit the outer loop. */ - goto loop_end; - } /* end if */ - } while(sis_off[sis_i] + sis_len[sis_i] <= ss_off[ss_i]); + HDassert(H5S_GET_SELECT_TYPE(src_intersect_space) == H5S_SEL_HYPERSLABS); - /* Reset advance_sis */ - advance_sis = FALSE; - } /* end if */ - else { - /* Sequences intersect, add intersection to projected space */ - /* Calculate intersection sequence in terms of offset within source - * selection and advance any sequences we complete */ - if(ss_off[ss_i] >= sis_off[sis_i]) - int_sel_off = ss_sel_off; - else - int_sel_off = sis_off[sis_i] - ss_off[ss_i] + ss_sel_off; - if((ss_off[ss_i] + (hsize_t)ss_len[ss_i]) <= (sis_off[sis_i] - + (hsize_t)sis_len[sis_i])) { - int_len = (size_t)((hsize_t)ss_len[ss_i] + ss_sel_off - int_sel_off); - advance_ss = TRUE; - } /* end if */ - else - int_len = (size_t)(sis_off[sis_i] + (hsize_t)sis_len[sis_i] - ss_off[ss_i] + ss_sel_off - int_sel_off); - if((ss_off[ss_i] + (hsize_t)ss_len[ss_i]) >= (sis_off[sis_i] - + (hsize_t)sis_len[sis_i])) - advance_sis = TRUE; - - /* Project intersection sequence to destination selection */ - while(int_len > (size_t)0) { - while(ds_sel_off + (hsize_t)ds_len[ds_i] <= int_sel_off) { - /* Intersection is not projected to this destination - * sequence, advance destination space */ - ds_sel_off += (hsize_t)ds_len[ds_i]; - if(++ds_i == ds_nseq) { - HDassert(ds_nelem > 0); - - /* Try to grab more sequences from dst_space */ - if(H5S_SELECT_GET_SEQ_LIST(dst_space, 0u, ds_iter, H5S_PROJECT_INTERSECT_NSEQS, ds_nelem, &ds_nseq, &nelem, ds_off, ds_len) < 0) - HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") - HDassert(ds_len[0] > 0); - - /* Update ss_nelem */ - HDassert(nelem > 0); - HDassert(nelem <= ds_nelem); - ds_nelem -= nelem; - - /* Reset source space index */ - ds_i = 0; - } /* end if */ - } /* end while */ + /* Set up ss_span_info */ + if(H5S_GET_SELECT_TYPE(src_space) == H5S_SEL_HYPERSLABS) { + /* Make certain the selection has a span tree */ + if(NULL == src_space->select.sel_info.hslab->span_lst) + if(H5S__hyper_generate_spans((H5S_t *)src_space) < 0) /* Casting away const OK -NAF */ + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "can't construct span tree for source hyperslab selection") - /* Add sequence to projected space */ - HDassert(ds_sel_off <= int_sel_off); - proj_off = ds_off[ds_i] + int_sel_off - ds_sel_off; - proj_len = proj_len_rem = (size_t)MIN(int_len, - (size_t)(ds_sel_off + (hsize_t)ds_len[ds_i] - - int_sel_off)); - - /* Add to span tree */ - while(proj_len_rem > (size_t)0) { - /* Check for more than one full row (in every dim) and - * append multiple spans at once? -NAF */ - /* Append spans in higher dimensions if we're going ouside - * the plane of the span currently being built (i.e. it's - * finished being built) */ - for(i = proj_rank - 1; ((i > 0) - && ((proj_off / proj_down_dims[i - 1]) - != curr_span_up_dim[i - 1])); i--) { - if(curr_span_tree[i]) { - HDassert(prev_span[i]); - - /* Append complete lower dimension span tree to - * current dimension */ - low = curr_span_up_dim[i - 1] % proj_space->extent.size[i - 1]; - if(H5S__hyper_append_span(&prev_span[i - 1], &curr_span_tree[i - 1], low, low, curr_span_tree[i], NULL) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* Simply point to existing span tree */ + ss_span_info = src_space->select.sel_info.hslab->span_lst; + } /* end if */ + else { + /* Create temporary span tree from all selection */ + HDassert(H5S_GET_SELECT_TYPE(src_space) == H5S_SEL_ALL); - /* Reset lower dimension's span tree and previous - * span since we just committed it and will start - * over with a new one */ - if(H5S__hyper_free_span_info(curr_span_tree[i]) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free span info") - curr_span_tree[i] = NULL; - prev_span[i] = NULL; - } /* end if */ + if(NULL == (ss_span_info_buf = H5S__hyper_make_spans(H5S_GET_EXTENT_NDIMS(src_space), + H5S_hyper_zeros_g, H5S_hyper_zeros_g, H5S_hyper_ones_g, src_space->extent.size))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't create span tree for ALL source space") + ss_span_info = ss_span_info_buf; + } /* end else */ - /* Update curr_span_up_dim */ - curr_span_up_dim[i - 1] = proj_off / proj_down_dims[i - 1]; - } /* end for */ + /* Set up ds_span_info */ + if(H5S_GET_SELECT_TYPE(dst_space) == H5S_SEL_HYPERSLABS) { + /* Make certain the selection has a span tree */ + if(NULL == dst_space->select.sel_info.hslab->span_lst) + if(H5S__hyper_generate_spans((H5S_t *)dst_space) < 0) /* Casting away const OK -NAF */ + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "can't construct span tree for dsetination hyperslab selection") - /* Compute bounds for new span in lowest dimension */ - low = proj_off % proj_space->extent.size[proj_rank - 1]; - span_len = MIN(proj_len_rem, - (size_t)(proj_space->extent.size[proj_rank - 1] - - low)); - HDassert(proj_len_rem >= span_len); - high = low + (hsize_t)span_len - (hsize_t)1; + /* Simply point to existing span tree */ + ds_span_info = dst_space->select.sel_info.hslab->span_lst; + } /* end if */ + else { + /* Create temporary span tree from all selection */ + HDassert(H5S_GET_SELECT_TYPE(dst_space) == H5S_SEL_ALL); - /* Append span in lowest dimension */ - if(H5S__hyper_append_span(&prev_span[proj_rank - 1], &curr_span_tree[proj_rank - 1], low, high, NULL, NULL) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + if(NULL == (ds_span_info_buf = H5S__hyper_make_spans(H5S_GET_EXTENT_NDIMS(dst_space), + H5S_hyper_zeros_g, H5S_hyper_zeros_g, H5S_hyper_ones_g, dst_space->extent.size))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't create span tree for ALL destination space") + ds_span_info = ds_span_info_buf; + } /* end else */ - /* Update remaining offset and length */ - proj_off += (hsize_t)span_len; - proj_len_rem -= span_len; - } /* end while */ + /* Make certain the source intersect selection has a span tree */ + if(NULL == src_intersect_space->select.sel_info.hslab->span_lst) + if(H5S__hyper_generate_spans((H5S_t *)src_intersect_space) < 0) /* Casting away const OK -NAF */ + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "can't construct span tree for source intersect hyperslab selection") + + /* Initialize udata */ + /* We will use op_info[0] for nelem and op_info[1] for copied spans */ + HDmemset(&udata, 0, sizeof(udata)); + udata.ds_span[0] = ds_span_info->head; + udata.ds_low[0] = udata.ds_span[0]->low; + udata.ss_rank = H5S_GET_EXTENT_NDIMS(src_space); + udata.ds_rank = H5S_GET_EXTENT_NDIMS(dst_space); + udata.op_gen = H5S__hyper_get_op_gen(); + udata.share_selection = share_selection; + + /* Iterate over selections and build projected span tree */ + if(H5S__hyper_proj_int_iterate(ss_span_info, src_intersect_space->select.sel_info.hslab->span_lst, 1, 0, &udata) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "selection iteration failed") - /* Update intersection sequence */ - int_sel_off += (hsize_t)proj_len; - int_len -= proj_len; - } /* end while */ - } /* end else */ - } /* end while */ + /* Remove current selection from proj_space */ + if(H5S_SELECT_RELEASE(proj_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") -loop_end: - /* Add remaining spans to span tree */ - for(i = proj_rank - 1; i > 0; i--) - if(curr_span_tree[i]) { - HDassert(prev_span[i]); + /* Check for elements in projected space */ + if(udata.ps_span_info[0]) { + /* Allocate space for the hyperslab selection information (note this sets + * diminfo_valid to FALSE, diminfo arrays to 0, and span list to NULL) */ + if(NULL == (proj_space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info") - /* Append remaining span tree to higher dimension */ - low = curr_span_up_dim[i - 1] % proj_space->extent.size[i - 1]; - if(H5S__hyper_append_span(&prev_span[i - 1], &curr_span_tree[i - 1], low, low, curr_span_tree[i], NULL) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + /* Set selection type */ + proj_space->select.type = H5S_sel_hyper; - /* Reset span tree */ - if(H5S__hyper_free_span_info(curr_span_tree[i]) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free span info") - curr_span_tree[i] = NULL; - } /* end if */ + /* Set unlim_dim */ + proj_space->select.sel_info.hslab->unlim_dim = -1; - /* Add span tree to proj_space */ - if(curr_span_tree[0]) { - proj_space->select.sel_info.hslab->span_lst = curr_span_tree[0]; - curr_span_tree[0] = NULL; + /* Set span tree */ + proj_space->select.sel_info.hslab->span_lst = udata.ps_span_info[0]; + udata.ps_span_info[0] = NULL; /* Set the number of elements in current selection */ proj_space->select.num_elem = H5S__hyper_spans_nelem(proj_space->select.sel_info.hslab->span_lst); - /* Attempt to rebuild "optimized" start/stride/count/block information. - * from resulting hyperslab span tree */ + /* Attempt to build "optimized" start/stride/count/block information + * from resulting hyperslab span tree. + */ H5S__hyper_rebuild(proj_space); } /* end if */ else @@ -9699,154 +11425,42 @@ loop_end: HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection") done: - /* Release source selection iterator */ - if(ss_iter_init && H5S_SELECT_ITER_RELEASE(ss_iter) < 0) - HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator") - if(ss_iter) - ss_iter = H5FL_FREE(H5S_sel_iter_t, ss_iter); - - /* Release destination selection iterator */ - if(ds_iter_init && H5S_SELECT_ITER_RELEASE(ds_iter) < 0) - HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator") - if(ds_iter) - ds_iter = H5FL_FREE(H5S_sel_iter_t, ds_iter); - - /* Release source intersect selection iterator */ - if(sis_iter_init && H5S_SELECT_ITER_RELEASE(sis_iter) < 0) - HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator") - if(sis_iter) - sis_iter = H5FL_FREE(H5S_sel_iter_t, sis_iter); + /* Free ss_span_info_buf */ + if(ss_span_info_buf) { + H5S__hyper_free_span_info(ss_span_info_buf); + ss_span_info_buf = NULL; + } /* end if */ + + /* Free ds_span_info_buf */ + if(ds_span_info_buf) { + H5S__hyper_free_span_info(ds_span_info_buf); + ds_span_info_buf = NULL; + } /* end if */ /* Cleanup on error */ if(ret_value < 0) { - /* Remove current selection from proj_space */ - if(H5S_SELECT_RELEASE(proj_space) < 0) - HDONE_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") + unsigned u; /* Free span trees */ - for(i = 0; i < proj_rank; i++) - if(curr_span_tree[i]) { - if(H5S__hyper_free_span_info(curr_span_tree[i]) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free span info") - curr_span_tree[i] = NULL; + for(u = 0; u < udata.ds_rank; u++) + if(udata.ps_span_info[u]) { + H5S__hyper_free_span_info(udata.ps_span_info[u]); + udata.ps_span_info[u] = NULL; } /* end if */ } /* end if */ - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_project_intersection() */ - - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_subtract - PURPOSE - Subtract one hyperslab selection from another - USAGE - herr_t H5S__hyper_subtract(space,subtract_space) - H5S_t *space; IN/OUT: Selection to be operated on - H5S_t *subtract_space; IN: Selection that will be subtracted from space - RETURNS - Non-negative on success/Negative on failure. - DESCRIPTION - Removes any and all portions of space that are also present in - subtract_space. In essence, performs an A_NOT_B operation with the - two selections. - - Note this function basically duplicates a subset of the functionality - of H5S_select_select(). It should probably be removed when that - function is enabled. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -herr_t -H5S__hyper_subtract(H5S_t *space, H5S_t *subtract_space) -{ - H5S_hyper_span_info_t *a_not_b = NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */ - H5S_hyper_span_info_t *a_and_b = NULL; /* Span tree for hyperslab spans in both old and new span trees */ - H5S_hyper_span_info_t *b_not_a = NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT - - /* Check args */ - HDassert(space); - HDassert(subtract_space); - - /* Check that the space selections both have span trees */ - if(space->select.sel_info.hslab->span_lst == NULL) - if(H5S__hyper_generate_spans(space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") - if(subtract_space->select.sel_info.hslab->span_lst == NULL) - if(H5S__hyper_generate_spans(subtract_space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") - - /* Generate lists of spans which overlap and don't overlap */ - if(H5S__hyper_clip_spans(space->select.sel_info.hslab->span_lst, subtract_space->select.sel_info.hslab->span_lst, &a_not_b, &a_and_b, &b_not_a)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") - - /* Reset the other dataspace selection information */ - if(H5S_SELECT_RELEASE(space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") - - /* Allocate space for the hyperslab selection information */ - if((space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)) == NULL) - HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info") - space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO; - - /* Set unlim_dim */ - space->select.sel_info.hslab->unlim_dim = -1; - - /* Check for anything returned in a_not_b */ - if(a_not_b) { - /* Update spans in space */ - space->select.sel_info.hslab->span_lst = a_not_b; - a_not_b = NULL; - - /* Update number of elements */ - space->select.num_elem = H5S__hyper_spans_nelem(space->select.sel_info.hslab->span_lst); - - /* Attempt to rebuild "optimized" start/stride/count/block information. - * from resulting hyperslab span tree */ - H5S__hyper_rebuild(space); - } /* end if */ - else { - H5S_hyper_span_info_t *spans; /* Empty hyperslab span tree */ - - /* Set number of elements */ - space->select.num_elem = 0; - - /* Allocate a span info node */ - if(NULL == (spans = H5FL_MALLOC(H5S_hyper_span_info_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span") - - /* Set the reference count */ - spans->count = 1; - - /* Reset the scratch pad space */ - spans->scratch = 0; - - /* Set to empty tree */ - spans->head = NULL; +#ifndef NDEBUG + /* Verify there are no more span trees */ + { + unsigned u; - /* Set pointer to empty span tree */ - space->select.sel_info.hslab->span_lst = spans; - } /* end if */ - -done: - /* Free span trees */ - if(a_and_b) - H5S__hyper_free_span_info(a_and_b); - if(b_not_a) - H5S__hyper_free_span_info(b_not_a); - if(a_not_b) { - HDassert(ret_value < 0); - H5S__hyper_free_span_info(b_not_a); - } /* end if */ + for(u = 0; u < H5S_MAX_RANK; u++) + HDassert(!udata.ps_span_info[u]); + } /* end block */ +#endif /* NDEBUG */ FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_subtract() */ +} /* end H5S__hyper_project_intersection() */ /*-------------------------------------------------------------------------- @@ -10018,6 +11632,13 @@ H5S_hyper_clip_unlim(H5S_t *space, hsize_t clip_size) hslab->diminfo_valid = H5S_DIMINFO_VALID_YES; } /* end else */ + /* Update the upper bound, if the diminfo is valid */ + if(hslab && (H5S_DIMINFO_VALID_YES == hslab->diminfo_valid)) + hslab->diminfo.high_bounds[orig_unlim_dim] = + hslab->diminfo.opt[orig_unlim_dim].start + + hslab->diminfo.opt[orig_unlim_dim].stride * (hslab->diminfo.opt[orig_unlim_dim].count - 1) + + (hslab->diminfo.opt[orig_unlim_dim].block - 1); + done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5S_hyper_clip_unlim() */ diff --git a/src/H5Smpio.c b/src/H5Smpio.c index 28bd253..147fd25 100644 --- a/src/H5Smpio.c +++ b/src/H5Smpio.c @@ -31,6 +31,7 @@ #include "H5private.h" /* Generic Functions */ #include "H5Dprivate.h" /* Datasets */ #include "H5Eprivate.h" /* Error handling */ +#include "H5FLprivate.h" /* Free Lists */ #include "H5MMprivate.h" /* Memory management */ #include "H5Spkg.h" /* Dataspaces */ #include "H5VMprivate.h" /* Vector and array functions */ @@ -50,6 +51,19 @@ /* Local Typedefs */ /******************/ +/* Node in linked list of MPI data types created during traversal of irregular hyperslab selection */ +typedef struct H5S_mpio_mpitype_node_t { + MPI_Datatype type; /* MPI Datatype */ + struct H5S_mpio_mpitype_node_t *next; /* Pointer to next node in list */ +} H5S_mpio_mpitype_node_t; + +/* List to track MPI data types generated during traversal of irregular hyperslab selection */ +typedef struct H5S_mpio_mpitype_list_t { + H5S_mpio_mpitype_node_t *head; /* Pointer to head of list */ + H5S_mpio_mpitype_node_t *tail; /* Pointer to tail of list */ +} H5S_mpio_mpitype_list_t; + + /********************/ /* Local Prototypes */ /********************/ @@ -65,12 +79,14 @@ static herr_t H5S__mpio_point_type(const H5S_t *space, size_t elmt_size, static herr_t H5S__mpio_permute_type(const H5S_t *space, size_t elmt_size, hsize_t **permute_map, MPI_Datatype *new_type, int *count, hbool_t *is_derived_type); -static herr_t H5S__mpio_hyper_type(const H5S_t *space, size_t elmt_size, +static herr_t H5S__mpio_reg_hyper_type(const H5S_t *space, size_t elmt_size, MPI_Datatype *new_type, int *count, hbool_t *is_derived_type); static herr_t H5S__mpio_span_hyper_type(const H5S_t *space, size_t elmt_size, MPI_Datatype *new_type, int *count, hbool_t *is_derived_type); -static herr_t H5S__obtain_datatype(const hsize_t down[], H5S_hyper_span_t* span, - const MPI_Datatype *elmt_type, MPI_Datatype *span_type, size_t elmt_size); +static herr_t H5S__release_datatype(H5S_mpio_mpitype_list_t *type_list); +static herr_t H5S__obtain_datatype(H5S_hyper_span_info_t *spans, const hsize_t *down, + size_t elmt_size, const MPI_Datatype *elmt_type, MPI_Datatype *span_type, + H5S_mpio_mpitype_list_t *type_list, unsigned op_info_i, uint64_t op_gen); /*****************************/ @@ -83,6 +99,8 @@ static herr_t H5S__obtain_datatype(const hsize_t down[], H5S_hyper_span_t* span, /*********************/ +/* Declare a free list to manage the H5S_mpio_mpitype_node_t struct */ +H5FL_DEFINE_STATIC(H5S_mpio_mpitype_node_t); /*------------------------------------------------------------------------- @@ -385,9 +403,12 @@ H5S__mpio_point_type(const H5S_t *space, size_t elmt_size, MPI_Datatype *new_typ /* Iterate through list of elements */ curr = space->select.sel_info.pnt_lst->head; for(u = 0 ; u < num_points ; u++) { - /* calculate the displacement of the current point */ - disp[u] = H5VM_array_offset(space->extent.rank, space->extent.size, curr->pnt); - disp[u] *= elmt_size; + /* Calculate the displacement of the current point */ + hsize_t disp_tmp = H5VM_array_offset(space->extent.rank, space->extent.size, curr->pnt); + if(disp_tmp > LONG_MAX) /* Maximum value of type long */ + HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "disp overflow") + disp[u] = (MPI_Aint)disp_tmp; + disp[u] *= (MPI_Aint)elmt_size; /* This is a File Space used to set the file view, so adjust the displacements * to have them monotonically non-decreasing. @@ -514,7 +535,7 @@ H5S__mpio_permute_type(const H5S_t *space, size_t elmt_size, hsize_t **permute, HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of displacements") /* Initialize selection iterator */ - if(H5S_select_iter_init(&sel_iter, space, elmt_size) < 0) + if(H5S_select_iter_init(&sel_iter, space, elmt_size, 0) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") sel_iter_init = TRUE; /* Selection iteration info has been initialized */ @@ -531,7 +552,7 @@ H5S__mpio_permute_type(const H5S_t *space, size_t elmt_size, hsize_t **permute, size_t curr_seq; /* Current sequence being worked on */ /* Get the sequences of bytes */ - if(H5S_SELECT_GET_SEQ_LIST(space, 0, &sel_iter, (size_t)H5D_IO_VECTOR_SIZE, max_elem, &nseq, &nelem, off, len) < 0) + if(H5S_SELECT_ITER_GET_SEQ_LIST(&sel_iter, (size_t)H5D_IO_VECTOR_SIZE, max_elem, &nseq, &nelem, off, len) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") /* Loop, while sequences left to process */ @@ -548,7 +569,9 @@ H5S__mpio_permute_type(const H5S_t *space, size_t elmt_size, hsize_t **permute, /* Loop, while bytes left in sequence */ while(curr_len > 0) { /* Set the displacement of the current point */ - disp[u] = curr_off; + if(curr_off > LONG_MAX) + HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "curr_off overflow") + disp[u] = (MPI_Aint)curr_off; /* This is a memory displacement, so for each point selected, * apply the map that was generated by the file selection */ @@ -602,9 +625,9 @@ done: /*------------------------------------------------------------------------- - * Function: H5S__mpio_hyper_type + * Function: H5S__mpio_reg_hyper_type * - * Purpose: Translate an HDF5 hyperslab selection into an MPI type. + * Purpose: Translate a regular HDF5 hyperslab selection into an MPI type. * * Return: Non-negative on success, negative on failure. * @@ -618,7 +641,7 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5S__mpio_hyper_type(const H5S_t *space, size_t elmt_size, +H5S__mpio_reg_hyper_type(const H5S_t *space, size_t elmt_size, MPI_Datatype *new_type, int *count, hbool_t *is_derived_type) { H5S_sel_iter_t sel_iter; /* Selection iteration info */ @@ -653,7 +676,7 @@ H5S__mpio_hyper_type(const H5S_t *space, size_t elmt_size, bigio_count = H5_mpi_get_bigio_count(); /* Initialize selection iterator */ - if(H5S_select_iter_init(&sel_iter, space, elmt_size) < 0) + if(H5S_select_iter_init(&sel_iter, space, elmt_size, 0) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") sel_iter_init = TRUE; /* Selection iteration info has been initialized */ @@ -667,7 +690,6 @@ H5S__mpio_hyper_type(const H5S_t *space, size_t elmt_size, if(sel_iter.u.hyp.iter_rank != 0 && sel_iter.u.hyp.iter_rank < space->extent.rank) { /* Flattened selection */ rank = sel_iter.u.hyp.iter_rank; - HDassert(rank <= H5S_MAX_RANK); /* within array bounds */ #ifdef H5S_DEBUG if(H5DEBUG(S)) HDfprintf(H5DEBUG(S), "%s: Flattened selection\n",FUNC); @@ -700,9 +722,6 @@ if(H5DEBUG(S)) { else { /* Non-flattened selection */ rank = space->extent.rank; - HDassert(rank <= H5S_MAX_RANK); /* within array bounds */ - if(0 == rank) - goto empty; #ifdef H5S_DEBUG if(H5DEBUG(S)) HDfprintf(H5DEBUG(S),"%s: Non-flattened selection\n",FUNC); @@ -880,8 +899,14 @@ if(H5DEBUG(S)) ****************************************/ /* Calculate start and extent values of this dimension */ - start_disp = d[i].start * offset[i] * elmt_size; - new_extent = (MPI_Aint)elmt_size * max_xtent[i]; + /* Check if value overflow to cast to type MPI_Aint */ + if(d[i].start > LONG_MAX || offset[i] > LONG_MAX || elmt_size > LONG_MAX) + HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "result overflow") + start_disp = (MPI_Aint)d[i].start * (MPI_Aint)offset[i] * (MPI_Aint)elmt_size; + + if(max_xtent[i] > LONG_MAX) + HGOTO_ERROR(H5E_DATASET, H5E_BADVALUE, FAIL, "max_xtent overflow") + new_extent = (MPI_Aint)elmt_size * (MPI_Aint)max_xtent[i]; if(MPI_SUCCESS != (mpi_code = MPI_Type_get_extent(outer_type, &lb, &extent_len))) HMPI_GOTO_ERROR(FAIL, "MPI_Type_get_extent failed", mpi_code) @@ -921,13 +946,6 @@ if(H5DEBUG(S)) /* fill in the remaining return values */ *count = 1; /* only have to move one of these suckers! */ *is_derived_type = TRUE; - HGOTO_DONE(SUCCEED); - -empty: - /* special case: empty hyperslab */ - *new_type = MPI_BYTE; - *count = 0; - *is_derived_type = FALSE; done: /* Release selection iterator */ @@ -940,7 +958,7 @@ if(H5DEBUG(S)) HDfprintf(H5DEBUG(S), "Leave %s, count=%ld is_derived_type=%t\n", FUNC, *count, *is_derived_type); #endif FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__mpio_hyper_type() */ +} /* end H5S__mpio_reg_hyper_type() */ /*------------------------------------------------------------------------- @@ -964,11 +982,13 @@ static herr_t H5S__mpio_span_hyper_type(const H5S_t *space, size_t elmt_size, MPI_Datatype *new_type, int *count, hbool_t *is_derived_type) { + H5S_mpio_mpitype_list_t type_list; /* List to track MPI data types created */ MPI_Datatype elmt_type; /* MPI datatype for an element */ hbool_t elmt_type_is_derived = FALSE; /* Whether the element type has been created */ MPI_Datatype span_type; /* MPI datatype for overall span tree */ hsize_t bigio_count; /* Transition point to create derived type */ hsize_t down[H5S_MAX_RANK]; /* 'down' sizes for each dimension */ + uint64_t op_gen; /* Operation generation value */ int mpi_code; /* MPI return code */ herr_t ret_value = SUCCEED; /* Return value */ @@ -995,12 +1015,23 @@ H5S__mpio_span_hyper_type(const H5S_t *space, size_t elmt_size, if(H5VM_array_down(space->extent.rank, space->extent.size, down) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGETSIZE, FAIL, "couldn't compute 'down' dimension sizes") - /* Obtain derived data type */ - if(H5S__obtain_datatype(down, space->select.sel_info.hslab->span_lst->head, &elmt_type, &span_type, elmt_size) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't obtain MPI derived data type") - if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(&span_type))) + /* Acquire an operation generation value for creating MPI datatypes */ + op_gen = H5S__hyper_get_op_gen(); + + /* Obtain derived MPI data type */ + /* Always use op_info[0] since we own this op_info, so there can be no + * simultaneous operations */ + type_list.head = type_list.tail = NULL; + if(H5S__obtain_datatype(space->select.sel_info.hslab->span_lst, down, elmt_size, &elmt_type, &span_type, &type_list, 0, op_gen) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't obtain MPI derived data type") + if(MPI_SUCCESS != (mpi_code = MPI_Type_dup(span_type, new_type))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code) + if(MPI_SUCCESS != (mpi_code = MPI_Type_commit(new_type))) HMPI_GOTO_ERROR(FAIL, "MPI_Type_commit failed", mpi_code) - *new_type = span_type; + + /* Release MPI data types generated during span tree traversal */ + if(H5S__release_datatype(&type_list) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "couldn't release MPI derived data type") /* fill in the remaining return values */ *count = 1; @@ -1017,6 +1048,53 @@ done: /*------------------------------------------------------------------------- + * Function: H5S__release_datatype + * + * Purpose: Release the MPI derived datatypes for span-tree hyperslab selection + * + * Return: Non-negative on success, negative on failure. + * + * Programmer: Quincey Koziol, February 2, 2019 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S__release_datatype(H5S_mpio_mpitype_list_t *type_list) +{ + H5S_mpio_mpitype_node_t *curr; /* Pointer to head of list */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity check */ + HDassert(type_list); + + /* Iterate over the list, freeing the MPI data types */ + curr = type_list->head; + while(curr) { + H5S_mpio_mpitype_node_t *next; /* Pointer to next node in list */ + int mpi_code; /* MPI return status code */ + + /* Release the MPI data type for this span tree */ + if(MPI_SUCCESS != (mpi_code = MPI_Type_free(&curr->type))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + + /* Get pointer to next node in list */ + next = curr->next; + + /* Free the current node */ + curr = H5FL_FREE(H5S_mpio_mpitype_node_t, curr); + + /* Advance to next node */ + curr = next; + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__release_datatype() */ + + +/*------------------------------------------------------------------------- * Function: H5S__obtain_datatype * * Purpose: Obtain an MPI derived datatype for span-tree hyperslab selection @@ -1030,8 +1108,9 @@ done: *------------------------------------------------------------------------- */ static herr_t -H5S__obtain_datatype(const hsize_t *down, H5S_hyper_span_t *spans, - const MPI_Datatype *elmt_type, MPI_Datatype *span_type, size_t elmt_size) +H5S__obtain_datatype(H5S_hyper_span_info_t *spans, const hsize_t *down, + size_t elmt_size, const MPI_Datatype *elmt_type, MPI_Datatype *span_type, + H5S_mpio_mpitype_list_t *type_list, unsigned op_info_i, uint64_t op_gen) { H5S_hyper_span_t *span; /* Hyperslab span to iterate with */ hsize_t bigio_count; /* Transition point to create derived type */ @@ -1039,8 +1118,6 @@ H5S__obtain_datatype(const hsize_t *down, H5S_hyper_span_t *spans, size_t outercount = 0; /* Number of span tree nodes at this level */ MPI_Datatype *inner_type = NULL; hbool_t inner_types_freed = FALSE; /* Whether the inner_type MPI datatypes have been freed */ - hbool_t span_type_valid = FALSE; /* Whether the span_type MPI datatypes is valid */ - hbool_t large_block = FALSE; /* Wether the block length is larger than 32 bit integer */ int *blocklen = NULL; MPI_Aint *disp = NULL; size_t u; /* Local index variable */ @@ -1051,173 +1128,194 @@ H5S__obtain_datatype(const hsize_t *down, H5S_hyper_span_t *spans, /* Sanity check */ HDassert(spans); + HDassert(type_list); bigio_count = H5_mpi_get_bigio_count(); - /* Allocate the initial displacement & block length buffers */ - alloc_count = H5S_MPIO_INITIAL_ALLOC_COUNT; - if(NULL == (disp = (MPI_Aint *)H5MM_malloc(alloc_count * sizeof(MPI_Aint)))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of displacements") - if(NULL == (blocklen = (int *)H5MM_malloc(alloc_count * sizeof(int)))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of block lengths") - - /* if this is the fastest changing dimension, it is the base case for derived datatype. */ - if(NULL == spans->down) { - span = spans; - outercount = 0; - while(span) { - /* Check if we need to increase the size of the buffers */ - if(outercount >= alloc_count) { - MPI_Aint *tmp_disp; /* Temporary pointer to new displacement buffer */ - int *tmp_blocklen; /* Temporary pointer to new block length buffer */ - - /* Double the allocation count */ - alloc_count *= 2; - - /* Re-allocate the buffers */ - if(NULL == (tmp_disp = (MPI_Aint *)H5MM_realloc(disp, alloc_count * sizeof(MPI_Aint)))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of displacements") - disp = tmp_disp; - if(NULL == (tmp_blocklen = (int *)H5MM_realloc(blocklen, alloc_count * sizeof(int)))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of block lengths") - blocklen = tmp_blocklen; + /* Check if we've visited this span tree before */ + if(spans->op_info[op_info_i].op_gen != op_gen) { + H5S_mpio_mpitype_node_t *type_node; /* Pointer to new node in MPI data type list */ + + /* Allocate the initial displacement & block length buffers */ + alloc_count = H5S_MPIO_INITIAL_ALLOC_COUNT; + if(NULL == (disp = (MPI_Aint *)H5MM_malloc(alloc_count * sizeof(MPI_Aint)))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of displacements") + if(NULL == (blocklen = (int *)H5MM_malloc(alloc_count * sizeof(int)))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of block lengths") + + /* If this is the fastest changing dimension, it is the base case for derived datatype. */ + span = spans->head; + if(NULL == span->down) { + hbool_t large_block = FALSE; /* Wether the block length is larger than 32 bit integer */ + + outercount = 0; + while(span) { + hsize_t nelmts; /* # of elements covered by current span */ + + /* Check if we need to increase the size of the buffers */ + if(outercount >= alloc_count) { + MPI_Aint *tmp_disp; /* Temporary pointer to new displacement buffer */ + int *tmp_blocklen; /* Temporary pointer to new block length buffer */ + + /* Double the allocation count */ + alloc_count *= 2; + + /* Re-allocate the buffers */ + if(NULL == (tmp_disp = (MPI_Aint *)H5MM_realloc(disp, alloc_count * sizeof(MPI_Aint)))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of displacements") + disp = tmp_disp; + if(NULL == (tmp_blocklen = (int *)H5MM_realloc(blocklen, alloc_count * sizeof(int)))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of block lengths") + blocklen = tmp_blocklen; + } /* end if */ + + /* Compute the number of elements to attempt in this span */ + nelmts = (span->high - span->low) + 1; + + /* Store displacement & block length */ + disp[outercount] = (MPI_Aint)elmt_size * (MPI_Aint)span->low; + H5_CHECK_OVERFLOW(nelmts, hsize_t, int) + blocklen[outercount] = (int)nelmts; + + if(bigio_count < (hsize_t)blocklen[outercount]) + large_block = TRUE; /* at least one block type is large, so set this flag to true */ + + span = span->next; + outercount++; + } /* end while */ + + /* Everything fits into integers, so cast them and use hindexed */ + if(bigio_count >= outercount && large_block == FALSE) { + if(MPI_SUCCESS != (mpi_code = MPI_Type_create_hindexed((int)outercount, blocklen, disp, *elmt_type, &spans->op_info[op_info_i].u.down_type))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hindexed failed", mpi_code) } /* end if */ + else { /* LARGE_DATATYPE:: Something doesn't fit into a 32 bit integer */ + for(u = 0 ; u < outercount; u++) { + MPI_Datatype temp_type = MPI_DATATYPE_NULL; + + /* create the block type from elmt_type while checking the 32 bit int limit */ + if((hsize_t)(blocklen[u]) > bigio_count) { + if(H5_mpio_create_large_type((hsize_t)blocklen[u], 0, *elmt_type, &temp_type) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create a large element datatype in span_hyper selection") + } /* end if */ + else + if(MPI_SUCCESS != (mpi_code = MPI_Type_contiguous((int)blocklen[u], *elmt_type, &temp_type))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_contiguous failed", mpi_code) + + /* Combine the current datatype that is created with this current block type */ + if(0 == u) /* first iteration, there is no combined datatype yet */ + spans->op_info[op_info_i].u.down_type = temp_type; + else { + int bl[2] = {1, 1}; + MPI_Aint ds[2] = {disp[u - 1], disp[u]}; + MPI_Datatype dt[2] = {spans->op_info[op_info_i].u.down_type, temp_type}; + + if(MPI_SUCCESS != (mpi_code = MPI_Type_create_struct(2, /* count */ + bl, /* blocklength */ + ds, /* stride in bytes*/ + dt, /* old type */ + &spans->op_info[op_info_i].u.down_type))) /* new type */ + HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_struct failed", mpi_code) + + /* Release previous temporary datatype */ + if(MPI_SUCCESS != (mpi_code = MPI_Type_free(&temp_type))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + } /* end else */ + } /* end for */ + } /* end else (LARGE_DATATYPE::) */ + } /* end if */ + else { + MPI_Aint stride; /* Distance between inner MPI datatypes */ - /* Store displacement & block length */ - disp[outercount] = (MPI_Aint)elmt_size * span->low; - H5_CHECK_OVERFLOW(span->nelem, hsize_t, int) - blocklen[outercount] = (int)span->nelem; - span = span->next; + if(NULL == (inner_type = (MPI_Datatype *)H5MM_malloc(alloc_count * sizeof(MPI_Datatype)))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of inner MPI datatypes") - if (bigio_count < blocklen[outercount]) { - large_block = TRUE; /* at least one block type is large, so set this flag to true */ - } + /* Calculate the total bytes of the lower dimension */ + stride = (MPI_Aint)(*down) * (MPI_Aint)elmt_size; + + /* Loop over span nodes */ + outercount = 0; + while(span) { + MPI_Datatype down_type; /* Temporary MPI datatype for a span tree node's children */ + hsize_t nelmts; /* # of elements covered by current span */ + + /* Check if we need to increase the size of the buffers */ + if(outercount >= alloc_count) { + MPI_Aint *tmp_disp; /* Temporary pointer to new displacement buffer */ + int *tmp_blocklen; /* Temporary pointer to new block length buffer */ + MPI_Datatype *tmp_inner_type; /* Temporary pointer to inner MPI datatype buffer */ + + /* Double the allocation count */ + alloc_count *= 2; + + /* Re-allocate the buffers */ + if(NULL == (tmp_disp = (MPI_Aint *)H5MM_realloc(disp, alloc_count * sizeof(MPI_Aint)))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of displacements") + disp = tmp_disp; + if(NULL == (tmp_blocklen = (int *)H5MM_realloc(blocklen, alloc_count * sizeof(int)))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of block lengths") + blocklen = tmp_blocklen; + if(NULL == (tmp_inner_type = (MPI_Datatype *)H5MM_realloc(inner_type, alloc_count * sizeof(MPI_Datatype)))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of inner MPI datatypes") + inner_type = tmp_inner_type; + } /* end if */ - outercount++; - } /* end while */ + /* Displacement should be in byte and should have dimension information */ + /* First using MPI Type vector to build derived data type for this span only */ + /* Need to calculate the disp in byte for this dimension. */ + disp[outercount] = (MPI_Aint)span->low * stride; + blocklen[outercount] = 1; - /* Everything fits into integers, so cast them and use hindexed */ - if(bigio_count >= outercount && large_block == FALSE) { + /* Generate MPI datatype for next dimension down */ + if(H5S__obtain_datatype(span->down, down + 1, elmt_size, elmt_type, &down_type, type_list, op_info_i, op_gen) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't obtain MPI derived data type") - if(MPI_SUCCESS != (mpi_code = MPI_Type_create_hindexed((int)outercount, blocklen, disp, *elmt_type, span_type))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hindexed failed", mpi_code) - span_type_valid = TRUE; - } - else { /* LARGE_DATATYPE:: Something doesn't fit into a 32 bit integer */ - size_t i; - - for(i=0 ; i bigio_count) { - if(H5_mpio_create_large_type (blocklen[i], 0, *elmt_type, &temp_type) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't create a large element datatype in span_hyper selection") - } - else - if(MPI_SUCCESS != (mpi_code = MPI_Type_contiguous((int)blocklen[i], *elmt_type, &temp_type))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_contiguous failed", mpi_code) - - /* combine the current datatype that is created with this current block type */ - if(0 == i) { /* first iteration, there is no combined datatype yet */ - *span_type = temp_type; - } - else { - int bl[2] = {1,1}; - MPI_Aint ds[2] = {disp[i-1],disp[i]}; - MPI_Datatype dt[2] = {*span_type, temp_type}; - - if(MPI_SUCCESS != (mpi_code = MPI_Type_create_struct (2, /* count */ - bl, /* blocklength */ - ds, /* stride in bytes*/ - dt, /* old type */ - &outer_type))){ /* new type */ - HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_struct failed", mpi_code) - } - *span_type = outer_type; - } - - if(outer_type != MPI_DATATYPE_NULL) - MPI_Type_free(&outer_type); - /* temp_type shouldn't be freed here... - * Note that we have simply copied it above (not MPI_Type_dup) - * into the 'span_type' argument of the caller. - * The caller needs to deal with it there! - */ - } - } /* end (LARGE_DATATYPE::) */ + /* Compute the number of elements to attempt in this span */ + nelmts = (span->high - span->low) + 1; - } /* end if */ - else { + /* Build the MPI datatype for this node */ + H5_CHECK_OVERFLOW(nelmts, hsize_t, int) + if(MPI_SUCCESS != (mpi_code = MPI_Type_create_hvector((int)nelmts, 1, stride, down_type, &inner_type[outercount]))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hvector failed", mpi_code) - if(NULL == (inner_type = (MPI_Datatype *)H5MM_malloc(alloc_count * sizeof(MPI_Datatype)))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of inner MPI datatypes") + span = span->next; + outercount++; + } /* end while */ - span = spans; - outercount = 0; - while(span) { - MPI_Datatype down_type; /* Temporary MPI datatype for a span tree node's children */ - MPI_Aint stride; /* Distance between inner MPI datatypes */ + /* Building the whole vector datatype */ + H5_CHECK_OVERFLOW(outercount, size_t, int) + if(MPI_SUCCESS != (mpi_code = MPI_Type_create_struct((int)outercount, blocklen, disp, inner_type, &spans->op_info[op_info_i].u.down_type))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_struct failed", mpi_code) - /* Check if we need to increase the size of the buffers */ - if(outercount >= alloc_count) { - MPI_Aint *tmp_disp; /* Temporary pointer to new displacement buffer */ - int *tmp_blocklen; /* Temporary pointer to new block length buffer */ - MPI_Datatype *tmp_inner_type; /* Temporary pointer to inner MPI datatype buffer */ - - /* Double the allocation count */ - alloc_count *= 2; - - /* Re-allocate the buffers */ - if(NULL == (tmp_disp = (MPI_Aint *)H5MM_realloc(disp, alloc_count * sizeof(MPI_Aint)))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of displacements") - disp = tmp_disp; - if(NULL == (tmp_blocklen = (int *)H5MM_realloc(blocklen, alloc_count * sizeof(int)))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of block lengths") - blocklen = tmp_blocklen; - if(NULL == (tmp_inner_type = (MPI_Datatype *)H5MM_realloc(inner_type, alloc_count * sizeof(MPI_Datatype)))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate array of inner MPI datatypes") - inner_type = tmp_inner_type; - } /* end if */ + /* Release inner node types */ + for(u = 0; u < outercount; u++) + if(MPI_SUCCESS != (mpi_code = MPI_Type_free(&inner_type[u]))) + HMPI_GOTO_ERROR(FAIL, "MPI_Type_free failed", mpi_code) + inner_types_freed = TRUE; + } /* end else */ - /* Displacement should be in byte and should have dimension information */ - /* First using MPI Type vector to build derived data type for this span only */ - /* Need to calculate the disp in byte for this dimension. */ - /* Calculate the total bytes of the lower dimension */ - disp[outercount] = span->low * (*down) * elmt_size; - blocklen[outercount] = 1; - - /* Generate MPI datatype for next dimension down */ - if(H5S__obtain_datatype(down + 1, span->down->head, elmt_type, &down_type, elmt_size) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "couldn't obtain MPI derived data type") - - /* Build the MPI datatype for this node */ - stride = (*down) * elmt_size; - H5_CHECK_OVERFLOW(span->nelem, hsize_t, int) - if(MPI_SUCCESS != (mpi_code = MPI_Type_create_hvector((int)span->nelem, 1, stride, down_type, &inner_type[outercount]))) { - MPI_Type_free(&down_type); - HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_hvector failed", mpi_code) - } /* end if */ + /* Allocate space for the MPI data type list node */ + if(NULL == (type_node = H5FL_MALLOC(H5S_mpio_mpitype_node_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate MPI data type list node") + + /* Set up MPI type node */ + type_node->type = spans->op_info[op_info_i].u.down_type; + type_node->next = NULL; + + /* Add MPI type node to list */ + if(type_list->head == NULL) + type_list->head = type_list->tail = type_node; + else { + type_list->tail->next = type_node; + type_list->tail = type_node; + } /* end else */ - /* Release MPI datatype for next dimension down */ - if(MPI_SUCCESS != (mpi_code = MPI_Type_free(&down_type))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_free failed", mpi_code) - - span = span->next; - outercount++; - } /* end while */ - - /* building the whole vector datatype */ - H5_CHECK_OVERFLOW(outercount, size_t, int) - if(MPI_SUCCESS != (mpi_code = MPI_Type_create_struct((int)outercount, blocklen, disp, inner_type, span_type))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_create_struct failed", mpi_code) - span_type_valid = TRUE; - - /* Release inner node types */ - for(u = 0; u < outercount; u++) - if(MPI_SUCCESS != (mpi_code = MPI_Type_free(&inner_type[u]))) - HMPI_GOTO_ERROR(FAIL, "MPI_Type_free failed", mpi_code) - inner_types_freed = TRUE; + /* Remember that we've visited this span tree */ + spans->op_info[op_info_i].op_gen = op_gen; } /* end else */ + /* Return MPI data type for span tree */ + *span_type = spans->op_info[op_info_i].u.down_type; + done: /* General cleanup */ if(inner_type != NULL) { @@ -1232,13 +1330,6 @@ done: if(disp != NULL) H5MM_free(disp); - /* Error cleanup */ - if(ret_value < 0) { - if(span_type_valid) - if(MPI_SUCCESS != (mpi_code = MPI_Type_free(span_type))) - HMPI_DONE_ERROR(FAIL, "MPI_Type_free failed", mpi_code) - } /* end if */ - FUNC_LEAVE_NOAPI(ret_value) } /* end H5S__obtain_datatype() */ @@ -1326,7 +1417,7 @@ H5S_mpio_space_type(const H5S_t *space, size_t elmt_size, MPI_Datatype *new_type case H5S_SEL_HYPERSLABS: if((H5S_SELECT_IS_REGULAR(space) == TRUE)) { - if(H5S__mpio_hyper_type(space, elmt_size, new_type, count, is_derived_type) < 0) + if(H5S__mpio_reg_hyper_type(space, elmt_size, new_type, count, is_derived_type) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL,"couldn't convert regular 'hyperslab' selection to MPI type") } /* end if */ else diff --git a/src/H5Snone.c b/src/H5Snone.c index 1546d0b..672302d 100644 --- a/src/H5Snone.c +++ b/src/H5Snone.c @@ -33,7 +33,6 @@ #include "H5Iprivate.h" /* ID Functions */ #include "H5Spkg.h" /* Dataspace functions */ #include "H5VMprivate.h" /* Vector functions */ -#include "H5Dprivate.h" /****************/ @@ -52,9 +51,6 @@ /* Selection callbacks */ static herr_t H5S__none_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection); -static herr_t H5S__none_get_seq_list(const H5S_t *space, unsigned flags, - H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes, - size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); static herr_t H5S__none_release(H5S_t *space); static htri_t H5S__none_is_valid(const H5S_t *space); static hssize_t H5S__none_serial_size(const H5S_t *space); @@ -66,7 +62,11 @@ static int H5S__none_unlim_dim(const H5S_t *space); static htri_t H5S__none_is_contiguous(const H5S_t *space); static htri_t H5S__none_is_single(const H5S_t *space); static htri_t H5S__none_is_regular(const H5S_t *space); +static htri_t H5S__none_shape_same(const H5S_t *space1, const H5S_t *space2); +static htri_t H5S__none_intersect_block(const H5S_t *space, const hsize_t *start, + const hsize_t *end); static herr_t H5S__none_adjust_u(H5S_t *space, const hsize_t *offset); +static herr_t H5S__none_adjust_s(H5S_t *space, const hssize_t *offset); static herr_t H5S__none_project_scalar(const H5S_t *space, hsize_t *offset); static herr_t H5S__none_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset); static herr_t H5S__none_iter_init(const H5S_t *space, H5S_sel_iter_t *iter); @@ -78,6 +78,8 @@ static hsize_t H5S__none_iter_nelmts(const H5S_sel_iter_t *iter); static htri_t H5S__none_iter_has_next_block(const H5S_sel_iter_t *iter); static herr_t H5S__none_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem); static herr_t H5S__none_iter_next_block(H5S_sel_iter_t *sel_iter); +static herr_t H5S__none_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq, + size_t maxbytes, size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); static herr_t H5S__none_iter_release(H5S_sel_iter_t *sel_iter); @@ -96,7 +98,6 @@ const H5S_select_class_t H5S_sel_none[1] = {{ /* Methods on selection */ H5S__none_copy, - H5S__none_get_seq_list, H5S__none_release, H5S__none_is_valid, H5S__none_serial_size, @@ -109,7 +110,10 @@ const H5S_select_class_t H5S_sel_none[1] = {{ H5S__none_is_contiguous, H5S__none_is_single, H5S__none_is_regular, + H5S__none_shape_same, + H5S__none_intersect_block, H5S__none_adjust_u, + H5S__none_adjust_s, H5S__none_project_scalar, H5S__none_project_simple, H5S__none_iter_init, @@ -131,6 +135,7 @@ static const H5S_sel_iter_class_t H5S_sel_iter_none[1] = {{ H5S__none_iter_has_next_block, H5S__none_iter_next, H5S__none_iter_next_block, + H5S__none_iter_get_seq_list, H5S__none_iter_release, }}; @@ -332,6 +337,61 @@ H5S__none_iter_next_block(H5S_sel_iter_t H5_ATTR_UNUSED *iter) /*-------------------------------------------------------------------------- NAME + H5S__none_iter_get_seq_list + PURPOSE + Create a list of offsets & lengths for a selection + USAGE + herr_t H5S__none_iter_get_seq_list(iter,maxseq,maxelem,nseq,nelem,off,len) + H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last + position of interest in selection. + size_t maxseq; IN: Maximum number of sequences to generate + size_t maxelem; IN: Maximum number of elements to include in the + generated sequences + size_t *nseq; OUT: Actual number of sequences generated + size_t *nelem; OUT: Actual number of elements in sequences generated + hsize_t *off; OUT: Array of offsets + size_t *len; OUT: Array of lengths + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + Use the selection in the dataspace to generate a list of byte offsets and + lengths for the region(s) selected. Start/Restart from the position in the + ITER parameter. The number of sequences generated is limited by the MAXSEQ + parameter and the number of sequences actually generated is stored in the + NSEQ parameter. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__none_iter_get_seq_list(H5S_sel_iter_t H5_ATTR_UNUSED *iter, + size_t H5_ATTR_UNUSED maxseq, size_t H5_ATTR_UNUSED maxelem, size_t *nseq, + size_t *nelem, hsize_t H5_ATTR_UNUSED *off, size_t H5_ATTR_UNUSED *len) +{ + FUNC_ENTER_STATIC_NOERR + + /* Check args */ + HDassert(iter); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); + + /* "none" selections don't generate sequences of bytes */ + *nseq = 0; + + /* They don't use any elements, either */ + *nelem = 0; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__none_iter_get_seq_list() */ + + +/*-------------------------------------------------------------------------- + NAME H5S__none_iter_release PURPOSE Release "none" selection iterator information for a dataspace @@ -797,6 +857,74 @@ H5S__none_is_regular(const H5S_t H5_ATTR_UNUSED *space) /*-------------------------------------------------------------------------- NAME + H5S__none_shape_same + PURPOSE + Check if a two "none" selections are the same shape + USAGE + htri_t H5S__none_shape_same(space1, space2) + const H5S_t *space1; IN: First dataspace to check + const H5S_t *space2; IN: Second dataspace to check + RETURNS + TRUE / FALSE / FAIL + DESCRIPTION + Checks to see if the current selection in each dataspace are the same + shape. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static htri_t +H5S__none_shape_same(const H5S_t H5_ATTR_UNUSED *space1, + const H5S_t H5_ATTR_UNUSED *space2) +{ + FUNC_ENTER_STATIC_NOERR + + /* Check args */ + HDassert(space1); + HDassert(space2); + + FUNC_LEAVE_NOAPI(TRUE) +} /* end H5S__none_shape_same() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__none_intersect_block + PURPOSE + Detect intersections of selection with block + USAGE + htri_t H5S__none_intersect_block(space, start, end) + const H5S_t *space; IN: Dataspace with selection to use + const hsize_t *start; IN: Starting coordinate for block + const hsize_t *end; IN: Ending coordinate for block + RETURNS + Non-negative TRUE / FALSE on success, negative on failure + DESCRIPTION + Quickly detect intersections with a block + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5S__none_intersect_block(const H5S_t H5_ATTR_UNUSED *space, + const hsize_t H5_ATTR_UNUSED *start, const hsize_t H5_ATTR_UNUSED *end) +{ + FUNC_ENTER_STATIC_NOERR + + /* Sanity check */ + HDassert(space); + HDassert(H5S_SEL_NONE == H5S_GET_SELECT_TYPE(space)); + HDassert(start); + HDassert(end); + + FUNC_LEAVE_NOAPI(FALSE) +} /* end H5S__none_intersect_block() */ + + +/*-------------------------------------------------------------------------- + NAME H5S__none_adjust_u PURPOSE Adjust an "none" selection by subtracting an offset @@ -826,6 +954,37 @@ H5S__none_adjust_u(H5S_t H5_ATTR_UNUSED *space, const hsize_t H5_ATTR_UNUSED *of } /* end H5S__none_adjust_u() */ +/*-------------------------------------------------------------------------- + NAME + H5S__none_adjust_s + PURPOSE + Adjust an "none" selection by subtracting an offset + USAGE + herr_t H5S__none_adjust_u(space, offset) + H5S_t *space; IN/OUT: Pointer to dataspace to adjust + const hssize_t *offset; IN: Offset to subtract + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Moves selection by subtracting an offset from it. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__none_adjust_s(H5S_t H5_ATTR_UNUSED *space, const hssize_t H5_ATTR_UNUSED *offset) +{ + FUNC_ENTER_STATIC_NOERR + + /* Check args */ + HDassert(space); + HDassert(offset); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__none_adjust_s() */ + + /*------------------------------------------------------------------------- * Function: H5S__none_project_scalar * @@ -966,61 +1125,3 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Sselect_none() */ - -/*-------------------------------------------------------------------------- - NAME - H5S__none_get_seq_list - PURPOSE - Create a list of offsets & lengths for a selection - USAGE - herr_t H5S__none_get_seq_list(space,flags,iter,maxseq,maxelem,nseq,nelem,off,len) - H5S_t *space; IN: Dataspace containing selection to use. - unsigned flags; IN: Flags for extra information about operation - H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last - position of interest in selection. - size_t maxseq; IN: Maximum number of sequences to generate - size_t maxelem; IN: Maximum number of elements to include in the - generated sequences - size_t *nseq; OUT: Actual number of sequences generated - size_t *nelem; OUT: Actual number of elements in sequences generated - hsize_t *off; OUT: Array of offsets - size_t *len; OUT: Array of lengths - RETURNS - Non-negative on success/Negative on failure. - DESCRIPTION - Use the selection in the dataspace to generate a list of byte offsets and - lengths for the region(s) selected. Start/Restart from the position in the - ITER parameter. The number of sequences generated is limited by the MAXSEQ - parameter and the number of sequences actually generated is stored in the - NSEQ parameter. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5S__none_get_seq_list(const H5S_t H5_ATTR_UNUSED *space, unsigned H5_ATTR_UNUSED flags, H5S_sel_iter_t H5_ATTR_UNUSED *iter, - size_t H5_ATTR_UNUSED maxseq, size_t H5_ATTR_UNUSED maxelem, size_t *nseq, size_t *nelem, - hsize_t H5_ATTR_UNUSED *off, size_t H5_ATTR_UNUSED *len) -{ - FUNC_ENTER_STATIC_NOERR - - /* Check args */ - HDassert(space); - HDassert(iter); - HDassert(maxseq > 0); - HDassert(maxelem > 0); - HDassert(nseq); - HDassert(nelem); - HDassert(off); - HDassert(len); - - /* "none" selections don't generate sequences of bytes */ - *nseq = 0; - - /* They don't use any elements, either */ - *nelem = 0; - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__none_get_seq_list() */ - diff --git a/src/H5Spkg.h b/src/H5Spkg.h index 5e73e8e..a18179a 100644 --- a/src/H5Spkg.h +++ b/src/H5Spkg.h @@ -64,10 +64,14 @@ H5S_SELECT_INFO_ENC_SIZE_8 ) #define H5S_UINT32_MAX 0xFFFFFFFF /* 2^32 - 1 = 4,294,967,295 */ +#define H5S_UINT64_MAX ((hsize_t)(-1L)) /* 2^64 - 1 = 18,446,744,073,709,551,615 */ /* Length of stack-allocated sequences for "project intersect" routines */ #define H5S_PROJECT_INTERSECT_NSEQS 256 +/* Internal flags for initializing selection iterators */ +#define H5S_SEL_ITER_API_CALL 0x1000 /* Selection iterator created from API call */ + /* Initial version of the dataspace information */ #define H5O_SDSPACE_VERSION_1 1 @@ -86,6 +90,15 @@ * H5S_UNLIMITED) */ #define H5S_MAX_SIZE ((hsize_t)(hssize_t)(-2)) +/* Macro for checking if two ranges overlap one another */ +/* + * Check for the inverse of whether the ranges are disjoint. If they are + * disjoint, then the low bound of one of the ranges must be greater than the + * high bound of the other. + */ +/* (Assumes that low & high bounds are _inclusive_) */ +#define H5S_RANGE_OVERLAP(L1, H1, L2, H2) (!((L1) > (H2) || (L2) > (H1))) + /* * Dataspace extent information @@ -110,12 +123,18 @@ struct H5S_extent_t { /* Node in point selection list (typedef'd in H5Sprivate.h) */ struct H5S_pnt_node_t { struct H5S_pnt_node_t *next; /* Pointer to next point in list */ - hsize_t *pnt; /* Pointer to a selected point */ + hsize_t pnt[]; /* Selected point */ + /* (NOTE: This uses the C99 "flexible array member" feature) */ }; /* Information about point selection list (typedef'd in H5Sprivate.h) */ struct H5S_pnt_list_t { + /* The following two fields defines the bounding box of the whole set of points, relative to the offset */ + hsize_t low_bounds[H5S_MAX_RANK]; /* The smallest element selected in each dimension */ + hsize_t high_bounds[H5S_MAX_RANK]; /* The largest element selected in each dimension */ + H5S_pnt_node_t *head; /* Pointer to head of point list */ + H5S_pnt_node_t *tail; /* Pointer to tail of point list */ }; /* Information about hyperslab spans */ @@ -123,22 +142,52 @@ struct H5S_pnt_list_t { /* Information a particular hyperslab span (typedef'd in H5Sprivate.h) */ struct H5S_hyper_span_t { hsize_t low, high; /* Low & high bounds of elements selected for span, inclusive */ - hsize_t nelem; /* Number of elements in span (only needed during I/O) */ - hsize_t pstride; /* Pseudo-stride from start of previous span (only used during I/O) */ struct H5S_hyper_span_info_t *down; /* Pointer to list of spans in next dimension down */ struct H5S_hyper_span_t *next; /* Pointer to next span in list */ }; +/* "Operation info" struct. Used to hold temporary information during copies, + * 'adjust', 'nelem', and 'rebuild' operations, and higher level algorithms that + * generate this information. */ +typedef struct H5S_hyper_op_info_t { + uint64_t op_gen; /* Generation of the scratch info */ + union { + struct H5S_hyper_span_info_t *copied; /* Pointer to already copied span tree */ + hsize_t nelmts; /* # of elements */ + hsize_t nblocks; /* # of blocks */ +#ifdef H5_HAVE_PARALLEL + MPI_Datatype down_type; /* MPI datatype for span tree */ +#endif /* H5_HAVE_PARALLEL */ + }u; +} H5S_hyper_op_info_t; + /* Information about a list of hyperslab spans in one dimension (typedef'd in H5Sprivate.h) */ struct H5S_hyper_span_info_t { unsigned count; /* Ref. count of number of spans which share this span */ - struct H5S_hyper_span_info_t *scratch; /* Scratch pointer - * (used during copies, as mark - * during precomputes for I/O & - * to point to the last span in a - * list during single element adds) - */ - struct H5S_hyper_span_t *head; /* Pointer to list of spans in next dimension down */ + + /* The following two fields define the bounding box of this set of spans + * and all lower dimensions, relative to the offset. + */ + /* (NOTE: The bounds arrays are _relative_ to the depth of the span_info + * node in the span tree, so the top node in a 5-D span tree will + * use indices 0-4 in the arrays to store it's bounds information, + * but the next level down in the span tree will use indices 0-3. + * So, each level in the span tree will have the 0th index in the + * arrays correspond to the bounds in "this" dimension, even if + * it's not the highest level in the span tree. + */ + hsize_t *low_bounds; /* The smallest element selected in each dimension */ + hsize_t *high_bounds; /* The largest element selected in each dimension */ + + /* "Operation info" fields */ + /* (Used during copies, 'adjust', 'nelem', and 'rebuild' operations) */ + /* Currently the maximum number of simultaneous operations is 2 */ + H5S_hyper_op_info_t op_info[2]; + + struct H5S_hyper_span_t *head; /* Pointer to the first span of list of spans in the current dimension */ + struct H5S_hyper_span_t *tail; /* Pointer to the last span of list of spans in the current dimension */ + hsize_t bounds[]; /* Array for storing low & high bounds */ + /* (NOTE: This uses the C99 "flexible array member" feature) */ }; /* Enum for diminfo_valid field in H5S_hyper_sel_t */ @@ -160,6 +209,11 @@ typedef struct { */ H5S_hyper_dim_t app[H5S_MAX_RANK]; /* Application-set per-dim selection info */ H5S_hyper_dim_t opt[H5S_MAX_RANK]; /* Optimized per-dim selection info */ + + /* The following two fields defines the bounding box of the diminfo selection */ + /* (relative to the offset) */ + hsize_t low_bounds[H5S_MAX_RANK]; /* The smallest element selected in each dimension */ + hsize_t high_bounds[H5S_MAX_RANK]; /* The largest element selected in each dimension */ } H5S_hyper_diminfo_t; /* Information about hyperslab selection */ @@ -175,10 +229,6 @@ typedef struct { /* Selection information methods */ /* Method to copy a selection */ typedef herr_t (*H5S_sel_copy_func_t)(H5S_t *dst, const H5S_t *src, hbool_t share_selection); -/* Method to retrieve a list of offset/length sequences for selection */ -typedef herr_t (*H5S_sel_get_seq_list_func_t)(const H5S_t *space, unsigned flags, - H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes, - size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); /* Method to release current selection */ typedef herr_t (*H5S_sel_release_func_t)(H5S_t *space); /* Method to determine if current selection is valid for dataspace */ @@ -204,8 +254,14 @@ typedef htri_t (*H5S_sel_is_contiguous_func_t)(const H5S_t *space); typedef htri_t (*H5S_sel_is_single_func_t)(const H5S_t *space); /* Method to determine if current selection is "regular" */ typedef htri_t (*H5S_sel_is_regular_func_t)(const H5S_t *space); +/* Method to determine if two dataspaces' selections are the same shape */ +typedef htri_t (*H5S_sel_shape_same_func_t)(const H5S_t *space1, const H5S_t *space2); +/* Method to determine if selection intersects a block */ +typedef htri_t (*H5S_sel_intersect_block_func_t)(const H5S_t *space, const hsize_t *start, const hsize_t *end); /* Method to adjust a selection by an offset */ typedef herr_t (*H5S_sel_adjust_u_func_t)(H5S_t *space, const hsize_t *offset); +/* Method to adjust a selection by an offset (signed) */ +typedef herr_t (*H5S_sel_adjust_s_func_t)(H5S_t *space, const hssize_t *offset); /* Method to construct single element projection onto scalar dataspace */ typedef herr_t (*H5S_sel_project_scalar)(const H5S_t *space, hsize_t *offset); /* Method to construct selection projection onto/into simple dataspace */ @@ -219,7 +275,6 @@ typedef struct { /* Methods */ H5S_sel_copy_func_t copy; /* Method to make a copy of a selection */ - H5S_sel_get_seq_list_func_t get_seq_list; /* Method to retrieve a list of offset/length sequences for selection */ H5S_sel_release_func_t release; /* Method to release current selection */ H5S_sel_is_valid_func_t is_valid; /* Method to determine if current selection is valid for dataspace */ H5S_sel_serial_size_func_t serial_size; /* Method to determine number of bytes required to store current selection */ @@ -232,7 +287,10 @@ typedef struct { H5S_sel_is_contiguous_func_t is_contiguous; /* Method to determine if current selection is contiguous */ H5S_sel_is_single_func_t is_single; /* Method to determine if current selection is a single block */ H5S_sel_is_regular_func_t is_regular; /* Method to determine if current selection is "regular" */ + H5S_sel_shape_same_func_t shape_same; /* Method to determine if two dataspaces' selections are the same shape */ + H5S_sel_intersect_block_func_t intersect_block; /* Method to determine if a dataspaces' selection intersects a block */ H5S_sel_adjust_u_func_t adjust_u; /* Method to adjust a selection by an offset */ + H5S_sel_adjust_s_func_t adjust_s; /* Method to adjust a selection by an offset (signed) */ H5S_sel_project_scalar project_scalar; /* Method to construct scalar dataspace projection */ H5S_sel_project_simple project_simple; /* Method to construct simple dataspace projection */ H5S_sel_iter_init_func_t iter_init; /* Method to initialize iterator for current selection */ @@ -272,6 +330,10 @@ typedef htri_t (*H5S_sel_iter_has_next_block_func_t)(const H5S_sel_iter_t *iter) typedef herr_t (*H5S_sel_iter_next_func_t)(H5S_sel_iter_t *iter, size_t nelem); /* Method to move selection iterator to the next block in the selection */ typedef herr_t (*H5S_sel_iter_next_block_func_t)(H5S_sel_iter_t *iter); +/* Method to retrieve a list of offset/length sequences for selection iterator */ +typedef herr_t (*H5S_sel_iter_get_seq_list_func_t)(H5S_sel_iter_t *iter, + size_t maxseq, size_t maxbytes, size_t *nseq, size_t *nbytes, hsize_t *off, + size_t *len); /* Method to release iterator for current selection */ typedef herr_t (*H5S_sel_iter_release_func_t)(H5S_sel_iter_t *iter); @@ -286,6 +348,7 @@ typedef struct H5S_sel_iter_class_t { H5S_sel_iter_has_next_block_func_t iter_has_next_block; /* Method to query if there is another block left in the selection */ H5S_sel_iter_next_func_t iter_next; /* Method to move selection iterator to the next element in the selection */ H5S_sel_iter_next_block_func_t iter_next_block; /* Method to move selection iterator to the next block in the selection */ + H5S_sel_iter_get_seq_list_func_t iter_get_seq_list; /* Method to retrieve a list of offset/length sequences for selection iterator */ H5S_sel_iter_release_func_t iter_release; /* Method to release iterator for current selection */ } H5S_sel_iter_class_t; @@ -309,9 +372,8 @@ H5_DLLVAR const H5S_select_class_t H5S_sel_none[1]; */ H5_DLLVAR const H5S_select_class_t H5S_sel_point[1]; -/* Array of versions for Dataspace and hyperslab selections */ +/* Array of versions for Dataspace */ H5_DLLVAR const unsigned H5O_sdspace_ver_bounds[H5F_LIBVER_NBOUNDS]; -H5_DLLVAR const unsigned H5O_sds_hyper_ver_bounds[H5F_LIBVER_NBOUNDS]; /* Extent functions */ H5_DLL herr_t H5S__extent_release(H5S_extent_t *extent); @@ -319,16 +381,20 @@ H5_DLL herr_t H5S__extent_copy_real(H5S_extent_t *dst, const H5S_extent_t *src, hbool_t copy_max); /* Operations on hyperslab selections */ +H5_DLL uint64_t H5S__hyper_get_op_gen(void); +H5_DLL void H5S__hyper_rebuild(H5S_t *space); H5_DLL herr_t H5S__modify_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2); H5_DLL herr_t H5S__hyper_project_intersection(const H5S_t *src_space, - const H5S_t *dst_space, const H5S_t *src_intersect_space, - H5S_t *proj_space); -H5_DLL herr_t H5S__hyper_subtract(H5S_t *space, H5S_t *subtract_space); + const H5S_t *dst_space, const H5S_t *src_intersect_space, H5S_t *proj_space, + hbool_t share_space); /* Testing functions */ #ifdef H5S_TESTING -H5_DLL htri_t H5S__get_rebuild_status_test(hid_t space_id); -H5_DLL htri_t H5S_select_shape_same_test(hid_t sid1, hid_t sid2); +H5_DLL herr_t H5S__get_rebuild_status_test(hid_t space_id, + H5S_diminfo_valid_t *status1, H5S_diminfo_valid_t *status2); +H5_DLL herr_t H5S__get_diminfo_status_test(hid_t space_id, + H5S_diminfo_valid_t *status); +H5_DLL htri_t H5S__internal_consistency_test(hid_t space_id); #endif /* H5S_TESTING */ #endif /*_H5Spkg_H*/ diff --git a/src/H5Spoint.c b/src/H5Spoint.c index 89ce86a..ac45613 100644 --- a/src/H5Spoint.c +++ b/src/H5Spoint.c @@ -46,14 +46,22 @@ /* Local Typedefs */ /******************/ +/* Define alias for hsize_t, for allocating H5S_pnt_node_t + point objects */ +/* (Makes it easier to understand the alloc / free calls) */ +typedef hsize_t hcoords_t; + /********************/ /* Local Prototypes */ /********************/ +static herr_t H5S__point_add(H5S_t *space, H5S_seloper_t op, size_t num_elem, + const hsize_t *coord); +static H5S_pnt_list_t *H5S__copy_pnt_list(const H5S_pnt_list_t *src, + unsigned rank); +static void H5S__free_pnt_list(H5S_pnt_list_t *pnt_lst); + +/* Selection callbacks */ static herr_t H5S__point_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection); -static herr_t H5S__point_get_seq_list(const H5S_t *space, unsigned flags, - H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes, - size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); static herr_t H5S__point_release(H5S_t *space); static htri_t H5S__point_is_valid(const H5S_t *space); static hssize_t H5S__point_serial_size(const H5S_t *space); @@ -65,7 +73,10 @@ static int H5S__point_unlim_dim(const H5S_t *space); static htri_t H5S__point_is_contiguous(const H5S_t *space); static htri_t H5S__point_is_single(const H5S_t *space); static htri_t H5S__point_is_regular(const H5S_t *space); +static htri_t H5S__point_shape_same(const H5S_t *space1, const H5S_t *space2); +static htri_t H5S__point_intersect_block(const H5S_t *space, const hsize_t *start, const hsize_t *end); static herr_t H5S__point_adjust_u(H5S_t *space, const hsize_t *offset); +static herr_t H5S__point_adjust_s(H5S_t *space, const hssize_t *offset); static herr_t H5S__point_project_scalar(const H5S_t *space, hsize_t *offset); static herr_t H5S__point_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset); static herr_t H5S__point_iter_init(const H5S_t *space, H5S_sel_iter_t *iter); @@ -78,15 +89,26 @@ static hsize_t H5S__point_iter_nelmts(const H5S_sel_iter_t *iter); static htri_t H5S__point_iter_has_next_block(const H5S_sel_iter_t *iter); static herr_t H5S__point_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem); static herr_t H5S__point_iter_next_block(H5S_sel_iter_t *sel_iter); +static herr_t H5S__point_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq, + size_t maxbytes, size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); static herr_t H5S__point_iter_release(H5S_sel_iter_t *sel_iter); + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*********************/ +/* Package Variables */ +/*********************/ + /* Selection properties for point selections */ const H5S_select_class_t H5S_sel_point[1] = {{ H5S_SEL_POINTS, /* Methods on selection */ H5S__point_copy, - H5S__point_get_seq_list, H5S__point_release, H5S__point_is_valid, H5S__point_serial_size, @@ -99,12 +121,19 @@ const H5S_select_class_t H5S_sel_point[1] = {{ H5S__point_is_contiguous, H5S__point_is_single, H5S__point_is_regular, + H5S__point_shape_same, + H5S__point_intersect_block, H5S__point_adjust_u, + H5S__point_adjust_s, H5S__point_project_scalar, H5S__point_project_simple, H5S__point_iter_init, }}; +/*******************/ +/* Local Variables */ +/*******************/ + /* Iteration properties for point selections */ static const H5S_sel_iter_class_t H5S_sel_iter_point[1] = {{ H5S_SEL_POINTS, @@ -116,11 +145,12 @@ static const H5S_sel_iter_class_t H5S_sel_iter_point[1] = {{ H5S__point_iter_has_next_block, H5S__point_iter_next, H5S__point_iter_next_block, + H5S__point_iter_get_seq_list, H5S__point_iter_release, }}; -/* Declare a free list to manage the H5S_pnt_node_t struct */ -H5FL_DEFINE_STATIC(H5S_pnt_node_t); +/* Declare a free list to manage the H5S_pnt_node_t + hcoords_t array struct */ +H5FL_BARR_DEFINE_STATIC(H5S_pnt_node_t, hcoords_t, H5S_MAX_RANK); /* Declare a free list to manage the H5S_pnt_list_t struct */ H5FL_DEFINE_STATIC(H5S_pnt_list_t); @@ -141,22 +171,41 @@ H5FL_DEFINE_STATIC(H5S_pnt_list_t); static herr_t H5S__point_iter_init(const H5S_t *space, H5S_sel_iter_t *iter) { - FUNC_ENTER_STATIC_NOERR + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC /* Check args */ HDassert(space && H5S_SEL_POINTS == H5S_GET_SELECT_TYPE(space)); HDassert(iter); - /* Initialize the number of points to iterate over */ - iter->elmt_left = space->select.num_elem; + /* If this iterator is created from an API call, by default we clone the + * selection now, as the dataspace could be modified or go out of scope. + * + * However, if the H5S_SEL_ITER_SHARE_WITH_DATASPACE flag is given, + * the selection is shared between the selection iterator and the + * dataspace. In this case, the application _must_not_ modify or + * close the dataspace that the iterator is operating on, or undefined + * behavior will occur. + */ + if((iter->flags & H5S_SEL_ITER_API_CALL) && + !(iter->flags & H5S_SEL_ITER_SHARE_WITH_DATASPACE)) { + /* Copy the point list */ + if(NULL == (iter->u.pnt.pnt_lst = H5S__copy_pnt_list(space->select.sel_info.pnt_lst, space->extent.rank))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy point list") + } /* end if */ + else + /* OK to share point list for internal iterations */ + iter->u.pnt.pnt_lst = space->select.sel_info.pnt_lst; /* Start at the head of the list of points */ - iter->u.pnt.curr = space->select.sel_info.pnt_lst->head; + iter->u.pnt.curr = iter->u.pnt.pnt_lst->head; /* Initialize type of selection iterator */ iter->type = H5S_sel_iter_point; - FUNC_LEAVE_NOAPI(SUCCEED) +done: + FUNC_LEAVE_NOAPI(ret_value) } /* end H5S__point_iter_init() */ @@ -351,6 +400,137 @@ H5S__point_iter_next_block(H5S_sel_iter_t *iter) /*-------------------------------------------------------------------------- NAME + H5S__point_iter_get_seq_list + PURPOSE + Create a list of offsets & lengths for a selection + USAGE + herr_t H5S__point_iter_get_seq_list(iter,maxseq,maxelem,nseq,nelem,off,len) + H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last + position of interest in selection. + size_t maxseq; IN: Maximum number of sequences to generate + size_t maxelem; IN: Maximum number of elements to include in the + generated sequences + size_t *nseq; OUT: Actual number of sequences generated + size_t *nelem; OUT: Actual number of elements in sequences generated + hsize_t *off; OUT: Array of offsets (in bytes) + size_t *len; OUT: Array of lengths (in bytes) + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + Use the selection in the dataspace to generate a list of byte offsets and + lengths for the region(s) selected. Start/Restart from the position in the + ITER parameter. The number of sequences generated is limited by the MAXSEQ + parameter and the number of sequences actually generated is stored in the + NSEQ parameter. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__point_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem, + size_t *nseq, size_t *nelem, hsize_t *off, size_t *len) +{ + size_t io_left; /* The number of bytes left in the selection */ + size_t start_io_left; /* The initial number of bytes left in the selection */ + H5S_pnt_node_t *node; /* Point node */ + unsigned ndims; /* Dimensionality of dataspace*/ + hsize_t acc; /* Coordinate accumulator */ + hsize_t loc; /* Coordinate offset */ + size_t curr_seq; /* Current sequence being operated on */ + int i; /* Local index variable */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check args */ + HDassert(iter); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); + + /* Choose the minimum number of bytes to sequence through */ + H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t); + start_io_left = io_left = (size_t)MIN(iter->elmt_left, maxelem); + + /* Get the dataspace's rank */ + ndims = iter->rank; + + /* Walk through the points in the selection, starting at the current */ + /* location in the iterator */ + node = iter->u.pnt.curr; + curr_seq = 0; + while(NULL != node) { + /* Compute the offset of each selected point in the buffer */ + for(i = (int)(ndims - 1), acc = iter->elmt_size, loc = 0; i >= 0; i--) { + loc += (hsize_t)((hssize_t)node->pnt[i] + iter->sel_off[i]) * acc; + acc *= iter->dims[i]; + } /* end for */ + + /* Check if this is a later point in the selection */ + if(curr_seq > 0) { + /* If a sorted sequence is requested, make certain we don't go backwards in the offset */ + if((iter->flags & H5S_SEL_ITER_GET_SEQ_LIST_SORTED) && loc < off[curr_seq - 1]) + break; + + /* Check if this point extends the previous sequence */ + /* (Unlikely, but possible) */ + if(loc == (off[curr_seq - 1] + len[curr_seq - 1])) { + /* Extend the previous sequence */ + len[curr_seq - 1] += iter->elmt_size; + } /* end if */ + else { + /* Add a new sequence */ + off[curr_seq] = loc; + len[curr_seq] = iter->elmt_size; + + /* Increment sequence count */ + curr_seq++; + } /* end else */ + } /* end if */ + else { + /* Add a new sequence */ + off[curr_seq] = loc; + len[curr_seq] = iter->elmt_size; + + /* Increment sequence count */ + curr_seq++; + } /* end else */ + + /* Decrement number of elements left to process */ + io_left--; + + /* Move the iterator */ + iter->u.pnt.curr = node->next; + iter->elmt_left--; + + /* Check if we're finished with all sequences */ + if(curr_seq == maxseq) + break; + + /* Check if we're finished with all the elements available */ + if(io_left == 0) + break; + + /* Advance to the next point */ + node = node->next; + } /* end while */ + + /* Set the number of sequences generated */ + *nseq = curr_seq; + + /* Set the number of elements used */ + *nelem = start_io_left - io_left; + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__point_iter_get_seq_list() */ + + +/*-------------------------------------------------------------------------- + NAME H5S__point_iter_release PURPOSE Release point selection iterator information for a dataspace @@ -367,13 +547,18 @@ H5S__point_iter_next_block(H5S_sel_iter_t *iter) REVISION LOG --------------------------------------------------------------------------*/ static herr_t -H5S__point_iter_release(H5S_sel_iter_t H5_ATTR_UNUSED * iter) +H5S__point_iter_release(H5S_sel_iter_t * iter) { FUNC_ENTER_STATIC_NOERR /* Check args */ HDassert(iter); + /* If this iterator copied the point list, we must free it */ + if((iter->flags & H5S_SEL_ITER_API_CALL) && + !(iter->flags & H5S_SEL_ITER_SHARE_WITH_DATASPACE)) + H5S__free_pnt_list(iter->u.pnt.pnt_lst); + FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5S__point_iter_release() */ @@ -386,7 +571,7 @@ H5S__point_iter_release(H5S_sel_iter_t H5_ATTR_UNUSED * iter) USAGE herr_t H5S__point_add(space, num_elem, coord) H5S_t *space; IN: Dataspace of selection to modify - hsize_t num_elem; IN: Number of elements in COORD array. + size_t num_elem; IN: Number of elements in COORD array. const hsize_t *coord[]; IN: The location of each element selected RETURNS Non-negative on success/Negative on failure @@ -398,7 +583,7 @@ H5S__point_iter_release(H5S_sel_iter_t H5_ATTR_UNUSED * iter) REVISION LOG --------------------------------------------------------------------------*/ static herr_t -H5S__point_add(H5S_t *space, H5S_seloper_t op, hsize_t num_elem, const hsize_t *coord) +H5S__point_add(H5S_t *space, H5S_seloper_t op, size_t num_elem, const hsize_t *coord) { H5S_pnt_node_t *top = NULL, *curr = NULL, *new_node = NULL; /* Point selection nodes */ unsigned u; /* Counter */ @@ -413,14 +598,14 @@ H5S__point_add(H5S_t *space, H5S_seloper_t op, hsize_t num_elem, const hsize_t * HDassert(op == H5S_SELECT_SET || op == H5S_SELECT_APPEND || op == H5S_SELECT_PREPEND); for(u = 0; u < num_elem; u++) { + unsigned dim; /* Counter for dimensions */ + /* Allocate space for the new node */ - if(NULL == (new_node = H5FL_MALLOC(H5S_pnt_node_t))) + if(NULL == (new_node = (H5S_pnt_node_t *)H5FL_ARR_MALLOC(hcoords_t, space->extent.rank))) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node") /* Initialize fields in node */ new_node->next = NULL; - if(NULL == (new_node->pnt = (hsize_t *)H5MM_malloc(space->extent.rank * sizeof(hsize_t)))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate coordinate information") /* Copy over the coordinates */ H5MM_memcpy(new_node->pnt, coord + (u * space->extent.rank), (space->extent.rank * sizeof(hsize_t))); @@ -431,6 +616,17 @@ H5S__point_add(H5S_t *space, H5S_seloper_t op, hsize_t num_elem, const hsize_t * else curr->next = new_node; curr = new_node; + + /* Update bound box */ + /* (Note: when op is H5S_SELECT_SET, the bound box has been reset + * inside H5S_select_elements, the only caller of this function. + * So the following bound box update procedure works correctly + * for the SET operation) + */ + for(dim = 0; dim < space->extent.rank; dim++) { + space->select.sel_info.pnt_lst->low_bounds[dim] = MIN(space->select.sel_info.pnt_lst->low_bounds[dim], curr->pnt[dim]); + space->select.sel_info.pnt_lst->high_bounds[dim] = MAX(space->select.sel_info.pnt_lst->high_bounds[dim], curr->pnt[dim]); + } /* end for */ } /* end for */ new_node = NULL; @@ -442,20 +638,22 @@ H5S__point_add(H5S_t *space, H5S_seloper_t op, hsize_t num_elem, const hsize_t * /* Put new list in point selection */ space->select.sel_info.pnt_lst->head = top; + + /* Change the tail pointer if tail has not been set */ + if(NULL == space->select.sel_info.pnt_lst->tail) + space->select.sel_info.pnt_lst->tail = curr; } /* end if */ else { /* op==H5S_SELECT_APPEND */ H5S_pnt_node_t *tmp_node; /* Temporary point selection node */ tmp_node = space->select.sel_info.pnt_lst->head; if(tmp_node != NULL) { - while(tmp_node->next != NULL) - tmp_node = tmp_node->next; - - /* Append new list to point selection */ - tmp_node->next = top; + HDassert(space->select.sel_info.pnt_lst->tail); + space->select.sel_info.pnt_lst->tail->next = top; } /* end if */ else space->select.sel_info.pnt_lst->head = top; + space->select.sel_info.pnt_lst->tail = curr; } /* end else */ /* Set the number of elements in the new selection */ @@ -468,13 +666,12 @@ done: if(ret_value < 0) { /* Release possibly partially initialized new node */ if(new_node) - new_node = H5FL_FREE(H5S_pnt_node_t, new_node); + new_node = (H5S_pnt_node_t *)H5FL_ARR_FREE(hcoords_t, new_node); /* Release possible linked list of nodes */ while(top) { curr = top->next; - H5MM_xfree(top->pnt); - top = H5FL_FREE(H5S_pnt_node_t, top); + top = (H5S_pnt_node_t *)H5FL_ARR_FREE(hcoords_t, top); top = curr; } /* end while */ } /* end if */ @@ -503,24 +700,16 @@ done: static herr_t H5S__point_release(H5S_t *space) { - H5S_pnt_node_t *curr, *next; /* Point selection nodes */ - FUNC_ENTER_STATIC_NOERR /* Check args */ HDassert(space); - /* Delete all the nodes from the list */ - curr = space->select.sel_info.pnt_lst->head; - while(curr != NULL) { - next = curr->next; - H5MM_xfree(curr->pnt); - curr = H5FL_FREE(H5S_pnt_node_t, curr); - curr = next; - } /* end while */ + /* Free the point list */ + H5S__free_pnt_list(space->select.sel_info.pnt_lst); - /* Free & reset the point list header */ - space->select.sel_info.pnt_lst = H5FL_FREE(H5S_pnt_list_t, space->select.sel_info.pnt_lst); + /* Reset the point list header */ + space->select.sel_info.pnt_lst = NULL; /* Reset the number of elements in the selection */ space->select.num_elem = 0; @@ -550,10 +739,7 @@ H5S__point_release(H5S_t *space) array elements are iterated through when I/O is performed. Duplicate coordinates are not checked for. The selection operator, OP, determines how the new selection is to be combined with the existing selection for - the dataspace. Currently, only H5S_SELECT_SET is supported, which replaces - the existing selection with the one defined in this call. When operators - other than H5S_SELECT_SET are used to combine a new selection with an - existing selection, the selection ordering is reset to 'C' array ordering. + the dataspace. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES @@ -580,8 +766,14 @@ H5S_select_elements(H5S_t *space, H5S_seloper_t op, size_t num_elem, /* Allocate space for the point selection information if necessary */ if(H5S_GET_SELECT_TYPE(space) != H5S_SEL_POINTS || space->select.sel_info.pnt_lst == NULL) { + hsize_t tmp = HSIZET_MAX; + if(NULL == (space->select.sel_info.pnt_lst = H5FL_CALLOC(H5S_pnt_list_t))) HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate element information") + + /* Set the bound box to the default value */ + H5VM_array_fill(space->select.sel_info.pnt_lst->low_bounds, &tmp, sizeof(hsize_t), space->extent.rank); + HDmemset(space->select.sel_info.pnt_lst->high_bounds, 0, sizeof(hsize_t) * space->extent.rank); } /* Add points to selection */ @@ -598,57 +790,56 @@ done: /*-------------------------------------------------------------------------- NAME - H5S__point_copy + H5S__copy_pnt_list PURPOSE - Copy a selection from one dataspace to another + Copy a point selection list USAGE - herr_t H5S_point_copy(dst, src) - H5S_t *dst; OUT: Pointer to the destination dataspace - H5S_t *src; IN: Pointer to the source dataspace + H5S_pnt_list_t *H5S__copy_pnt_list(src) + const H5S_pnt_list_t *src; IN: Pointer to the source point list + unsigned rank; IN: # of dimensions for points RETURNS - Non-negative on success/Negative on failure + Non-NULL pointer to new point list on success / NULL on failure DESCRIPTION - Copies all the point selection information from the source - dataspace to the destination dataspace. + Copies point selection information from the source point list to newly + created point list. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__point_copy(H5S_t *dst, const H5S_t *src, hbool_t H5_ATTR_UNUSED share_selection) +static H5S_pnt_list_t * +H5S__copy_pnt_list(const H5S_pnt_list_t *src, unsigned rank) { - H5S_pnt_node_t *curr, *new_node, *new_tail; /* Point information nodes */ - herr_t ret_value = SUCCEED; /* Return value */ + H5S_pnt_list_t *dst = NULL; /* New point list */ + H5S_pnt_node_t *curr, *new_tail; /* Point information nodes */ + H5S_pnt_list_t *ret_value = NULL; /* Return value */ FUNC_ENTER_STATIC /* Sanity checks */ HDassert(src); - HDassert(dst); + HDassert(rank > 0); /* Allocate room for the head of the point list */ - if(NULL == (dst->select.sel_info.pnt_lst = H5FL_MALLOC(H5S_pnt_list_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point list node") + if(NULL == (dst = H5FL_MALLOC(H5S_pnt_list_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate point list node") - curr = src->select.sel_info.pnt_lst->head; + curr = src->head; new_tail = NULL; while(curr) { + H5S_pnt_node_t *new_node; /* New point information node */ + /* Create new point */ - if(NULL == (new_node = H5FL_MALLOC(H5S_pnt_node_t))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node") + if(NULL == (new_node = (H5S_pnt_node_t *)H5FL_ARR_MALLOC(hcoords_t, rank))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate point node") new_node->next = NULL; - if(NULL == (new_node->pnt = (hsize_t *)H5MM_malloc(src->extent.rank * sizeof(hsize_t)))) { - new_node = H5FL_FREE(H5S_pnt_node_t, new_node); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate coordinate information") - } /* end if */ /* Copy over the point's coordinates */ - H5MM_memcpy(new_node->pnt, curr->pnt, (src->extent.rank * sizeof(hsize_t))); + H5MM_memcpy(new_node->pnt, curr->pnt, (rank * sizeof(hsize_t))); /* Keep the order the same when copying */ if(NULL == new_tail) - new_tail = dst->select.sel_info.pnt_lst->head = new_node; + new_tail = dst->head = new_node; else { new_tail->next = new_node; new_tail = new_node; @@ -656,22 +847,101 @@ H5S__point_copy(H5S_t *dst, const H5S_t *src, hbool_t H5_ATTR_UNUSED share_selec curr = curr->next; } /* end while */ + dst->tail = new_tail; + + /* Copy the selection bounds */ + H5MM_memcpy(dst->high_bounds, src->high_bounds, (rank * sizeof(hsize_t))); + H5MM_memcpy(dst->low_bounds, src->low_bounds, (rank * sizeof(hsize_t))); + + /* Set return value */ + ret_value = dst; done: - if(ret_value < 0 && dst->select.sel_info.pnt_lst) { - /* Traverse the (incomplete?) dst list, freeing all memory */ - curr = dst->select.sel_info.pnt_lst->head; - while(curr) { - H5S_pnt_node_t *tmp_node = curr; - - curr->pnt = (hsize_t *)H5MM_xfree(curr->pnt); - curr = curr->next; - tmp_node = H5FL_FREE(H5S_pnt_node_t, tmp_node); - } /* end while */ + if(NULL == ret_value && dst) + H5S__free_pnt_list(dst); - dst->select.sel_info.pnt_lst = H5FL_FREE(H5S_pnt_list_t, dst->select.sel_info.pnt_lst); - } /* end if */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__copy_pnt_list() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__free_pnt_list + PURPOSE + Free a point selection list + USAGE + void H5S__free_pnt_list(pnt_lst) + H5S_pnt_list_t *pnt_lst; IN: Pointer to the point list to free + RETURNS + None + DESCRIPTION + Frees point selection information from the point list + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static void +H5S__free_pnt_list(H5S_pnt_list_t *pnt_lst) +{ + H5S_pnt_node_t *curr; /* Point information nodes */ + + FUNC_ENTER_STATIC_NOERR + + /* Sanity checks */ + HDassert(pnt_lst); + + /* Traverse the list, freeing all memory */ + curr = pnt_lst->head; + while(curr) { + H5S_pnt_node_t *tmp_node = curr; + + curr = curr->next; + tmp_node = (H5S_pnt_node_t *)H5FL_ARR_FREE(hcoords_t, tmp_node); + } /* end while */ + + H5FL_FREE(H5S_pnt_list_t, pnt_lst); + + FUNC_LEAVE_NOAPI_VOID +} /* end H5S__free_pnt_list() */ + +/*-------------------------------------------------------------------------- + NAME + H5S__point_copy + PURPOSE + Copy a selection from one dataspace to another + USAGE + herr_t H5S__point_copy(dst, src, share_selection) + H5S_t *dst; OUT: Pointer to the destination dataspace + H5S_t *src; IN: Pointer to the source dataspace + hbool_t share_selection; IN: Whether to share the selection between the dataspaces + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Copies all the point selection information from the source + dataspace to the destination dataspace. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__point_copy(H5S_t *dst, const H5S_t *src, hbool_t H5_ATTR_UNUSED share_selection) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Sanity checks */ + HDassert(src); + HDassert(dst); + + /* Allocate room for the head of the point list */ + if(NULL == (dst->select.sel_info.pnt_lst = H5S__copy_pnt_list(src->select.sel_info.pnt_lst, src->extent.rank))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy point list") + +done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5S__point_copy() */ @@ -699,7 +969,6 @@ done: static htri_t H5S__point_is_valid(const H5S_t *space) { - H5S_pnt_node_t *curr; /* Point information nodes */ unsigned u; /* Counter */ htri_t ret_value = TRUE; /* Return value */ @@ -707,20 +976,14 @@ H5S__point_is_valid(const H5S_t *space) HDassert(space); - /* Check each point to determine whether selection+offset is within extent */ - curr = space->select.sel_info.pnt_lst->head; - while(curr != NULL) { - /* Check each dimension */ - for(u = 0; u < space->extent.rank; u++) { - /* Check if an offset has been defined */ - /* Bounds check the selected point + offset against the extent */ - if(((curr->pnt[u] + (hsize_t)space->select.offset[u]) > space->extent.size[u]) - || (((hssize_t)curr->pnt[u] + space->select.offset[u]) < 0)) - HGOTO_DONE(FALSE) - } /* end for */ - - curr = curr->next; - } /* end while */ + /* Check each dimension */ + for(u = 0; u < space->extent.rank; u++) { + /* Bounds check the selected point + offset against the extent */ + if((space->select.sel_info.pnt_lst->high_bounds[u] + (hsize_t)space->select.offset[u]) > space->extent.size[u]) + HGOTO_DONE(FALSE) + if(((hssize_t)space->select.sel_info.pnt_lst->low_bounds[u] + space->select.offset[u]) < 0) + HGOTO_DONE(FALSE) + } /* end for */ done: FUNC_LEAVE_NOAPI(ret_value) @@ -854,7 +1117,7 @@ H5S__point_serial_size(const H5S_t *space) HDassert(space); - /* Determine the version */ + /* Determine the version and encoded size for point selection */ if(H5S__point_get_version_enc_size(space, &version, &enc_size) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't determine version and enc_size") @@ -866,7 +1129,7 @@ H5S__point_serial_size(const H5S_t *space) * + + + * + */ - ret_value=20; + ret_value = 20; /* */ ret_value += enc_size; @@ -925,7 +1188,7 @@ H5S__point_serialize(const H5S_t *space, uint8_t **p) pp = (*p); HDassert(pp); - /* Determine the version */ + /* Determine the version and encoded size for point selection info */ if(H5S__point_get_version_enc_size(space, &version, &enc_size) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't determine version and enc_size") @@ -1003,7 +1266,7 @@ H5S__point_deserialize(H5S_t **space, const uint8_t **p) uint32_t version; /* Version number */ hsize_t *coord = NULL, *tcoord; /* Pointer to array of elements */ const uint8_t *pp; /* Local pointer for decoding */ - size_t num_elem = 0; /* Number of elements in selection */ + uint64_t num_elem = 0; /* Number of elements in selection */ unsigned rank; /* Rank of points */ unsigned i, j; /* local counting variables */ herr_t ret_value = SUCCEED; /* Return value */ @@ -1094,7 +1357,7 @@ done: Get the list of element points currently selected USAGE herr_t H5S__get_select_elem_pointlist(space, hsize_t *buf) - H5S_t *space; IN: Dataspace pointer of selection to query + const H5S_t *space; IN: Dataspace pointer of selection to query hsize_t startpoint; IN: Element point to start with hsize_t numpoints; IN: Number of element points to get hsize_t *buf; OUT: List of element points selected @@ -1117,7 +1380,7 @@ done: REVISION LOG --------------------------------------------------------------------------*/ static herr_t -H5S__get_select_elem_pointlist(H5S_t *space, hsize_t startpoint, hsize_t numpoints, hsize_t *buf) +H5S__get_select_elem_pointlist(const H5S_t *space, hsize_t startpoint, hsize_t numpoints, hsize_t *buf) { H5S_pnt_node_t *node; /* Point node */ unsigned rank; /* Dataspace rank */ @@ -1234,8 +1497,6 @@ done: static herr_t H5S__point_bounds(const H5S_t *space, hsize_t *start, hsize_t *end) { - H5S_pnt_node_t *node; /* Point node */ - unsigned rank; /* Dataspace rank */ unsigned u; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ @@ -1246,30 +1507,19 @@ H5S__point_bounds(const H5S_t *space, hsize_t *start, hsize_t *end) HDassert(start); HDassert(end); - /* Get the dataspace extent rank */ - rank = space->extent.rank; + /* Loop over dimensions */ + for(u = 0; u < space->extent.rank; u++) { + /* Sanity check */ + HDassert(space->select.sel_info.pnt_lst->low_bounds[u] <= space->select.sel_info.pnt_lst->high_bounds[u]); - /* Set the start and end arrays up */ - for(u = 0; u < rank; u++) { - start[u] = HSIZET_MAX; - end[u] = 0; - } /* end for */ + /* Check for offset moving selection negative */ + if(((hssize_t)space->select.sel_info.pnt_lst->low_bounds[u] + space->select.offset[u]) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds") - /* Iterate through the node, checking the bounds on each element */ - node = space->select.sel_info.pnt_lst->head; - while(node != NULL) { - for(u = 0; u < rank; u++) { - /* Check for offset moving selection negative */ - if(((hssize_t)node->pnt[u] + space->select.offset[u]) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds") - - if(start[u] > (hsize_t)((hssize_t)node->pnt[u] + space->select.offset[u])) - start[u] = (hsize_t)((hssize_t)node->pnt[u] + space->select.offset[u]); - if(end[u] < (hsize_t)((hssize_t)node->pnt[u] + space->select.offset[u])) - end[u] = (hsize_t)((hssize_t)node->pnt[u] + space->select.offset[u]); - } /* end for */ - node = node->next; - } /* end while */ + /* Set the low & high bounds in this dimension */ + start[u] = (hsize_t)((hssize_t)space->select.sel_info.pnt_lst->low_bounds[u] + space->select.offset[u]); + end[u] = (hsize_t)((hssize_t)space->select.sel_info.pnt_lst->high_bounds[u] + space->select.offset[u]); + } /* end for */ done: FUNC_LEAVE_NOAPI(ret_value) @@ -1489,6 +1739,171 @@ H5S__point_is_regular(const H5S_t *space) /*-------------------------------------------------------------------------- NAME + H5S__point_shape_same + PURPOSE + Check if a two "point" selections are the same shape + USAGE + htri_t H5S__point_shape_same(space1, space2) + const H5S_t *space1; IN: First dataspace to check + const H5S_t *space2; IN: Second dataspace to check + RETURNS + TRUE / FALSE / FAIL + DESCRIPTION + Checks to see if the current selection in each dataspace are the same + shape. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static htri_t +H5S__point_shape_same(const H5S_t *space1, const H5S_t *space2) +{ + H5S_pnt_node_t *pnt1, *pnt2; /* Point information nodes */ + hssize_t offset[H5S_MAX_RANK]; /* Offset between the selections */ + unsigned space1_rank; /* Number of dimensions of first dataspace */ + unsigned space2_rank; /* Number of dimensions of second dataspace */ + int space1_dim; /* Current dimension in first dataspace */ + int space2_dim; /* Current dimension in second dataspace */ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check args */ + HDassert(space1); + HDassert(space2); + + /* Get dataspace ranks */ + space1_rank = space1->extent.rank; + space2_rank = space2->extent.rank; + + /* Sanity check */ + HDassert(space1_rank >= space2_rank); + HDassert(space2_rank > 0); + + /* Initialize dimensions */ + space1_dim = (int)space1_rank - 1; + space2_dim = (int)space2_rank - 1; + + /* Look at first point in each selection to compute the offset for common + * dimensions. + */ + pnt1 = space1->select.sel_info.pnt_lst->head; + pnt2 = space2->select.sel_info.pnt_lst->head; + while(space2_dim >= 0) { + /* Set the relative locations of the selections */ + offset[space1_dim] = (hssize_t)pnt2->pnt[space2_dim] - (hssize_t)pnt1->pnt[space1_dim]; + + space1_dim--; + space2_dim--; + } /* end while */ + + /* For dimensions that appear only in space1: */ + while(space1_dim >= 0) { + /* Set the absolute offset of the remaining dimensions */ + offset[space1_dim] = (hssize_t)pnt1->pnt[space1_dim]; + + space1_dim--; + } /* end while */ + + /* Advance to next point */ + pnt1 = pnt1->next; + pnt2 = pnt2->next; + + /* Loop over remaining points */ + while(pnt1 && pnt2) { + /* Initialize dimensions */ + space1_dim = (int)space1_rank - 1; + space2_dim = (int)space2_rank - 1; + + /* Compare locations in common dimensions, including relative offset */ + while(space2_dim >= 0) { + if((hsize_t)((hssize_t)pnt1->pnt[space1_dim] + offset[space1_dim]) != pnt2->pnt[space2_dim]) + HGOTO_DONE(FALSE) + + space1_dim--; + space2_dim--; + } /* end while */ + + /* For dimensions that appear only in space1: */ + while(space1_dim >= 0) { + /* Compare the absolute offset in the remaining dimensions */ + if((hssize_t)pnt1->pnt[space1_dim] != offset[space1_dim]) + HGOTO_DONE(FALSE) + + space1_dim--; + } /* end while */ + + + /* Advance to next point */ + pnt1 = pnt1->next; + pnt2 = pnt2->next; + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__point_shape_same() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__point_intersect_block + PURPOSE + Detect intersections of selection with block + USAGE + htri_t H5S__point_intersect_block(space, start, end) + const H5S_t *space; IN: Dataspace with selection to use + const hsize_t *start; IN: Starting coordinate for block + const hsize_t *end; IN: Ending coordinate for block + RETURNS + Non-negative TRUE / FALSE on success, negative on failure + DESCRIPTION + Quickly detect intersections with a block + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5S__point_intersect_block(const H5S_t *space, const hsize_t *start, + const hsize_t *end) +{ + H5S_pnt_node_t *pnt; /* Point information node */ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Sanity check */ + HDassert(space); + HDassert(H5S_SEL_POINTS == H5S_GET_SELECT_TYPE(space)); + HDassert(start); + HDassert(end); + + /* Loop over points */ + pnt = space->select.sel_info.pnt_lst->head; + while(pnt) { + unsigned u; /* Local index variable */ + + /* Verify that the point is within the block */ + for(u = 0; u < space->extent.rank; u++) + if(pnt->pnt[u] < start[u] || pnt->pnt[u] > end[u]) + break; + + /* Check if point was within block for all dimensions */ + if(u == space->extent.rank) + HGOTO_DONE(TRUE) + + /* Advance to next point */ + pnt = pnt->next; + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__point_intersect_block() */ + + +/*-------------------------------------------------------------------------- + NAME H5S__point_adjust_u PURPOSE Adjust a "point" selection by subtracting an offset @@ -1543,12 +1958,88 @@ H5S__point_adjust_u(H5S_t *space, const hsize_t *offset) /* Advance to next point node in selection */ node = node->next; } /* end while */ + + /* update the bound box of the selection */ + for(u = 0; u < rank; u++) { + space->select.sel_info.pnt_lst->low_bounds[u] -= offset[u]; + space->select.sel_info.pnt_lst->high_bounds[u] -= offset[u]; + } /* end for */ } /* end if */ FUNC_LEAVE_NOAPI(SUCCEED) } /* end H5S__point_adjust_u() */ +/*-------------------------------------------------------------------------- + NAME + H5S__point_adjust_s + PURPOSE + Adjust a "point" selection by subtracting an offset + USAGE + herr_t H5S__point_adjust_u(space, offset) + H5S_t *space; IN/OUT: Pointer to dataspace to adjust + const hssize_t *offset; IN: Offset to subtract + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Moves a point selection by subtracting an offset from it. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__point_adjust_s(H5S_t *space, const hssize_t *offset) +{ + hbool_t non_zero_offset = FALSE; /* Whether any offset is non-zero */ + H5S_pnt_node_t *node; /* Point node */ + unsigned rank; /* Dataspace rank */ + unsigned u; /* Local index variable */ + + FUNC_ENTER_STATIC_NOERR + + HDassert(space); + HDassert(offset); + + /* Check for an all-zero offset vector */ + for(u = 0; u < space->extent.rank; u++) + if(0 != offset[u]) { + non_zero_offset = TRUE; + break; + } /* end if */ + + /* Only perform operation if the offset is non-zero */ + if(non_zero_offset) { + /* Iterate through the nodes, checking the bounds on each element */ + node = space->select.sel_info.pnt_lst->head; + rank = space->extent.rank; + while(node) { + /* Adjust each coordinate for point node */ + for(u = 0; u < rank; u++) { + /* Check for offset moving selection negative */ + HDassert((hssize_t)node->pnt[u] >= offset[u]); + + /* Adjust node's coordinate location */ + node->pnt[u] = (hsize_t)((hssize_t)node->pnt[u] - offset[u]); + } /* end for */ + + /* Advance to next point node in selection */ + node = node->next; + } /* end while */ + + /* update the bound box of the selection */ + for(u = 0; u < rank; u++) { + HDassert((hssize_t)space->select.sel_info.pnt_lst->low_bounds[u] >= offset[u]); + space->select.sel_info.pnt_lst->low_bounds[u] = (hsize_t)((hssize_t)space->select.sel_info.pnt_lst->low_bounds[u] - offset[u]); + space->select.sel_info.pnt_lst->high_bounds[u] = (hsize_t)((hssize_t)space->select.sel_info.pnt_lst->high_bounds[u] - offset[u]); + } /* end for */ + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__point_adjust_s() */ + + + /*------------------------------------------------------------------------- * Function: H5S__point_project_scalar * @@ -1609,6 +2100,7 @@ H5S__point_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *of H5S_pnt_node_t *new_node; /* Point node in new space */ H5S_pnt_node_t *prev_node; /* Previous point node in new space */ unsigned rank_diff; /* Difference in ranks between spaces */ + unsigned u; /* Local index variable */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC @@ -1643,13 +2135,9 @@ H5S__point_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *of prev_node = NULL; while(base_node) { /* Create new point */ - if(NULL == (new_node = H5FL_MALLOC(H5S_pnt_node_t))) + if(NULL == (new_node = (H5S_pnt_node_t *)H5FL_ARR_MALLOC(hcoords_t, new_space->extent.rank))) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node") new_node->next = NULL; - if(NULL == (new_node->pnt = (hsize_t *)H5MM_malloc(new_space->extent.rank * sizeof(hsize_t)))) { - new_node = H5FL_FREE(H5S_pnt_node_t, new_node); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate coordinate information") - } /* end if */ /* Copy over the point's coordinates */ H5MM_memcpy(new_node->pnt, &base_node->pnt[rank_diff], (new_space->extent.rank * sizeof(hsize_t))); @@ -1665,6 +2153,12 @@ H5S__point_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *of /* Advance to next node */ base_node = base_node->next; } /* end while */ + + /* Update the bounding box */ + for(u = 0; u < new_space->extent.rank; u++) { + new_space->select.sel_info.pnt_lst->low_bounds[u] = base_space->select.sel_info.pnt_lst->low_bounds[u + rank_diff]; + new_space->select.sel_info.pnt_lst->high_bounds[u] = base_space->select.sel_info.pnt_lst->high_bounds[u + rank_diff]; + } /* end for */ } /* end if */ else { HDassert(new_space->extent.rank > base_space->extent.rank); @@ -1680,13 +2174,9 @@ H5S__point_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *of prev_node = NULL; while(base_node) { /* Create new point */ - if(NULL == (new_node = H5FL_MALLOC(H5S_pnt_node_t))) + if(NULL == (new_node = (H5S_pnt_node_t *)H5FL_ARR_MALLOC(hcoords_t, new_space->extent.rank))) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node") new_node->next = NULL; - if(NULL == (new_node->pnt = (hsize_t *)H5MM_malloc(new_space->extent.rank * sizeof(hsize_t)))) { - new_node = H5FL_FREE(H5S_pnt_node_t, new_node); - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate coordinate information") - } /* end if */ /* Copy over the point's coordinates */ HDmemset(new_node->pnt, 0, sizeof(hsize_t) * rank_diff); @@ -1703,6 +2193,16 @@ H5S__point_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *of /* Advance to next node */ base_node = base_node->next; } /* end while */ + + /* Update the bounding box */ + for(u = 0; u < rank_diff; u++) { + new_space->select.sel_info.pnt_lst->low_bounds[u] = 0; + new_space->select.sel_info.pnt_lst->high_bounds[u] = 0; + } /* end for */ + for(; u < new_space->extent.rank; u++) { + new_space->select.sel_info.pnt_lst->low_bounds[u] = base_space->select.sel_info.pnt_lst->low_bounds[u - rank_diff]; + new_space->select.sel_info.pnt_lst->high_bounds[u] = base_space->select.sel_info.pnt_lst->high_bounds[u - rank_diff]; + } /* end for */ } /* end else */ /* Number of elements selected will be the same */ @@ -1776,141 +2276,3 @@ done: FUNC_LEAVE_API(ret_value) } /* end H5Sselect_elements() */ - -/*-------------------------------------------------------------------------- - NAME - H5S__point_get_seq_list - PURPOSE - Create a list of offsets & lengths for a selection - USAGE - herr_t H5S__point_get_seq_list(space,flags,iter,maxseq,maxelem,nseq,nelem,off,len) - H5S_t *space; IN: Dataspace containing selection to use. - unsigned flags; IN: Flags for extra information about operation - H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last - position of interest in selection. - size_t maxseq; IN: Maximum number of sequences to generate - size_t maxelem; IN: Maximum number of elements to include in the - generated sequences - size_t *nseq; OUT: Actual number of sequences generated - size_t *nelem; OUT: Actual number of elements in sequences generated - hsize_t *off; OUT: Array of offsets - size_t *len; OUT: Array of lengths - RETURNS - Non-negative on success/Negative on failure. - DESCRIPTION - Use the selection in the dataspace to generate a list of byte offsets and - lengths for the region(s) selected. Start/Restart from the position in the - ITER parameter. The number of sequences generated is limited by the MAXSEQ - parameter and the number of sequences actually generated is stored in the - NSEQ parameter. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static herr_t -H5S__point_get_seq_list(const H5S_t *space, unsigned flags, H5S_sel_iter_t *iter, - size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem, - hsize_t *off, size_t *len) -{ - size_t io_left; /* The number of bytes left in the selection */ - size_t start_io_left; /* The initial number of bytes left in the selection */ - H5S_pnt_node_t *node; /* Point node */ - hsize_t dims[H5S_MAX_RANK]; /* Total size of memory buf */ - int ndims; /* Dimensionality of space*/ - hsize_t acc; /* Coordinate accumulator */ - hsize_t loc; /* Coordinate offset */ - size_t curr_seq; /* Current sequence being operated on */ - int i; /* Local index variable */ - herr_t ret_value=SUCCEED; /* return value */ - - FUNC_ENTER_STATIC - - /* Check args */ - HDassert(space); - HDassert(iter); - HDassert(maxseq > 0); - HDassert(maxelem > 0); - HDassert(nseq); - HDassert(nelem); - HDassert(off); - HDassert(len); - - /* Choose the minimum number of bytes to sequence through */ - H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t); - start_io_left = io_left = (size_t)MIN(iter->elmt_left, maxelem); - - /* Get the dataspace dimensions */ - if((ndims = H5S_get_simple_extent_dims (space, dims, NULL)) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to retrieve dataspace dimensions") - - /* Walk through the points in the selection, starting at the current */ - /* location in the iterator */ - node = iter->u.pnt.curr; - curr_seq = 0; - while(NULL != node) { - /* Compute the offset of each selected point in the buffer */ - for(i = ndims - 1, acc = iter->elmt_size, loc = 0; i >= 0; i--) { - loc += (hsize_t)((hssize_t)node->pnt[i] + space->select.offset[i]) * acc; - acc *= dims[i]; - } /* end for */ - - /* Check if this is a later point in the selection */ - if(curr_seq > 0) { - /* If a sorted sequence is requested, make certain we don't go backwards in the offset */ - if((flags & H5S_GET_SEQ_LIST_SORTED) && loc < off[curr_seq-1]) - break; - - /* Check if this point extends the previous sequence */ - /* (Unlikely, but possible) */ - if(loc == (off[curr_seq-1] + len[curr_seq-1])) { - /* Extend the previous sequence */ - len[curr_seq-1] += iter->elmt_size; - } /* end if */ - else { - /* Add a new sequence */ - off[curr_seq] = loc; - len[curr_seq] = iter->elmt_size; - - /* Increment sequence count */ - curr_seq++; - } /* end else */ - } /* end if */ - else { - /* Add a new sequence */ - off[curr_seq] = loc; - len[curr_seq] = iter->elmt_size; - - /* Increment sequence count */ - curr_seq++; - } /* end else */ - - /* Decrement number of elements left to process */ - io_left--; - - /* Move the iterator */ - iter->u.pnt.curr = node->next; - iter->elmt_left--; - - /* Check if we're finished with all sequences */ - if(curr_seq == maxseq) - break; - - /* Check if we're finished with all the elements available */ - if(io_left == 0) - break; - - /* Advance to the next point */ - node = node->next; - } /* end while */ - - /* Set the number of sequences generated */ - *nseq = curr_seq; - - /* Set the number of elements used */ - *nelem = start_io_left-io_left; - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__point_get_seq_list() */ - diff --git a/src/H5Sprivate.h b/src/H5Sprivate.h index c361612..5100f1c 100644 --- a/src/H5Sprivate.h +++ b/src/H5Sprivate.h @@ -30,9 +30,6 @@ #include "H5Pprivate.h" /* Property lists */ #include "H5Tprivate.h" /* Datatypes */ -/* Flags for "get_seq_list" methods */ -#define H5S_GET_SEQ_LIST_SORTED 0x0001 - /* Forward references of package typedefs */ typedef struct H5S_extent_t H5S_extent_t; typedef struct H5S_pnt_node_t H5S_pnt_node_t; @@ -50,6 +47,7 @@ typedef struct H5S_hyper_dim_t { /* Point selection iteration container */ typedef struct { + H5S_pnt_list_t *pnt_lst; /* Pointer to point list */ H5S_pnt_node_t *curr; /* Pointer to next node to output */ } H5S_point_iter_t; @@ -57,6 +55,7 @@ typedef struct { typedef struct { /* Common fields for all hyperslab selections */ hsize_t off[H5S_MAX_RANK]; /* Offset in span node (used as position for regular hyperslabs) */ + hsize_t slab[H5S_MAX_RANK]; /* Cumulative size of each dimension in bytes */ unsigned iter_rank; /* Rank of iterator information */ /* (This should always be the same as the dataspace * rank, except for regular hyperslab selections in @@ -72,6 +71,7 @@ typedef struct { hbool_t flattened[H5S_MAX_RANK]; /* Whether this dimension has been flattened */ /* Irregular hyperslab selection fields */ + hsize_t loc_off[H5S_MAX_RANK]; /* Byte offset in buffer, for each dimension's current offset */ H5S_hyper_span_info_t *spans; /* Pointer to copy of the span tree */ H5S_hyper_span_t *span[H5S_MAX_RANK];/* Array of pointers to span nodes */ } H5S_hyper_iter_t; @@ -92,9 +92,11 @@ typedef struct H5S_sel_iter_t { /* Information common to all iterators */ unsigned rank; /* Rank of dataspace the selection iterator is operating on */ - hsize_t *dims; /* Dimensions of dataspace the selection is operating on */ + hsize_t dims[H5S_MAX_RANK]; /* Dimensions of dataspace the selection is operating on */ + hssize_t sel_off[H5S_MAX_RANK]; /* Selection offset in dataspace */ hsize_t elmt_left; /* Number of elements left to iterate over */ size_t elmt_size; /* Size of elements to iterate over */ + unsigned flags; /* Flags controlling iterator behavior */ /* Information specific to each type of iterator */ union { @@ -134,7 +136,6 @@ typedef struct H5S_sel_iter_op_t { #define H5S_GET_EXTENT_NPOINTS(S) ((S)->extent.nelem) #define H5S_GET_SELECT_NPOINTS(S) ((S)->select.num_elem) #define H5S_GET_SELECT_TYPE(S) ((S)->select.type->type) -#define H5S_SELECT_GET_SEQ_LIST(S,FLAGS,ITER,MAXSEQ,MAXBYTES,NSEQ,NBYTES,OFF,LEN) ((*(S)->select.type->get_seq_list)(S,FLAGS,ITER,MAXSEQ,MAXBYTES,NSEQ,NBYTES,OFF,LEN)) #define H5S_SELECT_VALID(S) ((*(S)->select.type->is_valid)(S)) #define H5S_SELECT_SERIAL_SIZE(S) ((*(S)->select.type->serial_size)(S)) #define H5S_SELECT_SERIALIZE(S,BUF) ((*(S)->select.type->serialize)(S,BUF)) @@ -144,6 +145,7 @@ typedef struct H5S_sel_iter_op_t { #define H5S_SELECT_IS_SINGLE(S) ((*(S)->select.type->is_single)(S)) #define H5S_SELECT_IS_REGULAR(S) ((*(S)->select.type->is_regular)(S)) #define H5S_SELECT_ADJUST_U(S,O) ((*(S)->select.type->adjust_u)(S, O)) +#define H5S_SELECT_ADJUST_S(S,O) ((*(S)->select.type->adjust_s)(S, O)) #define H5S_SELECT_PROJECT_SCALAR(S,O) ((*(S)->select.type->project_scalar)(S, O)) #define H5S_SELECT_PROJECT_SIMPLE(S,NS, O) ((*(S)->select.type->project_simple)(S, NS, O)) #define H5S_SELECT_ITER_COORDS(ITER,COORDS) ((*(ITER)->type->iter_coords)(ITER,COORDS)) @@ -152,6 +154,7 @@ typedef struct H5S_sel_iter_op_t { #define H5S_SELECT_ITER_HAS_NEXT_BLOCK(ITER) ((*(ITER)->type->iter_has_next_block)(ITER)) #define H5S_SELECT_ITER_NEXT(ITER,NELEM)((*(ITER)->type->iter_next)(ITER,NELEM)) #define H5S_SELECT_ITER_NEXT_BLOCK(ITER) ((*(ITER)->type->iter_next_block)(ITER)) +#define H5S_SELECT_ITER_GET_SEQ_LIST(ITER,MAXSEQ,MAXBYTES,NSEQ,NBYTES,OFF,LEN) ((*(ITER)->type->iter_get_seq_list)(ITER,MAXSEQ,MAXBYTES,NSEQ,NBYTES,OFF,LEN)) #define H5S_SELECT_ITER_RELEASE(ITER) ((*(ITER)->type->iter_release)(ITER)) #else /* H5S_MODULE */ #define H5S_GET_EXTENT_TYPE(S) (H5S_get_simple_extent_type(S)) @@ -159,7 +162,6 @@ typedef struct H5S_sel_iter_op_t { #define H5S_GET_EXTENT_NPOINTS(S) (H5S_get_simple_extent_npoints(S)) #define H5S_GET_SELECT_NPOINTS(S) (H5S_get_select_npoints(S)) #define H5S_GET_SELECT_TYPE(S) (H5S_get_select_type(S)) -#define H5S_SELECT_GET_SEQ_LIST(S,FLAGS,ITER,MAXSEQ,MAXBYTES,NSEQ,NBYTES,OFF,LEN) (H5S_select_get_seq_list(S,FLAGS,ITER,MAXSEQ,MAXBYTES,NSEQ,NBYTES,OFF,LEN)) #define H5S_SELECT_VALID(S) (H5S_select_valid(S)) #define H5S_SELECT_SERIAL_SIZE(S) (H5S_select_serial_size(S)) #define H5S_SELECT_SERIALIZE(S,BUF) (H5S_select_serialize(S,BUF)) @@ -169,6 +171,7 @@ typedef struct H5S_sel_iter_op_t { #define H5S_SELECT_IS_SINGLE(S) (H5S_select_is_single(S)) #define H5S_SELECT_IS_REGULAR(S) (H5S_select_is_regular(S)) #define H5S_SELECT_ADJUST_U(S,O) (H5S_select_adjust_u(S, O)) +#define H5S_SELECT_ADJUST_S(S,O) (H5S_select_adjust_s(S, O)) #define H5S_SELECT_PROJECT_SCALAR(S,O) (H5S_select_project_scalar(S, O)) #define H5S_SELECT_PROJECT_SIMPLE(S,NS,O) (H5S_select_project_simple(S, NS, O)) #define H5S_SELECT_ITER_COORDS(ITER,COORDS) (H5S_select_iter_coords(ITER,COORDS)) @@ -177,15 +180,20 @@ typedef struct H5S_sel_iter_op_t { #define H5S_SELECT_ITER_HAS_NEXT_BLOCK(ITER) (H5S_select_iter_has_next_block(ITER)) #define H5S_SELECT_ITER_NEXT(ITER,NELEM)(H5S_select_iter_next(ITER,NELEM)) #define H5S_SELECT_ITER_NEXT_BLOCK(ITER) (H5S_select_iter_next_block(ITER)) +#define H5S_SELECT_ITER_GET_SEQ_LIST(ITER,MAXSEQ,MAXBYTES,NSEQ,NBYTES,OFF,LEN) (H5S_select_iter_get_seq_list(ITER,MAXSEQ,MAXBYTES,NSEQ,NBYTES,OFF,LEN)) #define H5S_SELECT_ITER_RELEASE(ITER) (H5S_select_iter_release(ITER)) #endif /* H5S_MODULE */ /* Handle these callbacks in a special way, since they have prologs that need to be executed */ #define H5S_SELECT_COPY(DST,SRC,SHARE) (H5S_select_copy(DST,SRC,SHARE)) #define H5S_SELECT_SHAPE_SAME(S1,S2) (H5S_select_shape_same(S1,S2)) +#define H5S_SELECT_INTERSECT_BLOCK(S,START,END) (H5S_select_intersect_block(S,START,END)) #define H5S_SELECT_RELEASE(S) (H5S_select_release(S)) #define H5S_SELECT_DESERIALIZE(S,BUF) (H5S_select_deserialize(S,BUF)) +/* Forward declaration of structs used below */ +struct H5O_t; +struct H5O_loc_t; /* Early typedef to avoid circular dependencies */ typedef struct H5S_t H5S_t; @@ -240,24 +248,24 @@ H5_DLL herr_t H5S_get_select_num_elem_non_unlim(const H5S_t *space, H5_DLL herr_t H5S_select_offset(H5S_t *space, const hssize_t *offset); H5_DLL herr_t H5S_select_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection); H5_DLL htri_t H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2); +H5_DLL htri_t H5S_select_intersect_block(const H5S_t *space, const hsize_t *start, + const hsize_t *end); H5_DLL herr_t H5S_select_construct_projection(const H5S_t *base_space, H5S_t **new_space_ptr, unsigned new_space_rank, const void *buf, void const **adj_buf_ptr, hsize_t element_size); H5_DLL herr_t H5S_select_release(H5S_t *ds); -H5_DLL herr_t H5S_select_get_seq_list(const H5S_t *space, unsigned flags, - H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes, - size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); H5_DLL hssize_t H5S_select_serial_size(const H5S_t *space); H5_DLL herr_t H5S_select_serialize(const H5S_t *space, uint8_t **p); H5_DLL htri_t H5S_select_is_contiguous(const H5S_t *space); H5_DLL htri_t H5S_select_is_single(const H5S_t *space); H5_DLL htri_t H5S_select_is_regular(const H5S_t *space); H5_DLL herr_t H5S_select_adjust_u(H5S_t *space, const hsize_t *offset); +H5_DLL herr_t H5S_select_adjust_s(H5S_t *space, const hssize_t *offset); H5_DLL herr_t H5S_select_project_scalar(const H5S_t *space, hsize_t *offset); H5_DLL herr_t H5S_select_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset); H5_DLL herr_t H5S_select_project_intersection(const H5S_t *src_space, const H5S_t *dst_space, const H5S_t *src_intersect_space, - H5S_t **new_space_ptr); + H5S_t **new_space_ptr, hbool_t share_space); H5_DLL herr_t H5S_select_subtract(H5S_t *space, H5S_t *subtract_space); /* Operations on all selections */ @@ -273,12 +281,11 @@ H5_DLL herr_t H5S_select_elements(H5S_t *space, H5S_seloper_t op, /* Operations on hyperslab selections */ H5_DLL herr_t H5S_select_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[], const hsize_t *stride, const hsize_t count[], const hsize_t *block); +H5_DLL herr_t H5S_combine_hyperslab(H5S_t *old_space, H5S_seloper_t op, + const hsize_t start[], const hsize_t *stride, const hsize_t count[], + const hsize_t *block, H5S_t **new_space); H5_DLL herr_t H5S_hyper_add_span_element(H5S_t *space, unsigned rank, const hsize_t *coords); -H5_DLL herr_t H5S_hyper_reset_scratch(H5S_t *space); -H5_DLL herr_t H5S_hyper_convert(H5S_t *space); -H5_DLL htri_t H5S_hyper_intersect_block(H5S_t *space, const hsize_t *start, const hsize_t *end); -H5_DLL herr_t H5S_hyper_adjust_s(H5S_t *space, const hssize_t *offset); H5_DLL htri_t H5S_hyper_normalize_offset(H5S_t *space, hssize_t *old_offset); H5_DLL herr_t H5S_hyper_denormalize_offset(H5S_t *space, const hssize_t *old_offset); H5_DLL herr_t H5S_hyper_clip_unlim(H5S_t *space, hsize_t clip_size); @@ -293,11 +300,14 @@ H5_DLL hsize_t H5S_hyper_get_first_inc_block(const H5S_t *space, /* Operations on selection iterators */ H5_DLL herr_t H5S_select_iter_init(H5S_sel_iter_t *iter, const H5S_t *space, - size_t elmt_size); + size_t elmt_size, unsigned flags); H5_DLL herr_t H5S_select_iter_coords(const H5S_sel_iter_t *sel_iter, hsize_t *coords); H5_DLL hsize_t H5S_select_iter_nelmts(const H5S_sel_iter_t *sel_iter); H5_DLL herr_t H5S_select_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem); +H5_DLL herr_t H5S_select_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq, + size_t maxbytes, size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); H5_DLL herr_t H5S_select_iter_release(H5S_sel_iter_t *sel_iter); +H5_DLL herr_t H5S_sel_iter_close(H5S_sel_iter_t *sel_iter); #ifdef H5_HAVE_PARALLEL H5_DLL herr_t H5S_mpio_space_type(const H5S_t *space, size_t elmt_size, diff --git a/src/H5Spublic.h b/src/H5Spublic.h index e54fc39..e45f2c9 100644 --- a/src/H5Spublic.h +++ b/src/H5Spublic.h @@ -28,6 +28,35 @@ /* Define user-level maximum number of dimensions */ #define H5S_MAX_RANK 32 +/* Flags for selection iterators */ +#define H5S_SEL_ITER_GET_SEQ_LIST_SORTED 0x0001 /* Retrieve elements from iterator + * in increasing offset order, for + * each call to retrieve sequences. + * Currently, this only applies to + * point selections, as hyperslab + * selections are always returned + * in increasing offset order. + * + * Note that the order is only + * increasing for each call to + * get_seq_list, the next set of + * sequences could start with an + * earlier offset than the previous + * one. + */ +#define H5S_SEL_ITER_SHARE_WITH_DATASPACE 0x0002 /* Don't copy the dataspace + * selection when creating the + * selection iterator. + * + * This can improve performance + * of creating the iterator, but + * the dataspace _MUST_NOT_ be + * modified or closed until the + * selection iterator is closed + * or the iterator's behavior + * will be undefined. + */ + /* Different types of dataspaces */ typedef enum H5S_class_t { H5S_NO_CLASS = -1, /*error */ @@ -112,9 +141,14 @@ H5_DLL htri_t H5Sextent_equal(hid_t sid1, hid_t sid2); /* Operations on dataspace selections */ H5_DLL H5S_sel_type H5Sget_select_type(hid_t spaceid); H5_DLL hssize_t H5Sget_select_npoints(hid_t spaceid); +H5_DLL herr_t H5Sselect_copy(hid_t dst_id, hid_t src_id); H5_DLL htri_t H5Sselect_valid(hid_t spaceid); +H5_DLL herr_t H5Sselect_adjust(hid_t spaceid, const hssize_t *offset); H5_DLL herr_t H5Sget_select_bounds(hid_t spaceid, hsize_t start[], hsize_t end[]); +H5_DLL htri_t H5Sselect_shape_same(hid_t space1_id, hid_t space2_id); +H5_DLL htri_t H5Sselect_intersect_block(hid_t space_id, const hsize_t *start, + const hsize_t *end); H5_DLL herr_t H5Soffset_simple(hid_t space_id, const hssize_t *offset); H5_DLL herr_t H5Sselect_all(hid_t spaceid); H5_DLL herr_t H5Sselect_none(hid_t spaceid); @@ -126,22 +160,19 @@ H5_DLL herr_t H5Sget_select_elem_pointlist(hid_t spaceid, hsize_t startpoint, H5_DLL herr_t H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[], const hsize_t _stride[], const hsize_t count[], const hsize_t _block[]); -/* #define NEW_HYPERSLAB_API */ -/* Note that these haven't been working for a while and were never - * publicly released - QAK */ -#ifdef NEW_HYPERSLAB_API H5_DLL hid_t H5Scombine_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[], const hsize_t _stride[], const hsize_t count[], const hsize_t _block[]); -H5_DLL herr_t H5Sselect_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id); +H5_DLL herr_t H5Smodify_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id); H5_DLL hid_t H5Scombine_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id); -#endif /* NEW_HYPERSLAB_API */ H5_DLL htri_t H5Sis_regular_hyperslab(hid_t spaceid); H5_DLL htri_t H5Sget_regular_hyperslab(hid_t spaceid, hsize_t start[], hsize_t stride[], hsize_t count[], hsize_t block[]); H5_DLL hssize_t H5Sget_select_hyper_nblocks(hid_t spaceid); H5_DLL herr_t H5Sget_select_hyper_blocklist(hid_t spaceid, hsize_t startblock, hsize_t numblocks, hsize_t buf[/*numblocks*/]); +H5_DLL hid_t H5Sselect_project_intersection(hid_t src_space_id, + hid_t dst_space_id, hid_t src_intersect_space_id); #ifdef __cplusplus } diff --git a/src/H5Sselect.c b/src/H5Sselect.c index 87a9d47..c672a0b 100644 --- a/src/H5Sselect.c +++ b/src/H5Sselect.c @@ -41,6 +41,10 @@ /* Local Macros */ /****************/ +/* All the valid public flags to H5Ssel_iter_create() */ +#define H5S_SEL_ITER_ALL_PUBLIC_FLAGS (H5S_SEL_ITER_GET_SEQ_LIST_SORTED | \ + H5S_SEL_ITER_SHARE_WITH_DATASPACE) + /******************/ /* Local Typedefs */ @@ -167,6 +171,52 @@ done: /*-------------------------------------------------------------------------- NAME + H5Sselect_copy + PURPOSE + Copy a selection from one dataspace to another + USAGE + herr_t H5Sselect_copy(dst, src) + hid_t dst; OUT: ID of the destination dataspace + hid_t src; IN: ID of the source dataspace + + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Copies all the selection information (including offset) from the source + dataspace to the destination dataspace. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5Sselect_copy(hid_t dst_id, hid_t src_id) +{ + H5S_t *src; + H5S_t *dst; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "ii", dst_id, src_id); + + /* Check args */ + if(NULL == (src = (H5S_t *)H5I_object_verify(src_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + if(NULL == (dst = (H5S_t *)H5I_object_verify(dst_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + + /* Copy */ + if(H5S_select_copy(dst, src, FALSE) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy selection") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Sselect_copy() */ + + +/*-------------------------------------------------------------------------- + NAME H5S_select_copy PURPOSE Copy a selection from one dataspace to another @@ -201,6 +251,10 @@ H5S_select_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection) HDassert(dst); HDassert(src); + /* Release the current selection */ + if(H5S_SELECT_RELEASE(dst) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection") + /* Copy regular fields */ dst->select = src->select; @@ -248,43 +302,6 @@ done: /*------------------------------------------------------------------------- - * Function: H5S_select_get_seq_list - * - * Purpose: Retrieves the next sequence of offset/length pairs for an - * iterator on a dataspace - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol - * Tuesday, May 18, 2004 - * - * Note: This routine participates in the "Inlining C function pointers" - * pattern, don't call it directly, use the appropriate macro - * defined in H5Sprivate.h. - * - *------------------------------------------------------------------------- - */ -herr_t -H5S_select_get_seq_list(const H5S_t *space, unsigned flags, - H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes, - size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len) -{ - herr_t ret_value = FAIL; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT - - HDassert(space); - - /* Call the selection type's get_seq_list function */ - if((ret_value = (*space->select.type->get_seq_list)(space, flags, iter, maxseq, maxbytes, nseq, nbytes, off, len)) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get selection sequence list") - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_select_get_seq_list() */ - - -/*------------------------------------------------------------------------- * Function: H5S_select_serial_size * * Purpose: Determines the number of bytes required to store the current @@ -948,6 +965,95 @@ H5S_select_adjust_u(H5S_t *space, const hsize_t *offset) /*-------------------------------------------------------------------------- NAME + H5S_select_adjust_s + PURPOSE + Adjust a selection by subtracting an offset + USAGE + herr_t H5S_select_adjust_u(space, offset) + H5S_t *space; IN/OUT: Pointer to dataspace to adjust + const hssize_t *offset; IN: Offset to subtract + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Moves a selection by subtracting an offset from it. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + This routine participates in the "Inlining C function pointers" + pattern, don't call it directly, use the appropriate macro + defined in H5Sprivate.h. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5S_select_adjust_s(H5S_t *space, const hssize_t *offset) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(space); + HDassert(offset); + + /* Perform operation */ + ret_value = (*space->select.type->adjust_s)(space, offset); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_select_adjust_s() */ + + +/*-------------------------------------------------------------------------- + NAME + H5Sselect_adjust + PURPOSE + Adjust a selection by subtracting an offset + USAGE + herr_t H5Sselect_adjust_u(space_id, offset) + hid_t space_id; IN: ID of dataspace to adjust + const hsize_t *offset; IN: Offset to subtract + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Moves a selection by subtracting an offset from it. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5Sselect_adjust(hid_t space_id, const hssize_t *offset) +{ + H5S_t *space; + hsize_t low_bounds[H5S_MAX_RANK]; + hsize_t high_bounds[H5S_MAX_RANK]; + unsigned u; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE2("e", "i*Hs", space_id, offset); + + if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "not a dataspace") + if(NULL == offset) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "NULL offset pointer") + + /* Check bounds */ + if(H5S_SELECT_BOUNDS(space, low_bounds, high_bounds) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds") + for(u = 0; u < space->extent.rank; u++) + if(offset[u] > (hssize_t)low_bounds[u]) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "adjustment would move selection below zero offset") + + if(H5S_select_adjust_s(space, offset) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Sselect_adjust() */ + + +/*-------------------------------------------------------------------------- + NAME H5S_select_project_scalar PURPOSE Project a single element selection for a scalar dataspace @@ -1032,11 +1138,12 @@ H5S_select_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset) PURPOSE Initializes iteration information for a selection. USAGE - herr_t H5S_select_iter_init(sel_iter, space, elmt_size) + herr_t H5S_select_iter_init(sel_iter, space, elmt_size, flags) H5S_sel_iter_t *sel_iter; OUT: Selection iterator to initialize. H5S_t *space; IN: Dataspace object containing selection to iterate over size_t elmt_size; IN: Size of elements in the selection + unsigned flags; IN: Flags to control iteration behavior RETURNS Non-negative on success, negative on failure. DESCRIPTION @@ -1045,7 +1152,7 @@ H5S_select_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset) --------------------------------------------------------------------------*/ herr_t H5S_select_iter_init(H5S_sel_iter_t *sel_iter, const H5S_t *space, - size_t elmt_size) + size_t elmt_size, unsigned flags) { herr_t ret_value = FAIL; /* Return value */ @@ -1060,15 +1167,21 @@ H5S_select_iter_init(H5S_sel_iter_t *sel_iter, const H5S_t *space, /* Save the dataspace's rank */ sel_iter->rank = space->extent.rank; - /* Point to the dataspace dimensions, if there are any */ - if(sel_iter->rank > 0) - sel_iter->dims = space->extent.size; - else - sel_iter->dims = NULL; + /* If dims > 0, copy the dataspace dimensions & selection offset */ + if(sel_iter->rank > 0) { + H5MM_memcpy(sel_iter->dims, space->extent.size, sizeof(hsize_t) * space->extent.rank); + H5MM_memcpy(sel_iter->sel_off, space->select.offset, sizeof(hsize_t) * space->extent.rank); + } /* Save the element size */ sel_iter->elmt_size = elmt_size; + /* Initialize the number of elements to iterate over */ + sel_iter->elmt_left = space->select.num_elem; + + /* Set the flags for the iterator */ + sel_iter->flags = flags; + /* Call initialization routine for selection type */ ret_value = (*space->select.type->iter_init)(space, sel_iter); HDassert(sel_iter->type); @@ -1323,6 +1436,43 @@ H5S_select_iter_next_block(H5S_sel_iter_t *iter) #endif /* LATER */ +/*------------------------------------------------------------------------- + * Function: H5S_select_iter_get_seq_list + * + * Purpose: Retrieves the next sequence of offset/length pairs for an + * iterator on a dataspace + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, May 18, 2004 + * + * Note: This routine participates in the "Inlining C function pointers" + * pattern, don't call it directly, use the appropriate macro + * defined in H5Sprivate.h. + * + *------------------------------------------------------------------------- + */ +herr_t +H5S_select_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelmts, + size_t *nseq, size_t *nelmts, hsize_t *off, size_t *len) +{ + herr_t ret_value = FAIL; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Sanity check */ + HDassert(iter); + + /* Call the selection type's get_seq_list function */ + if((ret_value = (*iter->type->iter_get_seq_list)(iter, maxseq, maxelmts, nseq, nelmts, off, len)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get selection sequence list") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_select_iter_get_seq_list() */ + + /*-------------------------------------------------------------------------- NAME H5S_select_iter_release @@ -1421,7 +1571,7 @@ H5S_select_iterate(void *buf, const H5T_t *type, const H5S_t *space, HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate selection iterator") /* Initialize iterator */ - if(H5S_select_iter_init(iter, space, elmt_size) < 0) + if(H5S_select_iter_init(iter, space, elmt_size, 0) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") iter_init = TRUE; /* Selection iteration info has been initialized */ @@ -1455,7 +1605,7 @@ H5S_select_iterate(void *buf, const H5T_t *type, const H5S_t *space, size_t curr_seq; /* Current sequence being worked on */ /* Get the sequences of bytes */ - if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, (size_t)H5D_IO_VECTOR_SIZE, max_elem, &nseq, &nelem, off, len) < 0) + if(H5S_SELECT_ITER_GET_SEQ_LIST(iter, (size_t)H5D_IO_VECTOR_SIZE, max_elem, &nseq, &nelem, off, len) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") /* Loop, while sequences left to process */ @@ -1501,6 +1651,10 @@ H5S_select_iterate(void *buf, const H5T_t *type, const H5S_t *space, HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported op type") } /* end switch */ + /* Check for error return from iterator */ + if(user_ret < 0) + HERROR(H5E_DATASPACE, H5E_CANTNEXT, "iteration operator failed"); + /* Increment offset in dataspace */ curr_off += elmt_size; @@ -1623,20 +1777,19 @@ H5S_get_select_type(const H5S_t *space) This is primarily used for reading the entire selection in one swoop. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS - Assumes that there is only a single "block" for hyperslab selections. + This routine participates in the "Inlining C function pointers" pattern, + don't call it directly, use the appropriate macro defined in H5Sprivate.h. EXAMPLES REVISION LOG - Modified function to view identical shapes with different dimensions - as being the same under some circumstances. --------------------------------------------------------------------------*/ htri_t H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) { H5S_sel_iter_t *iter_a = NULL; /* Selection a iteration info */ H5S_sel_iter_t *iter_b = NULL; /* Selection b iteration info */ - hbool_t iter_a_init = FALSE; /* Selection a iteration info has been initialized */ - hbool_t iter_b_init = FALSE; /* Selection b iteration info has been initialized */ - htri_t ret_value = TRUE; /* Return value */ + hbool_t iter_a_init = FALSE; /* Selection a iteration info has been initialized */ + hbool_t iter_b_init = FALSE; /* Selection b iteration info has been initialized */ + htri_t ret_value = TRUE; /* Return value */ FUNC_ENTER_NOAPI(FAIL) @@ -1655,6 +1808,10 @@ H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) const H5S_t *space_b; /* Dataspace with smaller rank */ unsigned space_a_rank; /* Number of dimensions of dataspace A */ unsigned space_b_rank; /* Number of dimensions of dataspace B */ + int space_a_dim; /* Current dimension in dataspace A */ + int space_b_dim; /* Current dimension in dataspace B */ + H5S_sel_type sel_a_type; /* Selection type for dataspace A */ + H5S_sel_type sel_b_type; /* Selection type for dataspace B */ /* Need to be able to handle spaces of different rank: * @@ -1667,116 +1824,91 @@ H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) * * Let: space_a_rank be the rank of space_a, * space_b_rank be the rank of space_b, - * delta_rank = space_a_rank - space_b_rank. * * Set all this up here. */ if(space1->extent.rank >= space2->extent.rank) { space_a = space1; - space_a_rank = space_a->extent.rank; - space_b = space2; - space_b_rank = space_b->extent.rank; } /* end if */ else { space_a = space2; - space_a_rank = space_a->extent.rank; - space_b = space1; - space_b_rank = space_b->extent.rank; } /* end else */ + space_a_rank = space_a->extent.rank; + space_b_rank = space_b->extent.rank; HDassert(space_a_rank >= space_b_rank); HDassert(space_b_rank > 0); - /* Check for different number of elements selected */ - if(H5S_GET_SELECT_NPOINTS(space_a) != H5S_GET_SELECT_NPOINTS(space_b)) - HGOTO_DONE(FALSE) + /* Get selection type for both dataspaces */ + sel_a_type = H5S_GET_SELECT_TYPE(space_a); + sel_b_type = H5S_GET_SELECT_TYPE(space_b); - /* Check for "easy" cases before getting into generalized block iteration code */ - if((H5S_GET_SELECT_TYPE(space_a) == H5S_SEL_ALL) && (H5S_GET_SELECT_TYPE(space_b) == H5S_SEL_ALL)) { - hsize_t dims1[H5S_MAX_RANK]; /* End point of selection block in dataspace #1 */ - hsize_t dims2[H5S_MAX_RANK]; /* End point of selection block in dataspace #2 */ - int space_a_dim; /* Current dimension in dataspace A */ - int space_b_dim; /* Current dimension in dataspace B */ + /* If selections aren't "none", compare their bounds */ + if(sel_a_type != H5S_SEL_NONE && sel_b_type != H5S_SEL_NONE) { + hsize_t low_a[H5S_MAX_RANK]; /* Low bound of selection in dataspace a */ + hsize_t low_b[H5S_MAX_RANK]; /* Low bound of selection in dataspace b */ + hsize_t high_a[H5S_MAX_RANK]; /* High bound of selection in dataspace a */ + hsize_t high_b[H5S_MAX_RANK]; /* High bound of selection in dataspace b */ - if(H5S_get_simple_extent_dims(space_a, dims1, NULL) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimensionality") - if(H5S_get_simple_extent_dims(space_b, dims2, NULL) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "unable to get dimensionality") + /* Get low & high bounds for both dataspaces */ + if(H5S_SELECT_BOUNDS(space_a, low_a, high_a) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds for first dataspace") + if(H5S_SELECT_BOUNDS(space_b, low_b, high_b) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds for second dataspace") + /* Check that the range between the low & high bounds are the same */ space_a_dim = (int)space_a_rank - 1; space_b_dim = (int)space_b_rank - 1; - - /* recall that space_a_rank >= space_b_rank. - * - * In the following while loop, we test to see if space_a and space_b - * have identical size in all dimensions they have in common. - */ while(space_b_dim >= 0) { - if(dims1[space_a_dim] != dims2[space_b_dim]) + /* Sanity check */ + HDassert(low_a[space_a_dim] <= high_a[space_a_dim]); + HDassert(low_a[space_b_dim] <= high_a[space_b_dim]); + + /* Verify that the ranges are the same */ + if((high_a[space_a_dim] - low_a[space_a_dim]) + != (high_b[space_b_dim] - low_b[space_b_dim])) HGOTO_DONE(FALSE) + /* Go to next dimension */ space_a_dim--; space_b_dim--; } /* end while */ - /* Since we are selecting the entire space, we must also verify that space_a - * has size 1 in all dimensions that it does not share with space_b. - */ + /* Check that the rest of the ranges in space a are "flat" */ while(space_a_dim >= 0) { - if(dims1[space_a_dim] != 1) - HGOTO_DONE(FALSE) + /* Sanity check */ + HDassert(low_a[space_a_dim] <= high_a[space_a_dim]); - space_a_dim--; - } /* end while */ - } /* end if */ - else if((H5S_GET_SELECT_TYPE(space1) == H5S_SEL_NONE) || (H5S_GET_SELECT_TYPE(space2) == H5S_SEL_NONE)) { - /* (Both must be, at this point, if one is) */ - HGOTO_DONE(TRUE) - } /* end if */ - else if((H5S_GET_SELECT_TYPE(space_a) == H5S_SEL_HYPERSLABS && (H5S_DIMINFO_VALID_YES == space_a->select.sel_info.hslab->diminfo_valid)) - && (H5S_GET_SELECT_TYPE(space_b) == H5S_SEL_HYPERSLABS && (H5S_DIMINFO_VALID_YES == space_b->select.sel_info.hslab->diminfo_valid))) { - int space_a_dim; /* Current dimension in dataspace A */ - int space_b_dim; /* Current dimension in dataspace B */ - - space_a_dim = (int)space_a_rank - 1; - space_b_dim = (int)space_b_rank - 1; - - /* check that the shapes are the same in the common dimensions, and that - * block == 1 in all dimensions that appear only in space_a. - */ - while(space_b_dim >= 0) { - if(space_a->select.sel_info.hslab->diminfo.opt[space_a_dim].stride != - space_b->select.sel_info.hslab->diminfo.opt[space_b_dim].stride) - HGOTO_DONE(FALSE) - - if(space_a->select.sel_info.hslab->diminfo.opt[space_a_dim].count != - space_b->select.sel_info.hslab->diminfo.opt[space_b_dim].count) - HGOTO_DONE(FALSE) - - if(space_a->select.sel_info.hslab->diminfo.opt[space_a_dim].block != - space_b->select.sel_info.hslab->diminfo.opt[space_b_dim].block) + /* This range should be flat to be the same in a lower dimension */ + if(low_a[space_a_dim] != high_a[space_a_dim]) HGOTO_DONE(FALSE) space_a_dim--; - space_b_dim--; } /* end while */ - while(space_a_dim >= 0) { - if(space_a->select.sel_info.hslab->diminfo.opt[space_a_dim].block != 1) - HGOTO_DONE(FALSE) - - space_a_dim--; - } /* end while */ + /* Check for a single block in each selection */ + if(H5S_SELECT_IS_SINGLE(space_a) && H5S_SELECT_IS_SINGLE(space_b)) { + /* If both selections are a single block and their bounds are + * the same, then the selections are the same, even if the + * selection types are different. + */ + HGOTO_DONE(TRUE) + } /* end if */ } /* end if */ - /* Iterate through all the blocks in the selection */ + + /* If the dataspaces have the same selection type, use the selection's + * shape_same operator. + */ + if(sel_a_type == sel_b_type) + ret_value = (*space_a->select.type->shape_same)(space_a, space_b); + /* Otherwise, iterate through all the blocks in the selection */ else { hsize_t start_a[H5S_MAX_RANK]; /* Start point of selection block in dataspace a */ hsize_t start_b[H5S_MAX_RANK]; /* Start point of selection block in dataspace b */ hsize_t end_a[H5S_MAX_RANK]; /* End point of selection block in dataspace a */ hsize_t end_b[H5S_MAX_RANK]; /* End point of selection block in dataspace b */ - hsize_t off_a[H5S_MAX_RANK]; /* Offset of selection a blocks */ - hsize_t off_b[H5S_MAX_RANK]; /* Offset of selection b blocks */ + hssize_t offset[H5S_MAX_RANK]; /* Offset of selection b blocks relative to selection a blocks */ hbool_t first_block = TRUE; /* Flag to indicate the first block */ /* Allocate the selection iterators */ @@ -1790,17 +1922,15 @@ H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) * that the selection iterator shouldn't be "flattened", since we * aren't actually going to be doing I/O with the iterators. */ - if(H5S_select_iter_init(iter_a, space_a, (size_t)0) < 0) + if(H5S_select_iter_init(iter_a, space_a, (size_t)0, 0) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator a") iter_a_init = TRUE; - if(H5S_select_iter_init(iter_b, space_b, (size_t)0) < 0) + if(H5S_select_iter_init(iter_b, space_b, (size_t)0, 0) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator b") iter_b_init = TRUE; /* Iterate over all the blocks in each selection */ while(1) { - int space_a_dim; /* Current dimension in dataspace A */ - int space_b_dim; /* Current dimension in dataspace B */ htri_t status_a, status_b; /* Status from next block checks */ /* Get the current block for each selection iterator */ @@ -1825,8 +1955,7 @@ H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) HGOTO_DONE(FALSE) /* Set the relative locations of the selections */ - off_a[space_a_dim] = start_a[space_a_dim]; - off_b[space_b_dim] = start_b[space_b_dim]; + offset[space_a_dim] = (hssize_t)start_b[space_b_dim] - (hssize_t)start_a[space_a_dim]; space_a_dim--; space_b_dim--; @@ -1836,12 +1965,9 @@ H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) * in space_a is not equal to 1, get out. */ while(space_a_dim >= 0) { - if((end_a[space_a_dim] - start_a[space_a_dim]) != 0) + if(start_a[space_a_dim] != end_a[space_a_dim]) HGOTO_DONE(FALSE) - /* Set the relative locations of the selections */ - off_a[space_a_dim] = start_a[space_a_dim]; - space_a_dim--; } /* end while */ @@ -1853,7 +1979,7 @@ H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) /* For dimensions that space_a and space_b have in common: */ while(space_b_dim >= 0) { /* Check if the blocks are in the same relative location */ - if((start_a[space_a_dim] - off_a[space_a_dim]) != (start_b[space_b_dim] - off_b[space_b_dim])) + if((hsize_t)((hssize_t)start_a[space_a_dim] + offset[space_a_dim]) != start_b[space_b_dim]) HGOTO_DONE(FALSE) /* If the block sizes from each selection doesn't match, get out */ @@ -1868,7 +1994,7 @@ H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) /* For dimensions that appear only in space_a: */ while(space_a_dim >= 0) { /* If the block size isn't 1, get out */ - if((end_a[space_a_dim] - start_a[space_a_dim]) != 0) + if(start_a[space_a_dim] != end_a[space_a_dim]) HGOTO_DONE(FALSE) space_a_dim--; @@ -1915,6 +2041,164 @@ done: /*-------------------------------------------------------------------------- NAME + H5Sselect_shape_same + PURPOSE + Check if two selections are the same shape + USAGE + htri_t H5Sselect_shape_same(space1_id, space2_id) + hid_t space1_id; IN: ID of 1st Dataspace pointer to compare + hid_t space2_id; IN: ID of 2nd Dataspace pointer to compare + RETURNS + TRUE/FALSE/FAIL + DESCRIPTION + Checks to see if the current selection in the dataspaces are the same + dimensionality and shape. + This is primarily used for reading the entire selection in one swoop. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5Sselect_shape_same(hid_t space1_id, hid_t space2_id) +{ + H5S_t *space1, *space2; /* Dataspaces to compare */ + htri_t ret_value; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE2("t", "ii", space1_id, space2_id); + + if(NULL == (space1 = (H5S_t *)H5I_object_verify(space1_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "not a dataspace") + if(NULL == (space2 = (H5S_t *)H5I_object_verify(space2_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "not a dataspace") + + if((ret_value = H5S_select_shape_same(space1, space2)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "can't compare selections") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Sselect_shape_same() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_select_intersect_block + PURPOSE + Check if current selection intersects with a block + USAGE + htri_t H5S_select_intersect_block(space, start, end) + const H5S_t *space; IN: Dataspace to compare + const hsize_t *start; IN: Starting coordinate of block + const hsize_t *end; IN: Opposite ("ending") coordinate of block + RETURNS + TRUE / FALSE / FAIL + DESCRIPTION + Checks to see if the current selection in the dataspace intersects with + the block given. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Assumes that start & end block bounds are _inclusive_, so start == end + value OK. + + This routine participates in the "Inlining C function pointers" pattern, + don't call it directly, use the appropriate macro defined in H5Sprivate.h. +--------------------------------------------------------------------------*/ +htri_t +H5S_select_intersect_block(const H5S_t *space, const hsize_t *start, + const hsize_t *end) +{ + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Check args */ + HDassert(space); + HDassert(start); + HDassert(end); + + /* If selections aren't "none", compare their bounds */ + if(H5S_SEL_NONE != H5S_GET_SELECT_TYPE(space)) { + hsize_t low[H5S_MAX_RANK]; /* Low bound of selection in dataspace */ + hsize_t high[H5S_MAX_RANK]; /* High bound of selection in dataspace */ + unsigned u; /* Local index variable */ + + /* Get low & high bounds for dataspace selection */ + if(H5S_SELECT_BOUNDS(space, low, high) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds for dataspace") + + /* Loop over selection bounds and block, checking for overlap */ + for(u = 0; u < space->extent.rank; u++) + /* If selection bounds & block don't overlap, can leave now */ + if(!H5S_RANGE_OVERLAP(low[u], high[u], start[u], end[u])) + HGOTO_DONE(FALSE) + } /* end if */ + + /* Call selection type's intersect routine */ + if((ret_value = (*space->select.type->intersect_block)(space, start, end)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "can't intersect block with selection") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_select_intersect_block() */ + + +/*-------------------------------------------------------------------------- + NAME + H5Sselect_intersect_block + PURPOSE + Check if current selection intersects with a block + USAGE + htri_t H5Sselect_intersect_block(space_id, start, end) + hid_t space1_id; IN: ID of dataspace pointer to compare + const hsize_t *start; IN: Starting coordinate of block + const hsize_t *end; IN: Opposite ("ending") coordinate of block + RETURNS + TRUE / FALSE / FAIL + DESCRIPTION + Checks to see if the current selection in the dataspace intersects with + the block given. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Assumes that start & end block bounds are _inclusive_, so start == end + value OK. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5Sselect_intersect_block(hid_t space_id, const hsize_t *start, const hsize_t *end) +{ + H5S_t *space; /* Dataspace to query */ + unsigned u; /* Local index value */ + htri_t ret_value = FAIL; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE3("t", "i*h*h", space_id, start, end); + + /* Check arguments */ + if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "not a dataspace") + if(NULL == start) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "block start array pointer is NULL") + if(NULL == end) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "block end array pointer is NULL") + + /* Range check start & end values */ + for(u = 0; u < space->extent.rank; u++) + if(start[u] > end[u]) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "block start[%u] (%llu) > end[%u] (%llu)", u, (unsigned long long)start[u], u, (unsigned long long)end[u]) + + /* Call internal routine to do comparison */ + if((ret_value = H5S_select_intersect_block(space, start, end)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "can't compare selection and block") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Sselect_intersect_block() */ + + +/*-------------------------------------------------------------------------- + NAME H5S_select_construct_projection PURPOSE @@ -2229,7 +2513,7 @@ H5S_select_fill(const void *fill, size_t fill_size, const H5S_t *space, void *_b HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate selection iterator") /* Initialize iterator */ - if(H5S_select_iter_init(iter, space, fill_size) < 0) + if(H5S_select_iter_init(iter, space, fill_size, 0) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") iter_init = TRUE; /* Selection iteration info has been initialized */ @@ -2253,7 +2537,7 @@ H5S_select_fill(const void *fill, size_t fill_size, const H5S_t *space, void *_b size_t nelem; /* Number of elements used in sequences */ /* Get the sequences of bytes */ - if(H5S_SELECT_GET_SEQ_LIST(space, 0, iter, (size_t)H5D_IO_VECTOR_SIZE, max_elem, &nseq, &nelem, off, len) < 0) + if(H5S_SELECT_ITER_GET_SEQ_LIST(iter, (size_t)H5D_IO_VECTOR_SIZE, max_elem, &nseq, &nelem, off, len) < 0) HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") /* Loop over sequences */ @@ -2299,11 +2583,12 @@ done: within the selection of dst_space USAGE - herr_t H5S_select_project_intersection(src_space,dst_space,src_intersect_space,proj_space) + herr_t H5S_select_project_intersection(src_space,dst_space,src_intersect_space,proj_space,share_selection) H5S_t *src_space; IN: Selection that is mapped to dst_space, and intersected with src_intersect_space - H5S_t *dst_space; IN: Selection that is mapped to src_space, and which contains the result + H5S_t *dst_space; IN: Selection that is mapped to src_space H5S_t *src_intersect_space; IN: Selection whose intersection with src_space is projected to dst_space to obtain the result H5S_t **new_space_ptr; OUT: Will contain the result (intersection of src_intersect_space and src_space projected from src_space to dst_space) after the operation + hbool_t share_selection; IN: Whether we are allowed to share structures inside dst_space with proj_space RETURNS Non-negative on success/Negative on failure. @@ -2321,9 +2606,15 @@ done: --------------------------------------------------------------------------*/ herr_t H5S_select_project_intersection(const H5S_t *src_space, const H5S_t *dst_space, - const H5S_t *src_intersect_space, H5S_t **new_space_ptr) + const H5S_t *src_intersect_space, H5S_t **new_space_ptr, + hbool_t share_selection) { H5S_t *new_space = NULL; /* New dataspace constructed */ + H5S_t *tmp_src_intersect_space = NULL; /* Temporary SIS converted from points->hyperslabs */ + H5S_sel_iter_t *ss_iter = NULL; /* Selection iterator for src_space */ + hbool_t ss_iter_init = FALSE; /* Whether ss_iter has been initialized */ + H5S_sel_iter_t *ds_iter = NULL; /* Selection iterator for dst_space */ + hbool_t ds_iter_init = FALSE; /* Whether ds_iter has been initialized */ herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) @@ -2336,6 +2627,11 @@ H5S_select_project_intersection(const H5S_t *src_space, const H5S_t *dst_space, HDassert(H5S_GET_SELECT_NPOINTS(src_space) == H5S_GET_SELECT_NPOINTS(dst_space)); HDassert(H5S_GET_EXTENT_NDIMS(src_space) == H5S_GET_EXTENT_NDIMS(src_intersect_space)); + if(NULL == (ss_iter = H5FL_CALLOC(H5S_sel_iter_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate selection iterator") + if(NULL == (ds_iter = H5FL_CALLOC(H5S_sel_iter_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate selection iterator") + /* Create new space, using dst extent. Start with "all" selection. */ if(NULL == (new_space = H5S_create(H5S_SIMPLE))) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "unable to create output dataspace") @@ -2358,18 +2654,136 @@ H5S_select_project_intersection(const H5S_t *src_space, const H5S_t *dst_space, if(H5S_select_none(new_space) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection") } /* end if */ - /* If any of the spaces use point selection, fall back to general algorithm - */ - else if((src_intersect_space->select.type->type == H5S_SEL_POINTS) - || (src_space->select.type->type == H5S_SEL_POINTS) - || (dst_space->select.type->type == H5S_SEL_POINTS)) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "point selections not currently supported") else { - HDassert(src_intersect_space->select.type->type == H5S_SEL_HYPERSLABS); - /* Intersecting space is hyperslab selection. Call the hyperslab - * routine to project to another hyperslab selection. */ - if(H5S__hyper_project_intersection(src_space, dst_space, src_intersect_space, new_space) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't project hyperslab ondot destination selection") + /* Handle scalar dataspaces. It should not be possible for the source + * intersect space or the source space to be scalar since scalar spaces + * only support all or none selections, and both of those cases are + * covered above, and the source intersect space must have the same + * rank, so it also cannot be scalar, as scalar dataspaces have a rank + * of 0. */ + HDassert(H5S_GET_EXTENT_TYPE(src_space) != H5S_SCALAR); + HDassert(H5S_GET_EXTENT_TYPE(src_intersect_space) != H5S_SCALAR); + + /* Check for scalar dst_space. In this case we simply check if the + * (single) point selected in src_space intersects src_intersect_space, + * if so select all in new_space, otherwise select none. */ + if(H5S_GET_EXTENT_TYPE(dst_space) == H5S_SCALAR) { + hsize_t coords_start[H5S_MAX_RANK]; + hsize_t coords_end[H5S_MAX_RANK]; + htri_t intersect; + + /* Get source space bounds. Should be a single point. */ + if(H5S_SELECT_BOUNDS(src_space, coords_start, coords_end) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get source space bounds") + HDassert(0 == HDmemcmp(coords_start, coords_end, H5S_GET_EXTENT_NDIMS(src_space) * sizeof(coords_start[0]))); + + /* Check for intersection */ + if((intersect = H5S_SELECT_INTERSECT_BLOCK(src_intersect_space, coords_start, coords_end)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "can't check for intersection") + + /* Select all or none as appropriate */ + if(intersect) { + if(H5S_select_all(new_space, TRUE) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't select all") + } /* end if */ + else + if(H5S_select_none(new_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection") + } /* end if */ + else { + /* If the source intersect space is a point selection, convert it to a + * hyperslab (discarding ordering). We can get away with this because + * the order does not matter for the source intersect space */ + /* Maybe we should just leave it as a point selection for the point by + * point algorithm? The search through the selection in + * H5S_SELECT_INTERSECT_BLOCK will likely be O(N) either way. -NAF */ + if(H5S_GET_SELECT_TYPE(src_intersect_space) == H5S_SEL_POINTS) { + H5S_pnt_node_t *curr_pnt = src_intersect_space->select.sel_info.pnt_lst->head; + + /* Create dataspace and copy extent */ + if(NULL == (tmp_src_intersect_space = H5S_create(H5S_SIMPLE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "unable to create temporary source intersect dataspace") + if(H5S__extent_copy_real(&tmp_src_intersect_space->extent, &src_intersect_space->extent, FALSE) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy source intersect space extent") + + /* Iterate over points */ + for(curr_pnt = src_intersect_space->select.sel_info.pnt_lst->head; curr_pnt; curr_pnt = curr_pnt->next) + /* Add point to hyperslab selection */ + if(H5S_hyper_add_span_element(tmp_src_intersect_space, src_intersect_space->extent.rank, curr_pnt->pnt) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't add point to temporary dataspace selection") + + /* Redirect local src_intersect_space pointer (will not affect + * calling function) */ + src_intersect_space = tmp_src_intersect_space; + } /* end for */ + + /* By this point, src_intersect_space must be a hyperslab selection */ + HDassert(H5S_GET_SELECT_TYPE(src_intersect_space) == H5S_SEL_HYPERSLABS); + + /* If either the source space or the destination space is a point + * selection, iterate element by element */ + if((H5S_GET_SELECT_TYPE(src_space) == H5S_SEL_POINTS) + || (H5S_GET_SELECT_TYPE(dst_space) == H5S_SEL_POINTS)) { + hsize_t coords[H5S_MAX_RANK]; + htri_t intersect; + + /* Start with "none" selection */ + if(H5S_select_none(new_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection") + + /* Initialize iterators */ + if(H5S_select_iter_init(ss_iter, src_space, 1, H5S_SEL_ITER_SHARE_WITH_DATASPACE) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't initialize source space selection iterator") + ss_iter_init = TRUE; + if(H5S_select_iter_init(ds_iter, dst_space, 1, H5S_SEL_ITER_SHARE_WITH_DATASPACE) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't initialize destination space selection iterator") + ds_iter_init = TRUE; + + /* Iterate over points */ + do { + HDassert(ss_iter->elmt_left > 0); + HDassert(ss_iter->elmt_left > 0); + + /* Get SS coords */ + if(H5S_SELECT_ITER_COORDS(ss_iter, coords) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get source selection coordinates") + + /* Check for intersection */ + if((intersect = H5S_SELECT_INTERSECT_BLOCK(src_intersect_space, coords, coords)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "can't check for intersection") + + /* Add point if it intersects */ + if(intersect) { + /* Get DS coords */ + if(H5S_SELECT_ITER_COORDS(ds_iter, coords) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get destination selection coordinates") + + /* Add point to new_space */ + if(H5S_select_elements(new_space, H5S_SELECT_APPEND, 1, coords) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't add point to new selection") + } /* end if */ + + /* Advance iterators */ + if(H5S_SELECT_ITER_NEXT(ss_iter, 1) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTNEXT, FAIL, "can't advacne source selection iterator") + ss_iter->elmt_left--; + if(H5S_SELECT_ITER_NEXT(ds_iter, 1) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTNEXT, FAIL, "can't advacne destination selection iterator") + ds_iter->elmt_left--; + } while(ss_iter->elmt_left > 0); + HDassert(H5S_SELECT_ITER_NELMTS(ds_iter) == 0); + } /* end if */ + else { + HDassert(H5S_GET_SELECT_TYPE(src_space) != H5S_SEL_NONE); + HDassert(H5S_GET_SELECT_TYPE(dst_space) != H5S_SEL_NONE); + + /* Source and destination selections are all or hyperslab, + * intersecting selection is hyperslab. Call the hyperslab routine + * to project to another hyperslab selection. */ + if(H5S__hyper_project_intersection(src_space, dst_space, src_intersect_space, new_space, share_selection) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't project hyperslab onto destination selection") + } /* end else */ + } /* end else */ } /* end else */ /* load the address of the new space into *new_space_ptr */ @@ -2381,12 +2795,100 @@ done: if(new_space && H5S_close(new_space) < 0) HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataspace") + /* General cleanup */ + if(tmp_src_intersect_space && H5S_close(tmp_src_intersect_space) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release temporary dataspace") + if(ss_iter_init && H5S_SELECT_ITER_RELEASE(ss_iter) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release source selection iterator") + if(ds_iter_init && H5S_SELECT_ITER_RELEASE(ds_iter) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release destination selection iterator") + + ss_iter = H5FL_FREE(H5S_sel_iter_t, ss_iter); + ds_iter = H5FL_FREE(H5S_sel_iter_t, ds_iter); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5S_select_project_intersection() */ /*-------------------------------------------------------------------------- NAME + H5Sselect_project_intersection + + PURPOSE + Projects the intersection of of the selections of src_space_id and + src_intersect_space_id within the selection of src_space_id as a + selection within the selection of dst_space_id. + + USAGE + hid_t H5Sselect_project_intersection(src_space_id,dst_space_d,src_intersect_space_id) + hid_t src_space_id; IN: Selection that is mapped to dst_space_id, and intersected with src_intersect_space_id + hid_t dst_space_id; IN: Selection that is mapped to src_space_id + hid_t src_intersect_space_id; IN: Selection whose intersection with src_space_id is projected to dst_space_id to obtain the result + + RETURNS + A dataspace with a selection equal to the intersection of + src_intersect_space_id and src_space_id projected from src_space to + dst_space on success, negative on failure. + + DESCRIPTION + Projects the intersection of of the selections of src_space and + src_intersect_space within the selection of src_space as a selection + within the selection of dst_space. The result is placed in the + selection of new_space_ptr. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +hid_t +H5Sselect_project_intersection(hid_t src_space_id, hid_t dst_space_id, + hid_t src_intersect_space_id) +{ + H5S_t *src_space, *dst_space, *src_intersect_space; /* Input dataspaces */ + H5S_t *proj_space = NULL; /* Output dataspace */ + hid_t ret_value; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE3("i", "iii", src_space_id, dst_space_id, src_intersect_space_id); + + /* Check args */ + if(NULL == (src_space = (H5S_t *)H5I_object_verify(src_space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "not a dataspace") + if(NULL == (dst_space = (H5S_t *)H5I_object_verify(dst_space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "not a dataspace") + if(NULL == (src_intersect_space = (H5S_t *)H5I_object_verify(src_intersect_space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADTYPE, FAIL, "not a dataspace") + + /* Check numbers of points selected matches in source and destination */ + if(H5S_GET_SELECT_NPOINTS(src_space) != H5S_GET_SELECT_NPOINTS(dst_space)) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "number of points selected in source space does not match that in destination space") + + /* Check numbers of dimensions matches in source and source intersect spaces + */ + if(H5S_GET_EXTENT_NDIMS(src_space) != H5S_GET_EXTENT_NDIMS(src_intersect_space)) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "rank of source space does not match rank of source intersect space") + + /* Perform operation */ + if(H5S_select_project_intersection(src_space, dst_space, + src_intersect_space, &proj_space, FALSE) < 0) + HGOTO_ERROR(H5E_DATASET, H5E_CANTCLIP, FAIL, "can't project dataspace intersection") + + /* Atomize */ + if((ret_value = H5I_register(H5I_DATASPACE, proj_space, TRUE)) < 0) + HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom") + +done: + if(ret_value < 0) + if(proj_space && H5S_close(proj_space) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release dataspace") + + FUNC_LEAVE_API(ret_value) +} /* end H5Sselect_project_intersection() */ + + +/*-------------------------------------------------------------------------- + NAME H5S_select_subtract PURPOSE @@ -2431,12 +2933,13 @@ H5S_select_subtract(H5S_t *space, H5S_t *subtract_space) if(H5S_select_none(space) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection") } /* end if */ + /* If either selection is a point selection, fail currently */ + else if((subtract_space->select.type->type == H5S_SEL_POINTS) || + (space->select.type->type == H5S_SEL_POINTS)) { + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "point selections not currently supported") + } /* end if */ else { - /* Check for point selection in subtract_space, convert to hyperslab */ - if(subtract_space->select.type->type == H5S_SEL_POINTS) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "point selections not currently supported") - - /* Check for point or all selection in space, convert to hyperslab */ + /* Check for all selection in space, convert to hyperslab */ if(space->select.type->type == H5S_SEL_ALL) { /* Convert current "all" selection to "real" hyperslab selection */ /* Then allow operation to proceed */ @@ -2458,14 +2961,12 @@ H5S_select_subtract(H5S_t *space, H5S_t *subtract_space) if(H5S_select_hyperslab(space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count, tmp_block) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection") } /* end if */ - else if(space->select.type->type == H5S_SEL_POINTS) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "point selections not currently supported") HDassert(space->select.type->type == H5S_SEL_HYPERSLABS); HDassert(subtract_space->select.type->type == H5S_SEL_HYPERSLABS); /* Both spaces are now hyperslabs, perform the operation */ - if(H5S__hyper_subtract(space, subtract_space) < 0) + if(H5S__modify_select(space, H5S_SELECT_NOTB, subtract_space) < 0) HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't subtract hyperslab") } /* end else */ } /* end if */ @@ -2474,3 +2975,37 @@ done: FUNC_LEAVE_NOAPI(ret_value) } /* end H5S_select_subtract() */ + +/*------------------------------------------------------------------------- + * Function: H5S_sel_iter_close + * + * Purpose: Releases a dataspace selection iterator and its memory. + * + * Return: Non-negative on success / Negative on failure + * + * Programmer: Quincey Koziol + * Monday, February 11, 2019 + * + *------------------------------------------------------------------------- + */ +herr_t +H5S_sel_iter_close(H5S_sel_iter_t *sel_iter) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity check */ + HDassert(sel_iter); + + /* Call selection type-specific release routine */ + if(H5S_SELECT_ITER_RELEASE(sel_iter) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "problem releasing a selection iterator's type-specific info") + + /* Release the structure */ + sel_iter = H5FL_FREE(H5S_sel_iter_t, sel_iter); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_sel_iter_close() */ + diff --git a/src/H5Stest.c b/src/H5Stest.c index 4c7709b..b61b6bf 100644 --- a/src/H5Stest.c +++ b/src/H5Stest.c @@ -68,12 +68,18 @@ NAME H5S__get_rebuild_status_test PURPOSE - Determine the status of hyperslab rebuild + Determine the status of the diminfo_valid field (whether we know the + selection information for an equivalent single hyperslab selection) + before and after calling H5S__hyper_rebuild. USAGE - htri_t H5S__inquiry_rebuild_status(hid_t space_id) + herr_t H5S__get_rebuild_status_test(space_id, status1, status2) hid_t space_id; IN: dataspace id + H5S_diminfo_valid_t *status1; OUT: status before calling + H5S__hyper_rebuild + H5S_diminfo_valid_t *status2; OUT: status after calling + H5S__hyper_rebuild RETURNS - Non-negative TRUE/FALSE on success, negative on failure + Non-negative on success, negative on failure DESCRIPTION Query the status of rebuilding the hyperslab GLOBAL VARIABLES @@ -82,22 +88,29 @@ EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -htri_t -H5S__get_rebuild_status_test(hid_t space_id) +herr_t +H5S__get_rebuild_status_test(hid_t space_id, H5S_diminfo_valid_t *status1, + H5S_diminfo_valid_t *status2) { H5S_t *space; /* Pointer to 1st dataspace */ - htri_t ret_value = FAIL; /* Return value */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_PACKAGE + + HDassert(status1); + HDassert(status2); /* Get dataspace structures */ if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") - if(H5S_DIMINFO_VALID_YES == space->select.sel_info.hslab->diminfo_valid) - ret_value = TRUE; - else - ret_value = FALSE; + *status1 = space->select.sel_info.hslab->diminfo_valid; + + /* Fully rebuild diminfo, if necessary */ + if(*status1 == H5S_DIMINFO_VALID_NO) + H5S__hyper_rebuild(space); + + *status2 = space->select.sel_info.hslab->diminfo_valid; done: FUNC_LEAVE_NOAPI(ret_value) @@ -106,18 +119,229 @@ done: /*-------------------------------------------------------------------------- NAME - H5S_select_shape_same_test + H5S__get_diminfo_status_test + PURPOSE + Determine the status of the diminfo_valid field (whether we know the + selection information for an equivalent single hyperslab selection) + USAGE + herr_t H5S__get_diminfo_status_test(space_id, status) + hid_t space_id; IN: dataspace id + H5S_diminfo_valid_t *status; OUT: status of diminfo_valid + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Query the status of rebuilding the hyperslab + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5S__get_diminfo_status_test(hid_t space_id, H5S_diminfo_valid_t *status) +{ + H5S_t *space; /* Pointer to 1st dataspace */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + HDassert(status); + + /* Get dataspace structures */ + if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") + + *status = space->select.sel_info.hslab->diminfo_valid; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S__get_diminfo_status_test() */ + +/*-------------------------------------------------------------------------- + NAME + H5S__check_spans_tail_ptr PURPOSE - Determine if two dataspace selections are the same shape + Determine if the tail pointer of the spans are correctly set USAGE - htri_t H5S_select_shape_same_test(sid1, sid2) - hid_t sid1; IN: 1st dataspace to compare - hid_t sid2; IN: 2nd dataspace to compare + herr_t H5S__check_spans_tail_ptr(span_lst) + const H5S_hyper_span_info_t *span_lst; IN: the spans to check for taill pointers + RETURNS + SUCCEED/FAIL + DESCRIPTION + Checks to see if the current selection in the dataspaces has tail pointers of each + dimension correctly set. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Only check the hyperslab selection + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__check_spans_tail_ptr(const H5S_hyper_span_info_t *span_lst) +{ + H5S_hyper_span_t *cur_elem; + H5S_hyper_span_t *actual_tail = NULL; + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC + + HDassert(span_lst); + + cur_elem = span_lst->head; + while(cur_elem) { + actual_tail = cur_elem; + + /* check the next dimension of lower order */ + if(NULL != cur_elem->down) + if((ret_value = H5S__check_spans_tail_ptr(cur_elem->down)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_INCONSISTENTSTATE, FAIL, "the seletion has inconsistent tail pointers") + + cur_elem = cur_elem->next; + } /* end while */ + if(actual_tail != span_lst->tail) + HGOTO_ERROR(H5E_DATASPACE, H5E_INCONSISTENTSTATE, FAIL, "the seletion has inconsistent tail pointers") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S__check_spans_tail_ptr */ + +/*-------------------------------------------------------------------------- + NAME + H5S__check_points_tail_ptr + PURPOSE + Determine if the tail pointer of the points list are correctly set + USAGE + herr_t H5S__check_points_tail_ptr(pnt_lst) + const H5S_pnt_list_t *pnt_lst; IN: the points list to check for taill pointers + RETURNS + SUCCEED/FAIL + DESCRIPTION + Checks to see if the current selection in the dataspaces has tail pointers correctly set. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Only check the points selection + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__check_points_tail_ptr(const H5S_pnt_list_t *pnt_lst) +{ + H5S_pnt_node_t *cur_elem; + H5S_pnt_node_t *actual_tail = NULL; + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_STATIC + + HDassert(pnt_lst); + + cur_elem = pnt_lst->head; + while(cur_elem) { + actual_tail = cur_elem; + cur_elem = cur_elem->next; + } /* end while */ + if(actual_tail != pnt_lst->tail) + HGOTO_ERROR(H5E_DATASPACE, H5E_INCONSISTENTSTATE, FAIL, "the seletion has inconsistent tail pointers") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S__check_points_tail_ptr */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__check_internal_consistency + PURPOSE + Determine if internal data structures are consistent + USAGE + herr_t H5S__check_internal_consistency(space) + const H5S_t *space; IN: 1st Dataspace pointer to compare + RETURNS + SUCCEED/FAIL + DESCRIPTION + Checks to see if the current selection in the dataspaces has consistent + state of internal data structure. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Currently only check the hyperslab selection + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S__check_internal_consistency(const H5S_t *space) +{ + hsize_t low_bounds[H5S_MAX_RANK]; + hsize_t high_bounds[H5S_MAX_RANK]; + unsigned u; + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_STATIC + + /* Check args */ + HDassert(space); + + if(space->select.type->type == H5S_SEL_NONE) + HGOTO_DONE(ret_value); + + /* Initialize the inputs */ + for(u = 0; u < space->extent.rank; u++) { + low_bounds[u] = HSIZET_MAX; + high_bounds[u] = 0; + } /* end for */ + + /* Check the bound box */ + if(H5S_get_select_bounds(space, low_bounds, high_bounds) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_INCONSISTENTSTATE, FAIL, "the bound box could not be retrieved") + + if(space->select.type->type == H5S_SEL_HYPERSLABS) { + H5S_hyper_sel_t *hslab = space->select.sel_info.hslab; + + if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) { + for(u = 0; u < space->extent.rank; u++) { + if((hsize_t)((hssize_t)hslab->diminfo.low_bounds[u] + space->select.offset[u]) != low_bounds[u]) + HGOTO_ERROR(H5E_DATASPACE, H5E_INCONSISTENTSTATE, FAIL, "the lower bound box of the selection is inconsistent") + if((hsize_t)((hssize_t)hslab->diminfo.high_bounds[u] + space->select.offset[u]) != high_bounds[u]) + HGOTO_ERROR(H5E_DATASPACE, H5E_INCONSISTENTSTATE, FAIL, "the higher bound box of the selection is inconsistent") + } /* end for */ + } /* end if */ + else { + for(u = 0; u < space->extent.rank; u++) { + if((hsize_t)((hssize_t)hslab->span_lst->low_bounds[u] + space->select.offset[u]) != low_bounds[u]) + HGOTO_ERROR(H5E_DATASPACE, H5E_INCONSISTENTSTATE, FAIL, "the lower bound box of the selection is inconsistent") + if((hsize_t)((hssize_t)hslab->span_lst->high_bounds[u] + space->select.offset[u]) != high_bounds[u]) + HGOTO_ERROR(H5E_DATASPACE, H5E_INCONSISTENTSTATE, FAIL, "the higher bound box of the selection is inconsistent") + } /* end for */ + } /* end else */ + + /* check the tail pointer */ + if((NULL != hslab) && (NULL != hslab->span_lst)) + if(H5S__check_spans_tail_ptr(hslab->span_lst) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_INCONSISTENTSTATE, FAIL, "the seletion has inconsistent tail pointers") + } /* end if */ + else if(space->select.type->type == H5S_SEL_POINTS) { + H5S_pnt_list_t *pnt_lst = space->select.sel_info.pnt_lst; + + if(NULL != pnt_lst) + if(H5S__check_points_tail_ptr(pnt_lst) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_INCONSISTENTSTATE, FAIL, "the seletion has inconsistent tail pointers") + } /* end else-if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S__check_internal_consistency */ + +/*-------------------------------------------------------------------------- + NAME + H5S__internal_consistency_test + PURPOSE + Determine if states of internal data structures are consistent + USAGE + htri_t H5S__internal_consistency_test(hid_t space_id) + hid_t space_id; IN: dataspace id RETURNS Non-negative TRUE/FALSE on success, negative on failure DESCRIPTION - Checks to see if the current selection in the dataspaces are the same - dimensionality and shape. + Check the states of internal data structures of the hyperslab, and see + whether they are consistent or not GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS DO NOT USE THIS FUNCTION FOR ANYTHING EXCEPT TESTING @@ -125,25 +349,22 @@ done: REVISION LOG --------------------------------------------------------------------------*/ htri_t -H5S_select_shape_same_test(hid_t sid1, hid_t sid2) +H5S__internal_consistency_test(hid_t space_id) { - H5S_t *space1; /* Pointer to 1st dataspace */ - H5S_t *space2; /* Pointer to 2nd dataspace */ - htri_t ret_value = FAIL; /* Return value */ + H5S_t *space; /* Pointer to 1st dataspace */ + htri_t ret_value = TRUE; /* Return value */ - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_PACKAGE - /* Get dataspace structures */ - if(NULL == (space1 = (H5S_t *)H5I_object_verify(sid1, H5I_DATASPACE))) - HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") - if(NULL == (space2 = (H5S_t *)H5I_object_verify(sid2, H5I_DATASPACE))) + /* Get dataspace structures */ + if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace") /* Check if the dataspace selections are the same shape */ - if((ret_value = H5S_select_shape_same(space1, space2)) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "unable to compare dataspace selections") + if(FAIL == H5S__check_internal_consistency(space)) + HGOTO_ERROR(H5E_DATASPACE, H5E_INCONSISTENTSTATE, FAIL, "The dataspace has inconsistent internal state") done: FUNC_LEAVE_NOAPI(ret_value) -} /* H5S_select_shape_same_test() */ +} /* H5S__internal_consistency_test() */ diff --git a/src/H5T.c b/src/H5T.c index b472269..2ecc474 100644 --- a/src/H5T.c +++ b/src/H5T.c @@ -290,12 +290,9 @@ typedef H5T_t *(*H5T_copy_func_t)(H5T_t *old_dt); /********************/ /* Local Prototypes */ /********************/ -static herr_t H5T__register_int(H5T_pers_t pers, const char *name, H5T_t *src, - H5T_t *dst, H5T_lib_conv_t func); -static herr_t H5T__register(H5T_pers_t pers, const char *name, H5T_t *src, - H5T_t *dst, H5T_conv_func_t *conv); -static herr_t H5T__unregister(H5T_pers_t pers, const char *name, H5T_t *src, - H5T_t *dst, H5T_conv_t func); +static herr_t H5T__register_int(H5T_pers_t pers, const char *name, H5T_t *src, H5T_t *dst, H5T_lib_conv_t func); +static herr_t H5T__register(H5T_pers_t pers, const char *name, H5T_t *src, H5T_t *dst, H5T_conv_func_t *conv); +static herr_t H5T__unregister(H5T_pers_t pers, const char *name, H5T_t *src, H5T_t *dst, H5T_conv_t func); static htri_t H5T__compiler_conv(H5T_t *src, H5T_t *dst); static herr_t H5T__set_size(H5T_t *dt, size_t size); static herr_t H5T__close_cb(H5T_t *dt); @@ -307,6 +304,7 @@ static H5T_t *H5T__copy_all(H5T_t *old_dt); static herr_t H5T__complete_copy(H5T_t *new_dt, const H5T_t *old_dt, H5T_shared_t *reopened_fo, hbool_t set_memory_type, H5T_copy_func_t copyfn); + /*****************************/ /* Library Private Variables */ /*****************************/ @@ -1705,6 +1703,7 @@ H5Tcopy(hid_t obj_id) case H5I_ERROR_CLASS: case H5I_ERROR_MSG: case H5I_ERROR_STACK: + case H5I_SPACE_SEL_ITER: case H5I_NTYPES: default: HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a datatype or dataset") @@ -5165,6 +5164,8 @@ H5T_convert(H5T_path_t *tpath, hid_t src_id, hid_t dst_id, size_t nelmts, if(H5DEBUG(T)) H5_timer_begin(&timer); #endif + + /* Call the appropriate conversion callback */ tpath->cdata.command = H5T_CONV_CONV; if(tpath->conv.is_app) { if((tpath->conv.u.app_func)(src_id, dst_id, &(tpath->cdata), nelmts, buf_stride, bkg_stride, buf, bkg, H5CX_get_dxpl()) < 0) @@ -5503,7 +5504,7 @@ H5T_set_loc(H5T_t *dt, H5F_t *f, H5T_loc_t loc) /* Mark the VL, compound or array type */ if((changed=H5T_set_loc(dt->shared->parent,f,loc))<0) - HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "Unable to set VL location"); + HGOTO_ERROR(H5E_DATATYPE, H5E_CANTINIT, FAIL, "Unable to set VL location") if(changed>0) ret_value=changed; diff --git a/src/H5err.txt b/src/H5err.txt index 75faeeb..30c646f 100644 --- a/src/H5err.txt +++ b/src/H5err.txt @@ -226,6 +226,7 @@ MINOR, DSPACE, H5E_CANTSELECT, Can't select hyperslab MINOR, DSPACE, H5E_CANTNEXT, Can't move to next iterator location MINOR, DSPACE, H5E_BADSELECT, Invalid selection MINOR, DSPACE, H5E_CANTCOMPARE, Can't compare objects +MINOR, DSPACE, H5E_INCONSISTENTSTATE, Internal states are inconsistent MINOR, DSPACE, H5E_CANTAPPEND, Can't append object # Property list errors diff --git a/src/H5trace.c b/src/H5trace.c index afcf309..93ff681 100644 --- a/src/H5trace.c +++ b/src/H5trace.c @@ -247,7 +247,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'a': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -261,7 +261,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'b': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -280,7 +280,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'd': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -296,7 +296,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'a': if(ptr) { if(vp) - HDfprintf (out, "0x%lx", (unsigned long)vp); + HDfprintf (out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -334,7 +334,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'c': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -360,7 +360,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'f': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -394,7 +394,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'F': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -428,7 +428,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'h': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -458,7 +458,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'i': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -496,7 +496,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'k': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -542,7 +542,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'l': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -584,7 +584,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'n': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -631,7 +631,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'o': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -661,7 +661,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 's': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -695,7 +695,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 't': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -721,7 +721,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'v': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -757,7 +757,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'e': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -776,7 +776,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'd': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -802,21 +802,21 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'e': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ else { H5E_error2_t *error = HDva_arg(ap, H5E_error2_t *); - HDfprintf(out, "0x%lx", (unsigned long)error); + HDfprintf(out, "0x%p", error); } /* end else */ break; case 't': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -850,7 +850,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'd': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -884,7 +884,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'f': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -919,7 +919,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'm': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -970,7 +970,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 's': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -996,7 +996,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 't': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1005,7 +1005,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'v': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1047,7 +1047,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'o': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1095,14 +1095,14 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 's': if(ptr) { if(vp) - HDfprintf (out, "0x%lx", (unsigned long)vp); + HDfprintf (out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ else { H5G_stat_t *statbuf = HDva_arg(ap, H5G_stat_t*); - HDfprintf(out, "0x%lx", (unsigned long)statbuf); + HDfprintf(out, "0x%p", statbuf); } break; #endif /* H5_NO_DEPRECATED_SYMBOLS */ @@ -1116,7 +1116,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'h': if(ptr) { if(vp) { - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); if(asize_idx >= 0 && asize[asize_idx] >= 0) { hsize_t *p = (hsize_t *)vp; @@ -1150,7 +1150,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 's': if(ptr) { if(vp) { - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); if(asize_idx >= 0 && asize[asize_idx] >= 0) { hssize_t *p = (hssize_t *)vp; @@ -1180,7 +1180,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'i': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1351,6 +1351,10 @@ H5_trace(const double *returning, const char *func, const char *type, ...) HDfprintf(out, "%ld (err stack)", (long)obj); break; + case H5I_SPACE_SEL_ITER: + HDfprintf(out, "%ld (dataspace selection iterator)", (long)obj); + break; + case H5I_NTYPES: HDfprintf (out, "%ld (ntypes - error)", (long)obj); break; @@ -1368,7 +1372,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'i': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1402,7 +1406,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'o': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1440,7 +1444,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 's': if(ptr) { if(vp) { - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); if(asize_idx >= 0 && asize[asize_idx] >= 0) { int *p = (int*)vp; @@ -1464,7 +1468,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 't': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1532,6 +1536,10 @@ H5_trace(const double *returning, const char *func, const char *type, ...) HDfprintf(out, "H5I_ERROR_STACK"); break; + case H5I_SPACE_SEL_ITER: + HDfprintf(out, "H5I_SPACE_SEL_ITER"); + break; + case H5I_NTYPES: HDfprintf(out, "H5I_NTYPES"); break; @@ -1546,7 +1554,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'u': if(ptr) { if(vp) { - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); if(asize_idx >= 0 && asize[asize_idx] >= 0) { unsigned *p = (unsigned*)vp; @@ -1578,7 +1586,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'l': if(ptr) { if(vp) - HDfprintf (out, "0x%lx", (unsigned long)vp); + HDfprintf (out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1624,7 +1632,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'c': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1640,7 +1648,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'i': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1656,7 +1664,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 't': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1715,7 +1723,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'o': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1731,7 +1739,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 't': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1775,7 +1783,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'p': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1799,7 +1807,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'r': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1815,7 +1823,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 't': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1857,7 +1865,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'c': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1891,7 +1899,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 's': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1949,7 +1957,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 't': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -1997,7 +2005,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 's': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2013,7 +2021,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'c': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2060,7 +2068,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'd': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2090,7 +2098,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'e': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2120,7 +2128,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'n': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2154,7 +2162,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'o': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2196,7 +2204,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'p': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2234,7 +2242,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 's': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2268,7 +2276,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 't': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2338,7 +2346,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'z': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2394,7 +2402,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 't': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2415,7 +2423,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'l': if(ptr) { if(vp) { - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); if(asize_idx >= 0 && asize[asize_idx] >= 0) { unsigned long *p = (unsigned long *)vp; @@ -2439,7 +2447,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'L': if(ptr) { if(vp) { - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); if(asize_idx >= 0 && asize[asize_idx] >= 0) { unsigned long long *p = (unsigned long long *)vp; @@ -2469,14 +2477,14 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'x': if(ptr) { if(vp) { - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); if(asize_idx >= 0 && asize[asize_idx] >= 0) { void **p = (void**)vp; HDfprintf(out, " {"); for(i = 0; i < asize[asize_idx]; i++) { if(p[i]) - HDfprintf(out, "%s0x%lx", (i ? ", " : ""), (unsigned long)(p[i])); + HDfprintf(out, "%s0x%p", (i ? ", " : ""), p[i]); else HDfprintf(out, "%sNULL", (i ? ", " : "")); } /* end for */ @@ -2490,7 +2498,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) vp = HDva_arg (ap, void *); if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end else */ @@ -2499,7 +2507,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'z': if(ptr) { if(vp) { - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); if(asize_idx >= 0 && asize[asize_idx] >= 0) { size_t *p = (size_t *)vp; @@ -2525,7 +2533,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'a': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2555,21 +2563,21 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'c': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ else { H5Z_class2_t *filter = HDva_arg(ap, H5Z_class2_t*); - HDfprintf(out, "0x%lx", (unsigned long)filter); + HDfprintf(out, "0x%p", filter); } /* end else */ break; case 'e': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2588,7 +2596,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 'f': if(ptr) { if(vp) - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); else HDfprintf(out, "NULL"); } /* end if */ @@ -2605,7 +2613,7 @@ H5_trace(const double *returning, const char *func, const char *type, ...) case 's': if(ptr) { if(vp) { - HDfprintf(out, "0x%lx", (unsigned long)vp); + HDfprintf(out, "0x%p", vp); if(asize_idx >= 0 && asize[asize_idx] >= 0) { ssize_t *p = (ssize_t *)vp; diff --git a/test/links.c b/test/links.c index b9d23aa..0c10b44 100644 --- a/test/links.c +++ b/test/links.c @@ -3452,17 +3452,23 @@ error: static int external_set_elink_fapl2(hid_t fapl, hbool_t new_format) { - hid_t fid = (-1); /* File ID */ - hid_t gid = (-1); /* Group IDs */ - hid_t core_fapl = -1, space = -1, dset = -1, did = -1, dapl_id = -1, dcpl = -1; + hid_t fid = H5I_INVALID_HID; + hid_t gid = H5I_INVALID_HID; + hid_t core_fapl = H5I_INVALID_HID; + hid_t space = H5I_INVALID_HID; + hid_t dset = H5I_INVALID_HID; + hid_t did = H5I_INVALID_HID; + hid_t dapl_id = H5I_INVALID_HID; + hid_t dcpl = H5I_INVALID_HID; char filename1[NAME_BUF_SIZE], filename2[NAME_BUF_SIZE], tmpname[NAME_BUF_SIZE], cwdpath[NAME_BUF_SIZE]; - hsize_t dims[2]; + hsize_t dims[2]; int points[NUM40][NUM40]; - int i, j, n; - h5_stat_size_t filesize, new_filesize; + int i, j, n; + h5_stat_size_t filesize; + h5_stat_size_t new_filesize; if(new_format) TESTING("H5Pset/get_elink_fapl() with same physical layout (w/new group format)") @@ -3501,7 +3507,8 @@ external_set_elink_fapl2(hid_t fapl, hbool_t new_format) dcpl = H5Pcreate(H5P_DATASET_CREATE); else dcpl = H5Pcopy(dcpl_g); - if (0 > dcpl) TEST_ERROR; + if (0 > dcpl) + TEST_ERROR; if(H5Pset_alloc_time(dcpl, H5D_ALLOC_TIME_LATE) < 0) TEST_ERROR; /* create "Dataset" in group "A" of target file */ @@ -7120,6 +7127,7 @@ done: case H5I_ERROR_CLASS: case H5I_ERROR_MSG: case H5I_ERROR_STACK: + case H5I_SPACE_SEL_ITER: case H5I_NTYPES: default: return FAIL; @@ -7208,6 +7216,7 @@ done: case H5I_ERROR_CLASS: case H5I_ERROR_MSG: case H5I_ERROR_STACK: + case H5I_SPACE_SEL_ITER: case H5I_NTYPES: default: return FAIL; diff --git a/test/objcopy.c b/test/objcopy.c index 3c5981c..94d81bf 100644 --- a/test/objcopy.c +++ b/test/objcopy.c @@ -1153,7 +1153,7 @@ compare_data(hid_t parent1, hid_t parent2, hid_t pid, hid_t tid, size_t nelmts, if((obj2_sid = H5Rget_region(parent2, H5R_DATASET_REGION, ref_buf2)) < 0) TEST_ERROR /* Check if dataspaces are the same shape */ - if(H5S_select_shape_same_test(obj1_sid, obj2_sid) < 0) TEST_ERROR + if(H5Sselect_shape_same(obj1_sid, obj2_sid) < 0) TEST_ERROR /* Close dataspaces */ if(H5Sclose(obj1_sid) < 0) TEST_ERROR diff --git a/test/testfiles/err_compat_1 b/test/testfiles/err_compat_1 index e8ea044..d81dba1 100644 --- a/test/testfiles/err_compat_1 +++ b/test/testfiles/err_compat_1 @@ -15,7 +15,7 @@ HDF5-DIAG: Error detected in HDF5 (version (number)) thread (IDs): #000: (file name) line (number) in H5Dcreate2(): not a location ID major: Invalid arguments to routine minor: Inappropriate type - #001: (file name) line (number) in H5G_loc(): invalid object ID + #001: (file name) line (number) in H5G_loc(): invalid location ID major: Invalid arguments to routine minor: Bad value @@ -43,7 +43,7 @@ HDF5-DIAG: Error detected in HDF5 (version (number)) thread (IDs): #000: (file name) line (number) in H5Dcreate2(): not a location ID major: Invalid arguments to routine minor: Inappropriate type - #001: (file name) line (number) in H5G_loc(): invalid object ID + #001: (file name) line (number) in H5G_loc(): invalid location ID major: Invalid arguments to routine minor: Bad value diff --git a/test/tfile.c b/test/tfile.c index 6c313ba..6ad8b5a 100644 --- a/test/tfile.c +++ b/test/tfile.c @@ -1445,6 +1445,7 @@ test_obj_count_and_id(hid_t fid1, hid_t fid2, hid_t did, hid_t gid1, case H5I_ERROR_CLASS: case H5I_ERROR_MSG: case H5I_ERROR_STACK: + case H5I_SPACE_SEL_ITER: case H5I_NTYPES: default: ERROR("H5Fget_obj_ids"); diff --git a/test/th5s.c b/test/th5s.c index 1059b96..2afe473 100644 --- a/test/th5s.c +++ b/test/th5s.c @@ -22,7 +22,6 @@ #include "testhdf5.h" #include "H5srcdir.h" -#include "H5Bprivate.h" #include "H5Iprivate.h" #include "H5Pprivate.h" @@ -31,6 +30,7 @@ * This file also needs to access the dataspace testing code. */ #define H5S_FRIEND /*suppress error about including H5Spkg */ +#define H5S_TESTING /*suppress warning about H5S testing funcs*/ #include "H5Spkg.h" /* Dataspaces */ /* diff --git a/test/tselect.c b/test/tselect.c index 0637c33..770b78a 100644 --- a/test/tselect.c +++ b/test/tselect.c @@ -176,6 +176,13 @@ #define SEL_ITER_MAX_SEQ 256 +/* Defines for test_hyper_io_1d() */ +#define DNAME "DSET_1D" +#define RANK 1 +#define NUMCHUNKS 3 +#define CHUNKSZ 20 +#define NUM_ELEMENTS NUMCHUNKS * CHUNKSZ + /* Location comparison function */ static int compare_size_t(const void *s1, const void *s2); @@ -1661,7 +1668,7 @@ verify_select_hyper_contig_dr__run_test(const uint16_t *cube_buf, ** test_select_hyper_contig_dr__run_test(): Test H5S (dataspace) ** selection code with contiguous source and target having ** different ranks but the same shape. We have already -** tested H5S_select_shape_same in isolation, so now we try to do +** tested H5Sselect_shape_same in isolation, so now we try to do ** I/O. ** ****************************************************************/ @@ -1845,11 +1852,11 @@ test_select_hyper_contig_dr__run_test(int test_num, const uint16_t *cube_buf, /* first, verify that we can read from disk correctly using selections - * of different rank that H5S_select_shape_same() views as being of the + * of different rank that H5Sselect_shape_same() views as being of the * same shape. * * Start by reading small_rank-D slice from the on disk large cube, and - * verifying that the data read is correct. Verify that H5S_select_shape_same() + * verifying that the data read is correct. Verify that H5Sselect_shape_same() * returns true on the memory and file selections. */ @@ -1893,12 +1900,11 @@ test_select_hyper_contig_dr__run_test(int test_num, const uint16_t *cube_buf, block_ptr); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* verify that H5S_select_shape_same() reports the two + /* verify that H5Sselect_shape_same() reports the two * selections as having the same shape. */ - check = H5S_select_shape_same_test(small_cube_sid, - file_large_cube_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_sid, file_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Read selection from disk */ ret = H5Dread(large_cube_dataset, @@ -1970,12 +1976,11 @@ test_select_hyper_contig_dr__run_test(int test_num, const uint16_t *cube_buf, CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* verify that H5S_select_shape_same() reports the two + /* verify that H5Sselect_shape_same() reports the two * selections as having the same shape. */ - check = H5S_select_shape_same_test(small_cube_sid, - mem_large_cube_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_sid, mem_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Read selection from disk */ @@ -2037,12 +2042,12 @@ test_select_hyper_contig_dr__run_test(int test_num, const uint16_t *cube_buf, /* now we go in the opposite direction, verifying that we can write * from memory to file using selections of different rank that - * H5S_select_shape_same() views as being of the same shape. + * H5Sselect_shape_same() views as being of the same shape. * * Start by writing small_rank D slices from the in memory large cube, to * the the on disk small cube dataset. After each write, read the small * cube dataset back from disk, and verify that it contains the expected - * data. Verify that H5S_select_shape_same() returns true on the + * data. Verify that H5Sselect_shape_same() returns true on the * memory and file selections. */ @@ -2086,13 +2091,12 @@ test_select_hyper_contig_dr__run_test(int test_num, const uint16_t *cube_buf, CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* verify that H5S_select_shape_same() reports the in + /* verify that H5Sselect_shape_same() reports the in * memory slice through the cube selection and the * on disk full small cube selections as having the same shape. */ - check = H5S_select_shape_same_test(small_cube_sid, - mem_large_cube_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_sid, mem_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* write the slice from the in memory large cube to the on disk small cube */ @@ -2144,7 +2148,7 @@ test_select_hyper_contig_dr__run_test(int test_num, const uint16_t *cube_buf, /* Now write the contents of the in memory small cube to slices of * the on disk cube. After each write, read the on disk cube * into memeory, and verify that it contains the expected - * data. Verify that H5S_select_shape_same() returns true on + * data. Verify that H5Sselect_shape_same() returns true on * the memory and file selections. */ @@ -2196,14 +2200,13 @@ test_select_hyper_contig_dr__run_test(int test_num, const uint16_t *cube_buf, CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* verify that H5S_select_shape_same() reports the in + /* verify that H5Sselect_shape_same() reports the in * memory full selection of the small cube and the * on disk slice through the large cube selection * as having the same shape. */ - check = H5S_select_shape_same_test(small_cube_sid, - file_large_cube_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_sid, file_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* write the cube from memory to the target slice of the disk cube */ @@ -2308,7 +2311,7 @@ test_select_hyper_contig_dr__run_test(int test_num, const uint16_t *cube_buf, ** test_select_hyper_contig_dr(): Test H5S (dataspace) ** selection code with contiguous source and target having ** different ranks but the same shape. We have already -** tested H5S_select_shape_same in isolation, so now we try to do +** tested H5Sselect_shape_same in isolation, so now we try to do ** I/O. ** ****************************************************************/ @@ -2731,7 +2734,7 @@ test_select_hyper_checker_board_dr__verify_data(uint16_t * buf_ptr, ** test_select_hyper_checker_board_dr__run_test(): Test H5S ** (dataspace) selection code with checker board source and ** target selections having different ranks but the same -** shape. We have already tested H5S_select_shape_same in +** shape. We have already tested H5Sselect_shape_same in ** isolation, so now we try to do I/O. ** ****************************************************************/ @@ -2937,11 +2940,11 @@ test_select_hyper_checker_board_dr__run_test(int test_num, const uint16_t *cube_ /* first, verify that we can read from disk correctly using selections - * of different rank that H5S_select_shape_same() views as being of the + * of different rank that H5Sselect_shape_same() views as being of the * same shape. * * Start by reading small_rank-D slice from the on disk large cube, and - * verifying that the data read is correct. Verify that H5S_select_shape_same() + * verifying that the data read is correct. Verify that H5Sselect_shape_same() * returns true on the memory and file selections. * * The first step is to set up the needed checker board selection in the @@ -3003,12 +3006,11 @@ test_select_hyper_checker_board_dr__run_test(int test_num, const uint16_t *cube_ sel_start ); - /* verify that H5S_select_shape_same() reports the two + /* verify that H5Sselect_shape_same() reports the two * selections as having the same shape. */ - check = H5S_select_shape_same_test(mem_small_cube_sid, - file_large_cube_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mem_small_cube_sid, file_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* zero the buffer that we will be using for reading */ HDmemset(small_cube_buf_1, 0, sizeof(*small_cube_buf_1) * small_cube_size); @@ -3110,12 +3112,11 @@ test_select_hyper_checker_board_dr__run_test(int test_num, const uint16_t *cube_ sel_start ); - /* verify that H5S_select_shape_same() reports the two + /* verify that H5Sselect_shape_same() reports the two * selections as having the same shape. */ - check = H5S_select_shape_same_test(file_small_cube_sid, - mem_large_cube_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(file_small_cube_sid, mem_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* zero out the in memory large cube */ @@ -3194,12 +3195,12 @@ test_select_hyper_checker_board_dr__run_test(int test_num, const uint16_t *cube_ /* now we go in the opposite direction, verifying that we can write * from memory to file using selections of different rank that - * H5S_select_shape_same() views as being of the same shape. + * H5Sselect_shape_same() views as being of the same shape. * * Start by writing small_rank D slices from the in memory large cube, to * the the on disk small cube dataset. After each write, read the small * cube dataset back from disk, and verify that it contains the expected - * data. Verify that H5S_select_shape_same() returns true on the + * data. Verify that H5Sselect_shape_same() returns true on the * memory and file selections. */ @@ -3263,12 +3264,11 @@ test_select_hyper_checker_board_dr__run_test(int test_num, const uint16_t *cube_ sel_start ); - /* verify that H5S_select_shape_same() reports the two + /* verify that H5Sselect_shape_same() reports the two * selections as having the same shape. */ - check = H5S_select_shape_same_test(file_small_cube_sid, - mem_large_cube_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(file_small_cube_sid, mem_large_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* write the slice from the in memory large cube to the @@ -3331,7 +3331,7 @@ test_select_hyper_checker_board_dr__run_test(int test_num, const uint16_t *cube_ * small cube to slices of the on disk cube. After each write, * read the on disk large cube * into memeory, and verify that * it contains the expected * data. Verify that - * H5S_select_shape_same() returns true on the memory and file + * H5Sselect_shape_same() returns true on the memory and file * selections. */ @@ -3395,12 +3395,11 @@ test_select_hyper_checker_board_dr__run_test(int test_num, const uint16_t *cube_ sel_start ); - /* verify that H5S_select_shape_same() reports the two + /* verify that H5Sselect_shape_same() reports the two * selections as having the same shape. */ - check = H5S_select_shape_same_test(file_large_cube_sid, - mem_small_cube_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(file_large_cube_sid, mem_small_cube_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* write the checker board selection of the in memory @@ -3536,7 +3535,7 @@ test_select_hyper_checker_board_dr__run_test(int test_num, const uint16_t *cube_ ** test_select_hyper_checker_board_dr(): Test H5S (dataspace) ** selection code with checkerboard source and target having ** different ranks but the same shape. We have already -** tested H5S_select_shape_same in isolation, so now we try to do +** tested H5Sselect_shape_same in isolation, so now we try to do ** I/O. ** ** This is just an initial smoke check, so we will work @@ -4918,12 +4917,11 @@ test_select_hyper_union(void) HDfree(rbuf); } /* test_select_hyper_union() */ -#ifdef NEW_HYPERSLAB_API /**************************************************************** ** ** test_select_hyper_union_stagger(): Test basic H5S (dataspace) selection code. ** Tests unions of staggered hyperslabs. (Uses H5Scombine_hyperslab -** and H5Sselect_select instead of H5Sselect_hyperslab) +** and H5Smodify_select instead of H5Sselect_hyperslab) ** ****************************************************************/ static void @@ -4940,11 +4938,11 @@ test_select_hyper_union_stagger(void) hsize_t count[2]={3,1}; /* 1st Hyperslab size */ hsize_t count2[2]={3,1}; /* 2nd Hyperslab size */ hsize_t count3[2]={2,1}; /* 3rd Hyperslab size */ - hssize_t offset[2]={0,0}; /* 1st Hyperslab offset */ - hssize_t offset2[2]={2,1}; /* 2nd Hyperslab offset */ - hssize_t offset3[2]={4,2}; /* 3rd Hyperslab offset */ + hsize_t start[2]={0,0}; /* 1st Hyperslab offset */ + hsize_t start2[2]={2,1}; /* 2nd Hyperslab offset */ + hsize_t start3[2]={4,2}; /* 3rd Hyperslab offset */ hsize_t count_out[2]={4,2}; /* Hyperslab size in memory */ - hssize_t offset_out[2]={0,3}; /* Hyperslab offset in memory */ + hsize_t start_out[2]={0,3}; /* Hyperslab offset in memory */ int data[6][5]; /* Data to write */ int data_out[7][7]; /* Data read in */ int input_loc[8][2]={{0,0}, @@ -5015,27 +5013,27 @@ test_select_hyper_union_stagger(void) CHECK(dataspace, FAIL, "H5Dget_space"); /* Select the hyperslabs */ - error = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, stride, count, block); + error = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, start, stride, count, block); CHECK(error, FAIL, "H5Sselect_hyperslab"); - tmp_space = H5Scombine_hyperslab(dataspace, H5S_SELECT_OR, offset2, stride, count2, block); + tmp_space = H5Scombine_hyperslab(dataspace, H5S_SELECT_OR, start2, stride, count2, block); CHECK(tmp_space, FAIL, "H5Scombine_hyperslab"); /* Copy the file dataspace and select hyperslab */ tmp2_space = H5Scopy(dataspace); CHECK(tmp2_space, FAIL, "H5Scopy"); - error=H5Sselect_hyperslab(tmp2_space,H5S_SELECT_SET,offset3,stride,count3,block); + error=H5Sselect_hyperslab(tmp2_space, H5S_SELECT_SET, start3, stride, count3, block); CHECK(error, FAIL, "H5Sselect_hyperslab"); /* Combine the copied dataspace with the temporary dataspace */ - error=H5Sselect_select(tmp_space,H5S_SELECT_OR,tmp2_space); - CHECK(error, FAIL, "H5Sselect_select"); + error=H5Smodify_select(tmp_space,H5S_SELECT_OR,tmp2_space); + CHECK(error, FAIL, "H5Smodify_select"); /* Create Memory Dataspace */ memspace=H5Screate_simple(memrank,dimsm,NULL); CHECK(memspace, FAIL, "H5Screate_simple"); /* Select hyperslab in memory */ - error=H5Sselect_hyperslab(memspace,H5S_SELECT_SET,offset_out,stride,count_out,block); + error=H5Sselect_hyperslab(memspace, H5S_SELECT_SET, start_out, stride, count_out, block); CHECK(error, FAIL, "H5Sselect_hyperslab"); /* Read File Dataset */ @@ -5275,7 +5273,109 @@ test_select_hyper_union_3d(void) HDfree(wbuf); HDfree(rbuf); } /* test_select_hyper_union_3d() */ -#endif /* NEW_HYPERSLAB_API */ + +/**************************************************************** +** +** test_select_hyper_valid_combination(): Tests invalid and valid +** combinations of selections on dataspace for H5Scombine_select +** and H5Smodify_select. +** +****************************************************************/ +static void +test_select_hyper_valid_combination(void) +{ + hid_t single_pt_sid; /* Dataspace ID with single point selection */ + hid_t single_hyper_sid; /* Dataspace ID with single block hyperslab selection */ + hid_t regular_hyper_sid; /* Dataspace ID with regular hyperslab selection */ + hid_t non_existent_sid = -1; /* A non-existent space id */ + hid_t tmp_sid; /* Temporary dataspace ID */ + hsize_t dims2D[] = {SPACE9_DIM1, SPACE9_DIM2}; + hsize_t dims3D[] = {SPACE4_DIM1, SPACE4_DIM2, SPACE4_DIM3}; + + hsize_t coord1[1][SPACE2_RANK]; /* Coordinates for single point selection */ + hsize_t start[SPACE4_RANK]; /* Hyperslab start */ + hsize_t stride[SPACE4_RANK]; /* Hyperslab stride */ + hsize_t count[SPACE4_RANK]; /* Hyperslab block count */ + hsize_t block[SPACE4_RANK]; /* Hyperslab block size */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing Selection Combination Validity\n")); + assert(SPACE9_DIM2>=POINT1_NPOINTS); + + /* Create dataspace for single point selection */ + single_pt_sid = H5Screate_simple(SPACE9_RANK, dims2D, NULL); + CHECK(single_pt_sid, FAIL, "H5Screate_simple"); + + /* Select sequence of ten points for multiple point selection */ + coord1[0][0] = 2; coord1[0][1] = 2; + ret = H5Sselect_elements(single_pt_sid, H5S_SELECT_SET, (size_t)1, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Create dataspace for single hyperslab selection */ + single_hyper_sid = H5Screate_simple(SPACE9_RANK, dims2D, NULL); + CHECK(single_hyper_sid, FAIL, "H5Screate_simple"); + + /* Select 10x10 hyperslab for single hyperslab selection */ + start[0]=1; start[1]=1; + stride[0]=1; stride[1]=1; + count[0]=1; count[1]=1; + block[0]=(SPACE9_DIM1-2); block[1]=(SPACE9_DIM2-2); + ret = H5Sselect_hyperslab(single_hyper_sid,H5S_SELECT_SET,start,stride,count,block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for regular hyperslab selection */ + regular_hyper_sid = H5Screate_simple(SPACE4_RANK, dims3D, NULL); + CHECK(regular_hyper_sid, FAIL, "H5Screate_simple"); + + /* Select regular, strided hyperslab selection */ + start[0]=2; start[1]=2; start[2]=2; + stride[0]=2; stride[1]=2; stride[2]=2; + count[0]=5; count[1]=2; count[2]=5; + block[0]=1; block[1]=1; block[2]=1; + ret = H5Sselect_hyperslab(regular_hyper_sid,H5S_SELECT_SET,start,stride,count,block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + + /* Test all the selections created */ + + /* Test the invalid combinations between point and hyperslab */ + tmp_sid = H5Scombine_select(single_pt_sid, H5S_SELECT_AND, single_hyper_sid); + VERIFY(tmp_sid, FAIL, "H5Scombine_select"); + + tmp_sid = H5Smodify_select(single_pt_sid, H5S_SELECT_AND, single_hyper_sid); + VERIFY(tmp_sid, FAIL, "H5Smodify_select"); + + /* Test the invalid combination between two hyperslab but of different dimension size */ + tmp_sid = H5Scombine_select(single_hyper_sid, H5S_SELECT_AND, regular_hyper_sid); + VERIFY(tmp_sid, FAIL, "H5Scombine_select"); + + tmp_sid = H5Smodify_select(single_hyper_sid, H5S_SELECT_AND, regular_hyper_sid); + VERIFY(tmp_sid, FAIL, "H5Smodify_select"); + + /* Test invalid operation inputs to the two functions */ + tmp_sid = H5Scombine_select(single_hyper_sid, H5S_SELECT_SET, single_hyper_sid); + VERIFY(tmp_sid, FAIL, "H5Scombine_select"); + + tmp_sid = H5Smodify_select(single_hyper_sid, H5S_SELECT_SET, single_hyper_sid); + VERIFY(tmp_sid, FAIL, "H5Smodify_select"); + + /* Test inputs in case of non-existent space ids */ + tmp_sid = H5Scombine_select(single_hyper_sid, H5S_SELECT_AND, non_existent_sid); + VERIFY(tmp_sid, FAIL, "H5Scombine_select"); + + tmp_sid = H5Smodify_select(single_hyper_sid, H5S_SELECT_AND, non_existent_sid); + VERIFY(tmp_sid, FAIL, "H5Smodify_select"); + + /* Close dataspaces */ + ret = H5Sclose(single_pt_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(regular_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_select_hyper_valid_combination() */ + /**************************************************************** ** @@ -8100,294 +8200,294 @@ test_shape_same(void) /* Compare "all" selection to all the selections created */ /* Compare against itself */ - check = H5S_select_shape_same_test(all_sid,all_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid ,all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against copy of itself */ - tmp_sid=H5Scopy(all_sid); + tmp_sid = H5Scopy(all_sid); CHECK(tmp_sid, FAIL, "H5Scopy"); - check = H5S_select_shape_same_test(all_sid,tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against "none" selection */ - check = H5S_select_shape_same_test(all_sid, none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against single point selection */ - check = H5S_select_shape_same_test(all_sid, single_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against multiple point selection */ - check = H5S_select_shape_same_test(all_sid, mult_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "plain" single hyperslab selection */ - check = H5S_select_shape_same_test(all_sid, single_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "all" single hyperslab selection */ - check = H5S_select_shape_same_test(all_sid, single_hyper_all_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid, single_hyper_all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against "single point" single hyperslab selection */ - check = H5S_select_shape_same_test(all_sid, single_hyper_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against regular, strided hyperslab selection */ - check = H5S_select_shape_same_test(all_sid, regular_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against irregular hyperslab selection */ - check = H5S_select_shape_same_test(all_sid, irreg_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "no" hyperslab selection */ - check = H5S_select_shape_same_test(all_sid, none_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against scalar "all" hyperslab selection */ - check = H5S_select_shape_same_test(all_sid, scalar_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against scalar "none" hyperslab selection */ - check = H5S_select_shape_same_test(all_sid, scalar_none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(all_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare "none" selection to all the selections created */ /* Compare against itself */ - check = H5S_select_shape_same_test(none_sid, none_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, none_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against copy of itself */ tmp_sid = H5Scopy(none_sid); CHECK(tmp_sid, FAIL, "H5Scopy"); - check = H5S_select_shape_same_test(none_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against "all" selection */ - check = H5S_select_shape_same_test(none_sid, all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against single point selection */ - check = H5S_select_shape_same_test(none_sid, single_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against multiple point selection */ - check = H5S_select_shape_same_test(none_sid, mult_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "plain" single hyperslab selection */ - check = H5S_select_shape_same_test(none_sid, single_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "all" single hyperslab selection */ - check = H5S_select_shape_same_test(none_sid, single_hyper_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "single point" single hyperslab selection */ - check = H5S_select_shape_same_test(none_sid, single_hyper_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against regular, strided hyperslab selection */ - check = H5S_select_shape_same_test(none_sid, regular_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against irregular hyperslab selection */ - check = H5S_select_shape_same_test(none_sid, irreg_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "no" hyperslab selection */ - check = H5S_select_shape_same_test(none_sid, none_hyper_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, none_hyper_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against scalar "all" hyperslab selection */ - check = H5S_select_shape_same_test(none_sid, scalar_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against scalar "none" hyperslab selection */ - check = H5S_select_shape_same_test(none_sid, scalar_none_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(none_sid, scalar_none_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare single point selection to all the selections created */ /* Compare against itself */ - check = H5S_select_shape_same_test(single_pt_sid, single_pt_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, single_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against copy of itself */ tmp_sid = H5Scopy(single_pt_sid); CHECK(tmp_sid, FAIL, "H5Scopy"); - check = H5S_select_shape_same_test(single_pt_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against "all" selection */ - check = H5S_select_shape_same_test(single_pt_sid, all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "none" selection */ - check = H5S_select_shape_same_test(single_pt_sid, none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against multiple point selection */ - check = H5S_select_shape_same_test(single_pt_sid, mult_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "plain" single hyperslab selection */ - check = H5S_select_shape_same_test(single_pt_sid, single_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "all" single hyperslab selection */ - check = H5S_select_shape_same_test(single_pt_sid, single_hyper_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "single point" single hyperslab selection */ - check = H5S_select_shape_same_test(single_pt_sid, single_hyper_pt_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, single_hyper_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against regular, strided hyperslab selection */ - check = H5S_select_shape_same_test(single_pt_sid, regular_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against irregular hyperslab selection */ - check = H5S_select_shape_same_test(single_pt_sid, irreg_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "no" hyperslab selection */ - check=H5S_select_shape_same_test(single_pt_sid, none_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against scalar "all" hyperslab selection */ - check = H5S_select_shape_same_test(single_pt_sid, scalar_all_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, scalar_all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against scalar "none" hyperslab selection */ - check = H5S_select_shape_same_test(single_pt_sid, scalar_none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_pt_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare multiple point selection to all the selections created */ /* Compare against itself */ - check = H5S_select_shape_same_test(mult_pt_sid, mult_pt_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, mult_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against copy of itself */ tmp_sid = H5Scopy(mult_pt_sid); CHECK(tmp_sid, FAIL, "H5Scopy"); - check = H5S_select_shape_same_test(mult_pt_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against "all" selection */ - check = H5S_select_shape_same_test(mult_pt_sid, all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "none" selection */ - check = H5S_select_shape_same_test(mult_pt_sid, none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against single point selection */ - check = H5S_select_shape_same_test(mult_pt_sid, single_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "plain" single hyperslab selection */ - check = H5S_select_shape_same_test(mult_pt_sid, single_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "all" single hyperslab selection */ - check = H5S_select_shape_same_test(mult_pt_sid, single_hyper_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "single point" single hyperslab selection */ - check = H5S_select_shape_same_test(mult_pt_sid, single_hyper_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against regular, strided hyperslab selection */ - check = H5S_select_shape_same_test(mult_pt_sid, regular_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against irregular hyperslab selection */ - check = H5S_select_shape_same_test(mult_pt_sid, irreg_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "no" hyperslab selection */ - check = H5S_select_shape_same_test(mult_pt_sid, none_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against scalar "all" hyperslab selection */ - check = H5S_select_shape_same_test(mult_pt_sid, scalar_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against scalar "none" hyperslab selection */ - check = H5S_select_shape_same_test(mult_pt_sid, scalar_none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(mult_pt_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare single "normal" hyperslab selection to all the selections created */ /* Compare against itself */ - check = H5S_select_shape_same_test(single_hyper_sid, single_hyper_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, single_hyper_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against copy of itself */ tmp_sid = H5Scopy(single_hyper_sid); CHECK(tmp_sid, FAIL, "H5Scopy"); - check = H5S_select_shape_same_test(single_hyper_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against "all" selection */ - check = H5S_select_shape_same_test(single_hyper_sid, all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "none" selection */ - check = H5S_select_shape_same_test(single_hyper_sid, none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against single point selection */ - check = H5S_select_shape_same_test(single_hyper_sid, single_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against multiple point selection */ - check = H5S_select_shape_same_test(single_hyper_sid, mult_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "all" single hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_sid, single_hyper_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "single point" single hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_sid, single_hyper_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against regular, strided hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_sid, regular_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against irregular hyperslab selection */ - check=H5S_select_shape_same_test(single_hyper_sid, irreg_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "no" hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_sid, none_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); #ifdef NOT_YET /* In theory, these two selections are the same shape, but the - * H5S_select_shape_same() routine is just not this sophisticated yet and it + * H5Sselect_shape_same() routine is just not this sophisticated yet and it * would take too much effort to make this work. The worst case is that the * non-optimized chunk mapping routines will be invoked instead of the more * optimized routines, so this only hurts performance, not correctness @@ -8409,8 +8509,8 @@ test_shape_same(void) } /* end for */ /* Compare against hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); @@ -8436,70 +8536,70 @@ test_shape_same(void) } /* end for */ /* Compare against hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against scalar "all" hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_sid, scalar_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against scalar "none" hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_sid, scalar_none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare single "all" hyperslab selection to all the selections created */ /* Compare against itself */ - check = H5S_select_shape_same_test(single_hyper_all_sid, single_hyper_all_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, single_hyper_all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against copy of itself */ tmp_sid = H5Scopy(single_hyper_all_sid); CHECK(tmp_sid, FAIL, "H5Scopy"); - check = H5S_select_shape_same_test(single_hyper_all_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against "all" selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, all_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against "none" selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against single point selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, single_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against multiple point selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, mult_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "plain" single hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, single_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "single point" single hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, single_hyper_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against regular, strided hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, regular_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against irregular hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, irreg_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "no" hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, none_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); #ifdef NOT_YET /* In theory, these two selections are the same shape, but the @@ -8524,8 +8624,8 @@ test_shape_same(void) } /* end for */ /* Compare against hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); @@ -8551,129 +8651,129 @@ test_shape_same(void) } /* end for */ /* Compare against hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against scalar "all" hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, scalar_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against scalar "none" hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_all_sid, scalar_none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_all_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare single "point" hyperslab selection to all the selections created */ /* Compare against itself */ - check = H5S_select_shape_same_test(single_hyper_pt_sid, single_hyper_pt_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, single_hyper_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against copy of itself */ tmp_sid = H5Scopy(single_hyper_pt_sid); CHECK(tmp_sid, FAIL, "H5Scopy"); - check = H5S_select_shape_same_test(single_hyper_pt_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against "all" selection */ - check = H5S_select_shape_same_test(single_hyper_pt_sid, all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "none" selection */ - check = H5S_select_shape_same_test(single_hyper_pt_sid, none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against single point selection */ - check = H5S_select_shape_same_test(single_hyper_pt_sid, single_pt_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, single_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against multiple point selection */ - check = H5S_select_shape_same_test(single_hyper_pt_sid, mult_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "plain" single hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_pt_sid, single_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "all" single hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_pt_sid, single_hyper_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against regular, strided hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_pt_sid, regular_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against irregular hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_pt_sid, irreg_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "no" hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_pt_sid, none_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against scalar "all" hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_pt_sid, scalar_all_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, scalar_all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against scalar "none" hyperslab selection */ - check = H5S_select_shape_same_test(single_hyper_pt_sid, scalar_none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(single_hyper_pt_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare regular, strided hyperslab selection to all the selections created */ /* Compare against itself */ - check = H5S_select_shape_same_test(regular_hyper_sid, regular_hyper_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, regular_hyper_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against copy of itself */ tmp_sid = H5Scopy(regular_hyper_sid); CHECK(tmp_sid, FAIL, "H5Scopy"); - check = H5S_select_shape_same_test(regular_hyper_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against "all" selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "none" selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against single point selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, single_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against multiple point selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, mult_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "plain" single hyperslab selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, single_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "all" single hyperslab selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, single_hyper_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "single point" single hyperslab selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, single_hyper_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against irregular hyperslab selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, irreg_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "no" hyperslab selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, none_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Construct point selection which matches regular, strided hyperslab selection */ /* Create dataspace for point selection */ @@ -8691,8 +8791,8 @@ test_shape_same(void) } /* end for */ /* Compare against hyperslab selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); @@ -8717,8 +8817,8 @@ test_shape_same(void) } /* end for */ /* Compare against hyperslab selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); @@ -8737,70 +8837,70 @@ test_shape_same(void) CHECK(ret, FAIL, "H5Sselect_hyperslab"); /* Compare against hyperslab selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against scalar "all" hyperslab selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, scalar_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against scalar "none" hyperslab selection */ - check = H5S_select_shape_same_test(regular_hyper_sid, scalar_none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(regular_hyper_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare irregular hyperslab selection to all the selections created */ /* Compare against itself */ - check = H5S_select_shape_same_test(irreg_hyper_sid, irreg_hyper_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, irreg_hyper_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against copy of itself */ tmp_sid = H5Scopy(irreg_hyper_sid); CHECK(tmp_sid, FAIL, "H5Scopy"); - check = H5S_select_shape_same_test(irreg_hyper_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against "all" selection */ - check = H5S_select_shape_same_test(irreg_hyper_sid, all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "none" selection */ - check = H5S_select_shape_same_test(irreg_hyper_sid, none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against single point selection */ - check = H5S_select_shape_same_test(irreg_hyper_sid, single_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against multiple point selection */ - check = H5S_select_shape_same_test(irreg_hyper_sid, mult_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "plain" single hyperslab selection */ - check = H5S_select_shape_same_test(irreg_hyper_sid, single_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "all" single hyperslab selection */ - check = H5S_select_shape_same_test(irreg_hyper_sid, single_hyper_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "single point" single hyperslab selection */ - check = H5S_select_shape_same_test(irreg_hyper_sid, single_hyper_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against regular, strided hyperslab selection */ - check = H5S_select_shape_same_test(irreg_hyper_sid, regular_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "no" hyperslab selection */ - check = H5S_select_shape_same_test(irreg_hyper_sid, none_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Construct hyperslab selection which matches irregular hyperslab selection */ /* Create dataspace for hyperslab selection */ @@ -8825,141 +8925,141 @@ test_shape_same(void) } /* end for */ /* Compare against hyperslab selection */ - check = H5S_select_shape_same_test(irreg_hyper_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against scalar "all" hyperslab selection */ - check = H5S_select_shape_same_test(irreg_hyper_sid, scalar_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against scalar "none" hyperslab selection */ - check = H5S_select_shape_same_test(irreg_hyper_sid, scalar_none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(irreg_hyper_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare scalar "all" dataspace with all selections created */ /* Compare against itself */ - check = H5S_select_shape_same_test(scalar_all_sid, scalar_all_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, scalar_all_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against copy of itself */ tmp_sid = H5Scopy(scalar_all_sid); CHECK(tmp_sid, FAIL, "H5Scopy"); - check = H5S_select_shape_same_test(scalar_all_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against "all" selection */ - check = H5S_select_shape_same_test(scalar_all_sid, all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "none" selection */ - check = H5S_select_shape_same_test(scalar_all_sid, none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against single point selection */ - check = H5S_select_shape_same_test(scalar_all_sid, single_pt_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, single_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against multiple point selection */ - check = H5S_select_shape_same_test(scalar_all_sid, mult_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "plain" single hyperslab selection */ - check = H5S_select_shape_same_test(scalar_all_sid, single_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "all" single hyperslab selection */ - check = H5S_select_shape_same_test(scalar_all_sid, single_hyper_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "single point" single hyperslab selection */ - check = H5S_select_shape_same_test(scalar_all_sid, single_hyper_pt_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, single_hyper_pt_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against regular, strided hyperslab selection */ - check = H5S_select_shape_same_test(scalar_all_sid, regular_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against irregular hyperslab selection */ - check = H5S_select_shape_same_test(scalar_all_sid, irreg_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "no" hyperslab selection */ - check = H5S_select_shape_same_test(scalar_all_sid, none_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, none_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against scalar "none" hyperslab selection */ - check = H5S_select_shape_same_test(scalar_all_sid, scalar_none_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_all_sid, scalar_none_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare scalar "none" dataspace with all selections created */ /* Compare against itself */ - check = H5S_select_shape_same_test(scalar_none_sid, scalar_none_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, scalar_none_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against copy of itself */ tmp_sid = H5Scopy(scalar_none_sid); CHECK(tmp_sid, FAIL, "H5Scopy"); - check = H5S_select_shape_same_test(scalar_none_sid, tmp_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, tmp_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); ret = H5Sclose(tmp_sid); CHECK(ret, FAIL, "H5Sclose"); /* Compare against "all" selection */ - check = H5S_select_shape_same_test(scalar_none_sid, all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "none" selection */ - check = H5S_select_shape_same_test(scalar_none_sid, none_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, none_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against single point selection */ - check = H5S_select_shape_same_test(scalar_none_sid, single_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, single_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against multiple point selection */ - check = H5S_select_shape_same_test(scalar_none_sid, mult_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, mult_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "plain" single hyperslab selection */ - check = H5S_select_shape_same_test(scalar_none_sid, single_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, single_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "all" single hyperslab selection */ - check = H5S_select_shape_same_test(scalar_none_sid, single_hyper_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, single_hyper_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "single point" single hyperslab selection */ - check = H5S_select_shape_same_test(scalar_none_sid, single_hyper_pt_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, single_hyper_pt_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against regular, strided hyperslab selection */ - check = H5S_select_shape_same_test(scalar_none_sid, regular_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, regular_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against irregular hyperslab selection */ - check = H5S_select_shape_same_test(scalar_none_sid, irreg_hyper_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, irreg_hyper_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "no" hyperslab selection */ - check = H5S_select_shape_same_test(scalar_none_sid, none_hyper_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, none_hyper_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Compare against scalar "all" hyperslab selection */ - check = H5S_select_shape_same_test(scalar_none_sid, scalar_all_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(scalar_none_sid, scalar_all_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Close dataspaces */ @@ -9002,7 +9102,7 @@ test_shape_same(void) ** xz plane, and three parallel to the yz plane. ** ** Assuming that z is the fastest changing dimension, -** H5S_select_shape_same() should return TRUE when comparing +** H5Sselect_shape_same() should return TRUE when comparing ** the full 2-D space against any hyperslab parallel to the ** yz plane in the 3-D space, and FALSE when comparing the ** full 2-D space against the other two hyperslabs. @@ -9011,7 +9111,7 @@ test_shape_same(void) ** and select a (10 X 10 X 2) hyperslab parallel to the yz ** axis in one of them, and two parallel (10 X 10 X 1) hyper ** slabs parallel to the yz axis in the other. -** H5S_select_shape_same() should return FALSE when comparing +** H5Sselect_shape_same() should return FALSE when comparing ** each to the 2-D selection. ** ****************************************************************/ @@ -9200,42 +9300,42 @@ test_shape_same_dr__smoke_check_1(void) /* setup is done -- run the tests: */ /* Compare against "xy" selection */ - check = H5S_select_shape_same_test(small_cube_xy_slice_0_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xy_slice_0_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_xy_slice_1_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xy_slice_1_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_xy_slice_2_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xy_slice_2_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "xz" selection */ - check = H5S_select_shape_same_test(small_cube_xz_slice_0_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xz_slice_0_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_xz_slice_1_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xz_slice_1_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_xz_slice_2_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xz_slice_2_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "yz" selection */ - check = H5S_select_shape_same_test(small_cube_yz_slice_0_sid, small_square_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_yz_slice_0_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_yz_slice_1_sid, small_square_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_yz_slice_1_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_yz_slice_2_sid, small_square_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_yz_slice_2_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_yz_slice_3_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_yz_slice_3_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_yz_slice_4_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_yz_slice_4_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Close dataspaces */ @@ -9288,15 +9388,15 @@ test_shape_same_dr__smoke_check_1(void) ** a "checker board" hyperslab as follows: ** ** * * - - * * - - * * -** * * - - * * - - * * -** - - * * - - * * - - -** - - * * - - * * - - ** * * - - * * - - * * -** * * - - * * - - * * -** - - * * - - * * - - -** - - * * - - * * - - +** - - * * - - * * - - +** - - * * - - * * - - +** * * - - * * - - * * +** * * - - * * - - * * +** - - * * - - * * - - +** - - * * - - * * - - +** * * - - * * - - * * ** * * - - * * - - * * -** * * - - * * - - * * ** ** where asterisks indicate selected elements, and dashes ** indicate unselected elements. @@ -9308,7 +9408,7 @@ test_shape_same_dr__smoke_check_1(void) ** to the yz plane. ** ** Assuming that z is the fastest changing dimension, -** H5S_select_shape_same() should return TRUE when comparing +** H5Sselect_shape_same() should return TRUE when comparing ** the 2-D space checker board selection against a checker ** board hyperslab parallel to the yz plane in the 3-D ** space, and FALSE when comparing the 2-D checkerboard @@ -9318,7 +9418,7 @@ test_shape_same_dr__smoke_check_1(void) ** Also create an additional 3-D dataspaces (10 X 10 X 10), ** and select a checker board parallel with the yz axis, ** save with some squares being on different planes. -** H5S_select_shape_same() should return FALSE when +** H5Sselect_shape_same() should return FALSE when ** comparing this selection to the 2-D selection. ** ****************************************************************/ @@ -9613,39 +9713,39 @@ test_shape_same_dr__smoke_check_2(void) /* setup is done -- run the tests: */ /* Compare against "xy" selection */ - check = H5S_select_shape_same_test(small_cube_xy_slice_0_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xy_slice_0_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_xy_slice_1_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xy_slice_1_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_xy_slice_2_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xy_slice_2_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "xz" selection */ - check = H5S_select_shape_same_test(small_cube_xz_slice_0_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xz_slice_0_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_xz_slice_1_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xz_slice_1_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_xz_slice_2_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xz_slice_2_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "yz" selection */ - check = H5S_select_shape_same_test(small_cube_yz_slice_0_sid, small_square_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_yz_slice_0_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_yz_slice_1_sid, small_square_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_yz_slice_1_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_yz_slice_2_sid, small_square_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_yz_slice_2_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_yz_slice_3_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_yz_slice_3_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Close dataspaces */ @@ -9719,7 +9819,7 @@ test_shape_same_dr__smoke_check_2(void) ** cases. ** ** Assuming that z is the fastest changing dimension, -** H5S_select_shape_same() should return TRUE when +** H5Sselect_shape_same() should return TRUE when ** comparing the 2-D irregular hyperslab selection ** against the irregular hyperslab selections parallel ** to the yz plane in the 3-D space, and FALSE when @@ -10136,36 +10236,36 @@ test_shape_same_dr__smoke_check_3(void) /* setup is done -- run the tests: */ /* Compare against "xy" selection */ - check = H5S_select_shape_same_test(small_cube_xy_slice_0_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xy_slice_0_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_xy_slice_1_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xy_slice_1_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_xy_slice_2_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xy_slice_2_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "xz" selection */ - check = H5S_select_shape_same_test(small_cube_xz_slice_0_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xz_slice_0_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_xz_slice_1_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xz_slice_1_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_xz_slice_2_sid, small_square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_xz_slice_2_sid, small_square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Compare against "yz" selection */ - check = H5S_select_shape_same_test(small_cube_yz_slice_0_sid, small_square_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_yz_slice_0_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_yz_slice_1_sid, small_square_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_yz_slice_1_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(small_cube_yz_slice_2_sid, small_square_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(small_cube_yz_slice_2_sid, small_square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); /* Close dataspaces */ @@ -10229,7 +10329,7 @@ test_shape_same_dr__smoke_check_3(void) ** And select these entire spaces as well. ** ** Compare the 2-D space against all the other spaces -** with H5S_select_shape_same(). The (1 X 10 X 10) & +** with H5Sselect_shape_same(). The (1 X 10 X 10) & ** (1 X 1 X 10 X 10) should return TRUE. All others ** should return FALSE. ** @@ -10347,39 +10447,39 @@ test_shape_same_dr__smoke_check_4(void) /* setup is done -- run the tests: */ - check = H5S_select_shape_same_test(three_d_space_0_sid, square_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(three_d_space_0_sid, square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(three_d_space_1_sid, square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(three_d_space_1_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(three_d_space_2_sid, square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(three_d_space_2_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(three_d_space_3_sid, square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(three_d_space_3_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(four_d_space_0_sid, square_sid); - VERIFY(check, TRUE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(four_d_space_0_sid, square_sid); + VERIFY(check, TRUE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(four_d_space_1_sid, square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(four_d_space_1_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(four_d_space_2_sid, square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(four_d_space_2_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(four_d_space_3_sid, square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(four_d_space_3_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(four_d_space_4_sid, square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(four_d_space_4_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(four_d_space_5_sid, square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(four_d_space_5_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); - check = H5S_select_shape_same_test(four_d_space_6_sid, square_sid); - VERIFY(check, FALSE, "H5S_select_shape_same_test"); + check = H5Sselect_shape_same(four_d_space_6_sid, square_sid); + VERIFY(check, FALSE, "H5Sselect_shape_same"); /* Close dataspaces */ @@ -10426,10 +10526,10 @@ test_shape_same_dr__smoke_check_4(void) ** ** test_shape_same_dr__full_space_vs_slice(): Tests selection ** of a full n-cube dataspace vs an n-dimensional slice of -** of an m-cube (m > n) in a call to H5S_select_shape_same(). +** of an m-cube (m > n) in a call to H5Sselect_shape_same(). ** Note that this test does not require the n-cube and the ** n-dimensional slice to have the same rank (although -** H5S_select_shape_same() should always return FALSE if +** H5Sselect_shape_same() should always return FALSE if ** they don't). ** ** Per Quincey's suggestion, only test up to 5 dimensional @@ -10541,8 +10641,8 @@ test_shape_same_dr__full_space_vs_slice(int test_num, /* setup is done -- run the test: */ - check = H5S_select_shape_same_test(n_cube_0_sid, n_cube_1_sid); - VERIFY(check, expected_result, "test_shape_same_dr__full_space_vs_slice"); + check = H5Sselect_shape_same(n_cube_0_sid, n_cube_1_sid); + VERIFY(check, expected_result, "H5Sselect_shape_same"); /* Close dataspaces */ @@ -10561,7 +10661,7 @@ test_shape_same_dr__full_space_vs_slice(int test_num, ** Run the test_shape_same_dr__full_space_vs_slice() test ** over a variety of ranks and offsets. ** -** At present, we test H5S_select_shape_same() with +** At present, we test H5Sselect_shape_same() with ** fully selected 1, 2, 3, and 4 cubes as one parameter, and ** 1, 2, 3, and 4 dimensional slices through a n-cube of rank ** no more than 5 (and at least the rank of the slice). @@ -10569,7 +10669,7 @@ test_shape_same_dr__full_space_vs_slice(int test_num, ** sufficient. ** ** All the n-cubes will have lengths of the same size, so -** H5S_select_shape_same() should return true iff: +** H5Sselect_shape_same() should return true iff: ** ** 1) the rank for the fully selected n cube equals the ** number of dimensions selected in the slice through the @@ -10707,11 +10807,11 @@ test_shape_same_dr__run_full_space_vs_slice_tests(void) ** test_shape_same_dr__checkerboard(): Tests selection of a ** "checker board" subset of a full n-cube dataspace vs ** a "checker board" n-dimensional slice of an m-cube (m > n). -** in a call to H5S_select_shape_same(). +** in a call to H5Sselect_shape_same(). ** ** Note that this test does not require the n-cube and the ** n-dimensional slice to have the same rank (although -** H5S_select_shape_same() should always return FALSE if +** H5Sselect_shape_same() should always return FALSE if ** they don't). ** ** Per Quincey's suggestion, only test up to 5 dimensional @@ -11031,8 +11131,8 @@ test_shape_same_dr__checkerboard(int test_num, CHECK(ret, FAIL, "H5Sselect_hyperslab"); /* setup is done -- run the test: */ - check = H5S_select_shape_same_test(n_cube_0_sid, n_cube_1_sid); - VERIFY(check, expected_result, "test_shape_same_dr__checkerboard"); + check = H5Sselect_shape_same(n_cube_0_sid, n_cube_1_sid); + VERIFY(check, expected_result, "H5Sselect_shape_same"); /* Close dataspaces */ @@ -11048,14 +11148,14 @@ test_shape_same_dr__checkerboard(int test_num, ** ** test_shape_same_dr__run_checkerboard_tests(): ** -** In this set of tests, we test H5S_select_shape_same() +** In this set of tests, we test H5Sselect_shape_same() ** with a "checkerboard" selection of 1, 2, 3, and 4 cubes as ** one parameter, and 1, 2, 3, and 4 dimensional checkerboard ** slices through a n-cube of rank no more than 5 (and at ** least the rank of the slice). ** ** All the n-cubes will have lengths of the same size, so -** H5S_select_shape_same() should return true iff: +** H5Sselect_shape_same() should return true iff: ** ** 1) the rank of the n cube equals the number of dimensions ** selected in the checker board slice through the m-cube @@ -11321,11 +11421,11 @@ test_shape_same_dr__run_checkerboard_tests(void) ** Tests selection of an "irregular" subset of a full ** n-cube dataspace vs an identical "irregular" subset ** of an n-dimensional slice of an m-cube (m > n). -** in a call to H5S_select_shape_same(). +** in a call to H5Sselect_shape_same(). ** ** Note that this test does not require the n-cube and the ** n-dimensional slice to have the same rank (although -** H5S_select_shape_same() should always return FALSE if +** H5Sselect_shape_same() should always return FALSE if ** they don't). ** ****************************************************************/ @@ -11575,8 +11675,8 @@ test_shape_same_dr__irregular(int test_num, /* setup is done -- run the test: */ - check = H5S_select_shape_same_test(n_cube_0_sid, n_cube_1_sid); - VERIFY(check, expected_result, "test_shape_same_dr__checkerboard"); + check = H5Sselect_shape_same(n_cube_0_sid, n_cube_1_sid); + VERIFY(check, expected_result, "H5Sselect_shape_same"); /* Close dataspaces */ @@ -11592,7 +11692,7 @@ test_shape_same_dr__irregular(int test_num, ** ** test_shape_same_dr__run_irregular_tests(): ** -** In this set of tests, we test H5S_select_shape_same() +** In this set of tests, we test H5Sselect_shape_same() ** with an "irregular" subselection of 1, 2, 3, and 4 cubes as ** one parameter, and irregular subselections of 1, 2, 3, ** and 4 dimensional slices through a n-cube of rank no more @@ -11601,7 +11701,7 @@ test_shape_same_dr__irregular(int test_num, ** the n-cube and the slice. ** ** All the irregular selections will be identical (modulo rank) -** so H5S_select_shape_same() should return true iff: +** so H5Sselect_shape_same() should return true iff: ** ** 1) the rank of the n cube equals the number of dimensions ** selected in the irregular slice through the m-cube @@ -11849,7 +11949,7 @@ test_space_rebuild(void) hid_t sid_irreg1,sid_irreg2,sid_irreg3,sid_irreg4,sid_irreg5; /* rebuild status state */ - htri_t rebuild_stat; + H5S_diminfo_valid_t rebuild_stat1,rebuild_stat2; htri_t rebuild_check; herr_t ret; @@ -11919,18 +12019,22 @@ test_space_rebuild(void) ret = H5Sselect_hyperslab(sid_reg1,H5S_SELECT_OR,start1,stride1,count1,block1); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = FALSE; - rebuild_stat = H5S__get_rebuild_status_test(sid_reg1); - HDassert(rebuild_stat!=FAIL); - /* In this case, rebuild_stat should be TRUE. */ - if(!rebuild_stat){ + ret = H5S__get_rebuild_status_test(sid_reg1,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 and rebuild_stat2 should be + * H5S_DIMINFO_VALID_YES. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_YES) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } - else { + if(rebuild_stat2 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } + if(ret != FAIL) { /* In this case, rebuild_check should be TRUE. */ - rebuild_check = H5S_select_shape_same_test(sid_reg1,sid_reg_ori1); - CHECK(rebuild_check,FALSE,"H5S_hyper_rebuild"); + rebuild_check = H5Sselect_shape_same(sid_reg1, sid_reg_ori1); + CHECK(rebuild_check, FALSE, "H5Sselect_shape_same"); } /* For irregular hyperslab */ @@ -11951,11 +12055,15 @@ test_space_rebuild(void) ret = H5Sselect_hyperslab(sid_irreg1,H5S_SELECT_OR,start1,stride1,count1,block1); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = TRUE; - rebuild_stat = H5S__get_rebuild_status_test(sid_irreg1); - HDassert(rebuild_stat != FAIL); - /* In this case, rebuild_stat should be FALSE. */ - if(rebuild_stat){ + ret = H5S__get_rebuild_status_test(sid_irreg1,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_IMPOSSIBLE. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } + if(rebuild_stat2 != H5S_DIMINFO_VALID_IMPOSSIBLE) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } @@ -11999,18 +12107,22 @@ test_space_rebuild(void) ret = H5Sselect_hyperslab(sid_reg2,H5S_SELECT_OR,start2,stride2,count2,block2); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = FALSE; - rebuild_stat = H5S__get_rebuild_status_test(sid_reg2); - HDassert(rebuild_stat != FAIL); - /* In this case, rebuild_stat should be TRUE. */ - if(!rebuild_stat){ + ret = H5S__get_rebuild_status_test(sid_reg2,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 and rebuild_stat2 should be + * H5S_DIMINFO_VALID_YES. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_YES) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } - else { + if(rebuild_stat2 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } /* end if */ + if(ret != FAIL) { /* In this case, rebuild_check should be TRUE. */ - rebuild_check = H5S_select_shape_same_test(sid_reg2,sid_reg_ori2); - CHECK(rebuild_check, FALSE, "H5S_hyper_rebuild"); + rebuild_check = H5Sselect_shape_same(sid_reg2, sid_reg_ori2); + CHECK(rebuild_check, FALSE, "H5Sselect_shape_same"); } /* 2-D irregular case */ @@ -12036,11 +12148,15 @@ test_space_rebuild(void) ret = H5Sselect_hyperslab(sid_irreg2,H5S_SELECT_OR,start2,stride2,count2,block2); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = TRUE; - rebuild_stat = H5S__get_rebuild_status_test(sid_irreg2); - HDassert(rebuild_stat != FAIL); - /* In this case, rebuild_stat should be FALSE. */ - if(rebuild_stat){ + ret = H5S__get_rebuild_status_test(sid_irreg2,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_IMPOSSIBLE. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } + if(rebuild_stat2 != H5S_DIMINFO_VALID_IMPOSSIBLE) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } @@ -12089,19 +12205,22 @@ test_space_rebuild(void) ret = H5Sselect_hyperslab(sid_reg3,H5S_SELECT_OR,start3,stride3,count3,block3); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = FALSE; - rebuild_stat = H5S__get_rebuild_status_test(sid_reg3); - assert(rebuild_stat != FAIL); - - /* In this case, rebuild_stat should be TRUE. */ - if(!rebuild_stat){ + ret = H5S__get_rebuild_status_test(sid_reg3,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 and rebuild_stat2 should be + * H5S_DIMINFO_VALID_YES. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_YES) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } - else { + if(rebuild_stat2 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } + if(ret != FAIL) { /* In this case, rebuild_check should be TRUE. */ - rebuild_check = H5S_select_shape_same_test(sid_reg3,sid_reg_ori3); - CHECK(rebuild_check,FALSE,"H5S_hyper_rebuild"); + rebuild_check = H5Sselect_shape_same(sid_reg3, sid_reg_ori3); + CHECK(rebuild_check, FALSE, "H5Sselect_shape_same"); } sid_irreg3 = H5Screate_simple(SPACERE3_RANK,dims3,NULL); @@ -12132,11 +12251,15 @@ test_space_rebuild(void) ret = H5Sselect_hyperslab(sid_irreg3,H5S_SELECT_OR,start3,stride3,count3,block3); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = TRUE; - rebuild_stat = H5S__get_rebuild_status_test(sid_irreg3); - assert(rebuild_stat != FAIL); - /* In this case, rebuild_stat should be FALSE. */ - if(rebuild_stat){ + ret = H5S__get_rebuild_status_test(sid_irreg3,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_IMPOSSIBLE. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } + if(rebuild_stat2 != H5S_DIMINFO_VALID_IMPOSSIBLE) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } @@ -12193,18 +12316,22 @@ test_space_rebuild(void) CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = FALSE; - rebuild_stat = H5S__get_rebuild_status_test(sid_reg4); - assert(rebuild_stat != FAIL); - /* In this case, rebuild_stat should be TRUE. */ - if(!rebuild_stat){ + ret = H5S__get_rebuild_status_test(sid_reg4,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 and rebuild_stat2 should be + * H5S_DIMINFO_VALID_YES. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_YES) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } - else { + if(rebuild_stat2 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } + if(ret != FAIL) { /* In this case, rebuild_check should be TRUE. */ - rebuild_check = H5S_select_shape_same_test(sid_reg4,sid_reg_ori4); - CHECK(rebuild_check,FALSE,"H5S_hyper_rebuild"); + rebuild_check = H5Sselect_shape_same(sid_reg4, sid_reg_ori4); + CHECK(rebuild_check, FALSE, "H5Sselect_shape_same"); } /* Testing irregular selection */ @@ -12246,11 +12373,15 @@ test_space_rebuild(void) ret = H5Sselect_hyperslab(sid_irreg4,H5S_SELECT_OR,start4,stride4,count4,block4); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = TRUE; - rebuild_stat = H5S__get_rebuild_status_test(sid_irreg4); - assert(rebuild_stat != FAIL); - /* In this case, rebuild_stat should be FALSE. */ - if(rebuild_stat){ + ret = H5S__get_rebuild_status_test(sid_irreg4,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_IMPOSSIBLE. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } + if(rebuild_stat2 != H5S_DIMINFO_VALID_IMPOSSIBLE) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } @@ -12311,18 +12442,22 @@ test_space_rebuild(void) CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = FALSE; - rebuild_stat = H5S__get_rebuild_status_test(sid_reg5); - assert(rebuild_stat != FAIL); - /* In this case, rebuild_stat should be TRUE. */ - if(!rebuild_stat){ + ret = H5S__get_rebuild_status_test(sid_reg5,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 and rebuild_stat2 should be + * H5S_DIMINFO_VALID_YES. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_YES) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } - else { + if(rebuild_stat2 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } + if(ret != FAIL) { /* In this case, rebuild_check should be TRUE. */ - rebuild_check = H5S_select_shape_same_test(sid_reg5,sid_reg_ori5); - CHECK(rebuild_check,FALSE,"H5S_hyper_rebuild"); + rebuild_check = H5Sselect_shape_same(sid_reg5, sid_reg_ori5); + CHECK(rebuild_check, FALSE, "H5Sselect_shape_same"); } sid_irreg5 = H5Screate_simple(SPACERE5_RANK,dims5,NULL); @@ -12369,11 +12504,15 @@ test_space_rebuild(void) ret = H5Sselect_hyperslab(sid_irreg5,H5S_SELECT_OR,start5,stride5,count5,block5); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = TRUE; - rebuild_stat = H5S__get_rebuild_status_test(sid_irreg5); - assert(rebuild_stat != FAIL); - /* In this case, rebuild_stat should be FALSE. */ - if(rebuild_stat){ + ret = H5S__get_rebuild_status_test(sid_irreg5,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_IMPOSSIBLE. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } + if(rebuild_stat2 != H5S_DIMINFO_VALID_IMPOSSIBLE) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } @@ -12411,10 +12550,16 @@ test_space_rebuild(void) ret = H5Sselect_hyperslab(sid_spec,H5S_SELECT_SET,start5,stride5,count5,block5); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = FALSE; - rebuild_stat = H5S__get_rebuild_status_test(sid_spec); - /* In this case, rebuild_stat should be TRUE. */ - if(!rebuild_stat){ + + ret = H5S__get_rebuild_status_test(sid_spec,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 and rebuild_stat2 should both be + * H5S_DIMINFO_VALID_YES. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } + if(rebuild_stat2 != H5S_DIMINFO_VALID_YES) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } @@ -12434,11 +12579,15 @@ test_space_rebuild(void) ret = H5Sselect_hyperslab(sid_spec,H5S_SELECT_OR,start5,stride5,count5,block5); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = TRUE; - rebuild_stat = H5S__get_rebuild_status_test(sid_spec); - HDassert(rebuild_stat != FAIL); - /* In this case, rebuild_stat should be FALSE. */ - if(rebuild_stat){ + ret = H5S__get_rebuild_status_test(sid_spec,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_IMPOSSIBLE. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } + if(rebuild_stat2 != H5S_DIMINFO_VALID_IMPOSSIBLE) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } @@ -12458,11 +12607,15 @@ test_space_rebuild(void) ret = H5Sselect_hyperslab(sid_spec,H5S_SELECT_OR,start5,stride5,count5,block5); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - rebuild_stat = FALSE; - rebuild_stat = H5S__get_rebuild_status_test(sid_spec); - HDassert(rebuild_stat!=FAIL); - /* In this case, rebuild_stat should be FALSE. */ - if(!rebuild_stat){ + ret = H5S__get_rebuild_status_test(sid_spec,&rebuild_stat1,&rebuild_stat2); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + /* In this case, rebuild_stat1 should be H5S_DIMINFO_VALID_NO and + * rebuild_stat2 should be H5S_DIMINFO_VALID_YES. */ + if(rebuild_stat1 != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret,FAIL,"H5S_hyper_rebuild"); + } + if(rebuild_stat2 != H5S_DIMINFO_VALID_YES) { ret = FAIL; CHECK(ret,FAIL,"H5S_hyper_rebuild"); } @@ -12500,1114 +12653,2552 @@ test_space_rebuild(void) /**************************************************************** ** -** test_select_hyper_chunk_offset(): Tests selections on dataspace, -** verify that offsets for hyperslab selections are working in -** chunked datasets. +** test_space_update_diminfo(): Tests selection diminfo update +** routine. We will test whether regular selections can be +** quickly updated when the selection is modified. +** ** ****************************************************************/ static void -test_select_hyper_chunk_offset(void) +test_space_update_diminfo(void) { - hid_t fid; /* File ID */ - hid_t sid; /* Dataspace ID */ - hid_t msid; /* Memory dataspace ID */ - hid_t did; /* Dataset ID */ - const hsize_t mem_dims[1] = { SPACE10_DIM1 }; /* Dataspace dimensions for memory */ - const hsize_t dims[1] = { 0 }; /* Dataspace initial dimensions */ - const hsize_t maxdims[1] = { H5S_UNLIMITED }; /* Dataspace mam dims */ - int *wbuf; /* Buffer for writing data */ - int *rbuf; /* Buffer for reading data */ - hid_t dcpl; /* Dataset creation property list ID */ - hsize_t chunks[1]={SPACE10_CHUNK_SIZE }; /* Chunk size */ - hsize_t start[1] = { 0 }; /* The start of the hyperslab */ - hsize_t count[1] = { SPACE10_CHUNK_SIZE }; /* The size of the hyperslab */ - int i,j; /* Local index */ - herr_t ret; /* Generic return value */ - - /* Output message about test being performed */ - MESSAGE(6, ("Testing hyperslab selections using offsets in chunked datasets\n")); + hid_t space_id; /* Dataspace id */ + H5S_diminfo_valid_t diminfo_valid; /* Diminfo status */ + H5S_diminfo_valid_t rebuild_status; /* Diminfo status after rebuid */ + H5S_sel_type sel_type; /* Selection type */ + herr_t ret; /* Return value */ - /* Allocate buffers */ - wbuf = (int *)HDmalloc(sizeof(int) * SPACE10_DIM1); - CHECK_PTR(wbuf, "HDmalloc"); - rbuf = (int *)HDcalloc(sizeof(int), SPACE10_DIM1); - CHECK_PTR(rbuf, "HDcalloc"); + /* dimensions of rank 1 to rank 5 */ + hsize_t dims1[] ={SPACEUD1_DIM0}; + hsize_t dims3[] ={SPACEUD3_DIM0, SPACEUD3_DIM1, SPACEUD3_DIM2}; - /* Initialize the write buffer */ - for(i=0; i=((2*SPACE10_CHUNK_SIZE)/3)) - if(wbuf[i+j]!=rbuf[((SPACE10_DIM1-i)-SPACE10_CHUNK_SIZE)+j]) - TestErrPrintf("Line: %d - Error! i=%d, j=%d, rbuf=%d, wbuf=%d\n",__LINE__,i,j,rbuf[((SPACE10_DIM1-i)-SPACE10_CHUNK_SIZE)+j],wbuf[i+j]); + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Close the memory dataspace */ - ret=H5Sclose (msid); - CHECK(ret, FAIL, "H5Sclose"); + /* + * Test adding overlapping blocks + */ - /* Close the dataset */ - ret=H5Dclose (did); - CHECK(ret, FAIL, "H5Dclose"); + /* Create single block */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Close the file */ - ret=H5Fclose (fid); - CHECK(ret, FAIL, "H5Fclose"); + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Free the buffers */ - HDfree(wbuf); - HDfree(rbuf); -} /* test_select_hyper_chunk_offset() */ + /* Add block completely overlapping first, with OR */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); -/**************************************************************** -** -** test_select_hyper_chunk_offset2(): Tests selections on dataspace, -** another test to verify that offsets for hyperslab selections are -** working in chunked datasets. -** -****************************************************************/ -static void -test_select_hyper_chunk_offset2(void) -{ - hid_t file, dataset; /* handles */ - hid_t dataspace; - hid_t memspace; - hid_t dcpl; /* Dataset creation property list */ - herr_t status; - unsigned data_out[SPACE12_DIM0]; /* output buffer */ - unsigned data_in[SPACE12_CHUNK_DIM0]; /* input buffer */ - hsize_t dims[SPACE12_RANK]={SPACE12_DIM0}; /* Dimension size */ - hsize_t chunk_dims[SPACE12_RANK]={SPACE12_CHUNK_DIM0}; /* Chunk size */ - hsize_t start[SPACE12_RANK]; /* Start of hyperslab */ - hsize_t count[SPACE12_RANK]; /* Size of hyperslab */ - hssize_t offset[SPACE12_RANK]; /* hyperslab offset in the file */ - unsigned u, v; /* Local index variables */ + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Output message about test being performed */ - MESSAGE(6, ("Testing more hyperslab selections using offsets in chunked datasets\n")); + /* Add block parially overlapping first, with OR */ + start1[0] = 4; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Initialize data to write out */ - for (u = 0; u < SPACE12_DIM0; u++) - data_out[u] = u; + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Create the file */ - file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); - CHECK(file, FAIL, "H5Fcreate"); + /* Add block completely enclosing current, with OR */ + start1[0] = 2; + count1[0] = 1; + block1[0] = 5; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Create dataspace */ - dataspace = H5Screate_simple(SPACE12_RANK, dims, NULL); - CHECK(dataspace, FAIL, "H5Screate_simple"); + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Create dataset creation property list */ - dcpl = H5Pcreate(H5P_DATASET_CREATE); - CHECK(dcpl, FAIL, "H5Pcreate"); + /* Add block completely enclosed by current, with OR */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Set chunk sizes */ - status = H5Pset_chunk(dcpl, SPACE12_RANK, chunk_dims); - CHECK(status, FAIL, "H5Pset_chunk"); + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Create dataset */ - dataset = H5Dcreate2(file, DATASETNAME, H5T_NATIVE_UINT, dataspace, H5P_DEFAULT, dcpl, H5P_DEFAULT); - CHECK(dataset, FAIL, "H5Dcreate2"); + /* Add equally sized block parially overlapping current, with XOR */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 5; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_XOR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Close DCPL */ - status = H5Pclose(dcpl); - CHECK(status, FAIL, "H5Pclose"); + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Write out entire dataset */ - status = H5Dwrite(dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_out); - CHECK(status, FAIL, "H5Dclose"); + /* Fill in hole in block */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 4; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Create memory dataspace (same size as a chunk) */ - memspace = H5Screate_simple(SPACE12_RANK, chunk_dims, NULL); - CHECK(dataspace, FAIL, "H5Screate_simple"); + /* diminfo_valid should be NO, after rebuild it should be YES */ + ret = H5S__get_rebuild_status_test(space_id, &diminfo_valid, + &rebuild_status); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + if(rebuild_status != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } /* end if */ - /* - * Define hyperslab in the file dataspace. - */ - start[0] = 0; - count[0] = SPACE12_CHUNK_DIM0; - status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, start, NULL, count, NULL); - CHECK(status, FAIL, "H5Sselect_hyperslab"); + /* Add differently sized block parially overlapping current, with XOR */ + start1[0] = 4; + count1[0] = 1; + block1[0] = 5; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_XOR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Loop through retrieving data from file, checking it against data written */ - for(u = 0; u < SPACE12_DIM0; u += SPACE12_CHUNK_DIM0) { - /* Set the offset of the file selection */ - offset[0] = u; - status = H5Soffset_simple(dataspace, offset); - CHECK(status, FAIL, "H5Soffset_simple"); + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Read in buffer of data */ - status = H5Dread(dataset, H5T_NATIVE_UINT, memspace, dataspace, - H5P_DEFAULT, data_in); - CHECK(status, FAIL, "H5Dread"); + /* Fill in hole in block */ + start1[0] = 4; + count1[0] = 1; + block1[0] = 4; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Check data read in */ - for(v = 0; v < SPACE12_CHUNK_DIM0; v++) - if(data_out[u + v] != data_in[v]) - TestErrPrintf("Error! data_out[%u]=%u, data_in[%u]=%u\n",(unsigned)(u + v), data_out[u + v], v, data_in[v]); - } /* end for */ + /* diminfo_valid should be NO, after rebuild it should be YES */ + ret = H5S__get_rebuild_status_test(space_id, &diminfo_valid, + &rebuild_status); + CHECK(ret, FAIL, "H5S__get_rebuild_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + if(rebuild_status != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_rebuild"); + } /* end if */ - status = H5Dclose(dataset); - CHECK(status, FAIL, "H5Dclose"); + /* Add block completely overlapping current, with XOR */ + start1[0] = 2; + count1[0] = 1; + block1[0] = 7; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_XOR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - status = H5Sclose(dataspace); - CHECK(status, FAIL, "H5Sclose"); + sel_type = H5Sget_select_type(space_id); + VERIFY(sel_type, H5S_SEL_NONE, "H5Sget_select_type"); - status = H5Sclose(memspace); - CHECK(status, FAIL, "H5Sclose"); + /* + * Test various conditions that break the fast algorithm + */ - status = H5Fclose(file); - CHECK(status, FAIL, "H5Fclose"); -} /* test_select_hyper_chunk_offset2() */ + /* Create multiple blocks */ + start1[0] = 3; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); -/**************************************************************** -** -** test_select_bounds(): Tests selection bounds on dataspaces, -** both with and without offsets. -** -****************************************************************/ -static void -test_select_bounds(void) -{ - hid_t sid; /* Dataspace ID */ - const hsize_t dims[SPACE11_RANK] = {SPACE11_DIM1, SPACE11_DIM2}; /* Dataspace dimensions */ - hsize_t coord[SPACE11_NPOINTS][SPACE11_RANK]; /* Coordinates for point selection */ - hsize_t start[SPACE11_RANK]; /* The start of the hyperslab */ - hsize_t stride[SPACE11_RANK]; /* The stride between block starts for the hyperslab */ - hsize_t count[SPACE11_RANK]; /* The number of blocks for the hyperslab */ - hsize_t block[SPACE11_RANK]; /* The size of each block for the hyperslab */ - hssize_t offset[SPACE11_RANK]; /* Offset amount for selection */ - hsize_t low_bounds[SPACE11_RANK]; /* The low bounds for the selection */ - hsize_t high_bounds[SPACE11_RANK]; /* The high bounds for the selection */ - herr_t ret; /* Generic return value */ + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Output message about test being performed */ - MESSAGE(6, ("Testing selection bounds\n")); + /* Create single block with start out of phase */ + start1[0] = 8; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Create dataspace */ - sid = H5Screate_simple (SPACE11_RANK, dims, NULL); - CHECK(sid, FAIL, "H5Screate_simple"); + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Get bounds for 'all' selection */ - ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); - CHECK(ret, FAIL, "H5Sget_select_bounds"); - VERIFY(low_bounds[0], 0, "H5Sget_select_bounds"); - VERIFY(low_bounds[1], 0, "H5Sget_select_bounds"); - VERIFY(high_bounds[0], SPACE11_DIM1 - 1, "H5Sget_select_bounds"); - VERIFY(high_bounds[1], SPACE11_DIM2 - 1, "H5Sget_select_bounds"); + /* Create multiple blocks */ + start1[0] = 3; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Set offset for selection */ - offset[0] = 1; offset[1] = 1; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Get bounds for 'all' selection with offset (which should be ignored) */ - ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); - CHECK(ret, FAIL, "H5Sget_select_bounds"); - VERIFY(low_bounds[0], 0, "H5Sget_select_bounds"); - VERIFY(low_bounds[1], 0, "H5Sget_select_bounds"); - VERIFY(high_bounds[0], SPACE11_DIM1 - 1, "H5Sget_select_bounds"); - VERIFY(high_bounds[1], SPACE11_DIM2 - 1, "H5Sget_select_bounds"); + /* Create multiple blocks with start out of phase */ + start1[0] = 8; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Reset offset for selection */ - offset[0] = 0; offset[1] = 0; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Set 'none' selection */ - ret = H5Sselect_none(sid); - CHECK(ret, FAIL, "H5Sselect_none"); + /* Create multiple blocks */ + start1[0] = 3; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Get bounds for 'none' selection */ - H5E_BEGIN_TRY { - ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); - } H5E_END_TRY; - VERIFY(ret, FAIL, "H5Sget_select_bo unds"); + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Set point selection */ - coord[0][0] = 3; coord[0][1] = 3; - coord[1][0] = 3; coord[1][1] = 96; - coord[2][0] = 96; coord[2][1] = 3; - coord[3][0] = 96; coord[3][1] = 96; - ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)SPACE11_NPOINTS, (const hsize_t *)coord); - CHECK(ret, FAIL, "H5Sselect_elements"); + /* Create multiple blocks with wrong stride */ + start1[0] = 9; + stride1[0] = 4; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Get bounds for point selection */ - ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); - CHECK(ret, FAIL, "H5Sget_select_bounds"); - VERIFY(low_bounds[0], 3, "H5Sget_select_bounds"); - VERIFY(low_bounds[1], 3, "H5Sget_select_bounds"); - VERIFY(high_bounds[0], SPACE11_DIM1 - 4, "H5Sget_select_bounds"); - VERIFY(high_bounds[1], SPACE11_DIM2 - 4, "H5Sget_select_bounds"); + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Set bad offset for selection */ - offset[0] = 5; offset[1] = -5; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + /* Create single block */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Get bounds for hyperslab selection with negative offset */ - H5E_BEGIN_TRY { - ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); - } H5E_END_TRY; - VERIFY(ret, FAIL, "H5Sget_select_bounds"); + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Set valid offset for selection */ - offset[0] = 2; offset[1] = -2; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + /* Create single block with wrong size */ + start1[0] = 6; + count1[0] = 1; + block1[0] = 1; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Get bounds for point selection with offset */ - ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); - CHECK(ret, FAIL, "H5Sget_select_bounds"); - VERIFY(low_bounds[0], 5, "H5Sget_select_bounds"); - VERIFY(low_bounds[1], 1, "H5Sget_select_bounds"); - VERIFY(high_bounds[0], SPACE11_DIM1 - 2, "H5Sget_select_bounds"); - VERIFY(high_bounds[1], SPACE11_DIM2 - 6, "H5Sget_select_bounds"); + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Reset offset for selection */ - offset[0] = 0; offset[1] = 0; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + /* Create single block */ + start1[0] = 3; + count1[0] = 1; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Set "regular" hyperslab selection */ - start[0] = 2; start[1] = 2; - stride[0] = 10; stride[1] = 10; - count[0] = 4; count[1] = 4; - block[0] = 5; block[1] = 5; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + + /* Create multiple blocks with wrong size */ + start1[0] = 6; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 1; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, stride1, count1, block1); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Get bounds for hyperslab selection */ - ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); - CHECK(ret, FAIL, "H5Sget_select_bounds"); - VERIFY(low_bounds[0], 2, "H5Sget_select_bounds"); - VERIFY(low_bounds[1], 2, "H5Sget_select_bounds"); - VERIFY(high_bounds[0], 36, "H5Sget_select_bounds"); - VERIFY(high_bounds[1], 36, "H5Sget_select_bounds"); + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Set bad offset for selection */ - offset[0] = 5; offset[1] = -5; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + /* Create multiple blocks */ + start1[0] = 3; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Get bounds for hyperslab selection with negative offset */ - H5E_BEGIN_TRY { - ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); - } H5E_END_TRY; - VERIFY(ret, FAIL, "H5Sget_select_bounds"); + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Set valid offset for selection */ - offset[0] = 5; offset[1] = -2; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + /* Create single block with wrong size */ + start1[0] = 9; + count1[0] = 1; + block1[0] = 1; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, NULL, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Get bounds for hyperslab selection with offset */ - ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); - CHECK(ret, FAIL, "H5Sget_select_bounds"); - VERIFY(low_bounds[0], 7, "H5Sget_select_bounds"); - VERIFY(low_bounds[1], 0, "H5Sget_select_bounds"); - VERIFY(high_bounds[0], 41, "H5Sget_select_bounds"); - VERIFY(high_bounds[1], 34, "H5Sget_select_bounds"); + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Reset offset for selection */ - offset[0] = 0; offset[1] = 0; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + /* Create multiple blocks */ + start1[0] = 3; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start1, stride1, count1, block1); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Make "irregular" hyperslab selection */ - start[0] = 20; start[1] = 20; - stride[0] = 20; stride[1] = 20; - count[0] = 2; count[1] = 2; - block[0] = 10; block[1] = 10; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, stride, count, block); + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + + /* Create multiple blocks with wrong size */ + start1[0] = 9; + stride1[0] = 3; + count1[0] = 2; + block1[0] = 1; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start1, stride1, count1, block1); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Get bounds for hyperslab selection */ - ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); - CHECK(ret, FAIL, "H5Sget_select_bounds"); - VERIFY(low_bounds[0], 2, "H5Sget_select_bounds"); - VERIFY(low_bounds[1], 2, "H5Sget_select_bounds"); - VERIFY(high_bounds[0], 49, "H5Sget_select_bounds"); - VERIFY(high_bounds[1], 49, "H5Sget_select_bounds"); + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ - /* Set bad offset for selection */ - offset[0] = 5; offset[1] = -5; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + ret = H5Sclose(space_id); + CHECK(ret, FAIL, "H5Sclose"); - /* Get bounds for hyperslab selection with negative offset */ - H5E_BEGIN_TRY { - ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); - } H5E_END_TRY; - VERIFY(ret, FAIL, "H5Sget_select_bounds"); - /* Set valid offset for selection */ - offset[0] = 5; offset[1] = -2; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + MESSAGE(7, ("Testing functionality to update 3-D hyperslab dimension info\n")); - /* Get bounds for hyperslab selection with offset */ - ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); - CHECK(ret, FAIL, "H5Sget_select_bounds"); - VERIFY(low_bounds[0], 7, "H5Sget_select_bounds"); - VERIFY(low_bounds[1], 0, "H5Sget_select_bounds"); - VERIFY(high_bounds[0], 54, "H5Sget_select_bounds"); - VERIFY(high_bounds[1], 47, "H5Sget_select_bounds"); + /* Create 3-D dataspace */ + space_id = H5Screate_simple(3, dims3, NULL); - /* Reset offset for selection */ - offset[0] = 0; offset[1] = 0; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + /* Create multiple blocks */ + start3[0] = 0; + start3[1] = 1; + start3[2] = 2; + stride3[0] = 2; + stride3[1] = 3; + stride3[2] = 4; + count3[0] = 4; + count3[1] = 3; + count3[2] = 2; + block3[0] = 1; + block3[1] = 2; + block3[2] = 3; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Close the dataspace */ - ret = H5Sclose(sid); + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + + /* Add blocks with same values in all dimensions */ + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + + /* Add blocks with same values in two dimensions */ + start3[0] = 8; + stride3[0] = 1; + count3[0] = 1; + block3[0] = 1; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + + /* Create multiple blocks */ + start3[0] = 0; + start3[1] = 1; + start3[2] = 2; + stride3[0] = 2; + stride3[1] = 3; + stride3[2] = 4; + count3[0] = 4; + count3[1] = 3; + count3[2] = 2; + block3[0] = 1; + block3[1] = 2; + block3[2] = 3; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + + /* Add blocks with same values in one dimension */ + start3[0] = 8; + start3[1] = 10; + stride3[0] = 1; + stride3[1] = 1; + count3[0] = 1; + count3[1] = 1; + block3[0] = 1; + block3[1] = 2; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + + /* Create multiple blocks */ + start3[0] = 0; + start3[1] = 1; + start3[2] = 2; + stride3[0] = 2; + stride3[1] = 3; + stride3[2] = 4; + count3[0] = 4; + count3[1] = 3; + count3[2] = 2; + block3[0] = 1; + block3[1] = 2; + block3[2] = 3; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_SET, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* diminfo_valid should be YES */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_YES) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + + /* Add blocks with same values in no dimensions */ + start3[0] = 8; + start3[1] = 10; + start3[2] = 10; + stride3[0] = 1; + stride3[1] = 1; + stride3[2] = 1; + count3[0] = 1; + count3[1] = 1; + count3[2] = 1; + block3[0] = 1; + block3[1] = 2; + block3[2] = 3; + ret = H5Sselect_hyperslab(space_id, H5S_SELECT_OR, start3, stride3, count3, block3); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* diminfo_valid should be NO */ + ret = H5S__get_diminfo_status_test(space_id, &diminfo_valid); + CHECK(ret, FAIL, "H5S__get_diminfo_status_test"); + if(diminfo_valid != H5S_DIMINFO_VALID_NO) { + ret = FAIL; + CHECK(ret, FAIL, "H5S_hyper_update_diminfo"); + } /* end if */ + + ret = H5Sclose(space_id); CHECK(ret, FAIL, "H5Sclose"); -} /* test_select_bounds() */ +} /* end test_space_update_diminfo() */ /**************************************************************** ** -** test_hyper_regular(): Tests query operations on regular hyperslabs +** test_select_hyper_chunk_offset(): Tests selections on dataspace, +** verify that offsets for hyperslab selections are working in +** chunked datasets. ** ****************************************************************/ static void -test_hyper_regular(void) +test_select_hyper_chunk_offset(void) { + hid_t fid; /* File ID */ hid_t sid; /* Dataspace ID */ - const hsize_t dims[SPACE13_RANK] = {SPACE13_DIM1, SPACE13_DIM2, SPACE13_DIM3}; /* Dataspace dimensions */ - hsize_t coord[SPACE13_NPOINTS][SPACE13_RANK]; /* Coordinates for point selection */ - hsize_t start[SPACE13_RANK]; /* The start of the hyperslab */ - hsize_t stride[SPACE13_RANK]; /* The stride between block starts for the hyperslab */ - hsize_t count[SPACE13_RANK]; /* The number of blocks for the hyperslab */ - hsize_t block[SPACE13_RANK]; /* The size of each block for the hyperslab */ - hsize_t t_start[SPACE13_RANK]; /* Temporary start of the hyperslab */ - hsize_t t_count[SPACE13_RANK]; /* Temporary number of blocks for the hyperslab */ - hsize_t q_start[SPACE13_RANK]; /* The queried start of the hyperslab */ - hsize_t q_stride[SPACE13_RANK]; /* The queried stride between block starts for the hyperslab */ - hsize_t q_count[SPACE13_RANK]; /* The queried number of blocks for the hyperslab */ - hsize_t q_block[SPACE13_RANK]; /* The queried size of each block for the hyperslab */ - htri_t is_regular; /* Whether a hyperslab selection is regular */ - unsigned u; /* Local index variable */ + hid_t msid; /* Memory dataspace ID */ + hid_t did; /* Dataset ID */ + const hsize_t mem_dims[1] = { SPACE10_DIM1 }; /* Dataspace dimensions for memory */ + const hsize_t dims[1] = { 0 }; /* Dataspace initial dimensions */ + const hsize_t maxdims[1] = { H5S_UNLIMITED }; /* Dataspace mam dims */ + int *wbuf; /* Buffer for writing data */ + int *rbuf; /* Buffer for reading data */ + hid_t dcpl; /* Dataset creation property list ID */ + hsize_t chunks[1]={SPACE10_CHUNK_SIZE }; /* Chunk size */ + hsize_t start[1] = { 0 }; /* The start of the hyperslab */ + hsize_t count[1] = { SPACE10_CHUNK_SIZE }; /* The size of the hyperslab */ + int i,j; /* Local index */ herr_t ret; /* Generic return value */ /* Output message about test being performed */ - MESSAGE(6, ("Testing queries on regular hyperslabs\n")); + MESSAGE(6, ("Testing hyperslab selections using offsets in chunked datasets\n")); - /* Create dataspace */ - sid = H5Screate_simple(SPACE13_RANK, dims, NULL); + /* Allocate buffers */ + wbuf = (int *)HDmalloc(sizeof(int) * SPACE10_DIM1); + CHECK_PTR(wbuf, "HDmalloc"); + rbuf = (int *)HDcalloc(sizeof(int), SPACE10_DIM1); + CHECK_PTR(rbuf, "HDcalloc"); + + /* Initialize the write buffer */ + for(i=0; i=((2*SPACE10_CHUNK_SIZE)/3)) + if(wbuf[i+j]!=rbuf[((SPACE10_DIM1-i)-SPACE10_CHUNK_SIZE)+j]) + TestErrPrintf("Line: %d - Error! i=%d, j=%d, rbuf=%d, wbuf=%d\n",__LINE__,i,j,rbuf[((SPACE10_DIM1-i)-SPACE10_CHUNK_SIZE)+j],wbuf[i+j]); + + /* Close the memory dataspace */ + ret=H5Sclose (msid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Close the dataset */ + ret=H5Dclose (did); + CHECK(ret, FAIL, "H5Dclose"); + + /* Close the file */ + ret=H5Fclose (fid); + CHECK(ret, FAIL, "H5Fclose"); + + /* Free the buffers */ + HDfree(wbuf); + HDfree(rbuf); +} /* test_select_hyper_chunk_offset() */ + +/**************************************************************** +** +** test_select_hyper_chunk_offset2(): Tests selections on dataspace, +** another test to verify that offsets for hyperslab selections are +** working in chunked datasets. +** +****************************************************************/ +static void +test_select_hyper_chunk_offset2(void) +{ + hid_t file, dataset; /* handles */ + hid_t dataspace; + hid_t memspace; + hid_t dcpl; /* Dataset creation property list */ + herr_t status; + unsigned data_out[SPACE12_DIM0]; /* output buffer */ + unsigned data_in[SPACE12_CHUNK_DIM0]; /* input buffer */ + hsize_t dims[SPACE12_RANK]={SPACE12_DIM0}; /* Dimension size */ + hsize_t chunk_dims[SPACE12_RANK]={SPACE12_CHUNK_DIM0}; /* Chunk size */ + hsize_t start[SPACE12_RANK]; /* Start of hyperslab */ + hsize_t count[SPACE12_RANK]; /* Size of hyperslab */ + hssize_t offset[SPACE12_RANK]; /* hyperslab offset in the file */ + unsigned u, v; /* Local index variables */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing more hyperslab selections using offsets in chunked datasets\n")); + + /* Initialize data to write out */ + for (u = 0; u < SPACE12_DIM0; u++) + data_out[u] = u; + + /* Create the file */ + file = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(file, FAIL, "H5Fcreate"); + + /* Create dataspace */ + dataspace = H5Screate_simple(SPACE12_RANK, dims, NULL); + CHECK(dataspace, FAIL, "H5Screate_simple"); + + /* Create dataset creation property list */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, FAIL, "H5Pcreate"); + + /* Set chunk sizes */ + status = H5Pset_chunk(dcpl, SPACE12_RANK, chunk_dims); + CHECK(status, FAIL, "H5Pset_chunk"); + + /* Create dataset */ + dataset = H5Dcreate2(file, DATASETNAME, H5T_NATIVE_UINT, dataspace, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(dataset, FAIL, "H5Dcreate2"); + + /* Close DCPL */ + status = H5Pclose(dcpl); + CHECK(status, FAIL, "H5Pclose"); + + /* Write out entire dataset */ + status = H5Dwrite(dataset, H5T_NATIVE_UINT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_out); + CHECK(status, FAIL, "H5Dclose"); + + /* Create memory dataspace (same size as a chunk) */ + memspace = H5Screate_simple(SPACE12_RANK, chunk_dims, NULL); + CHECK(dataspace, FAIL, "H5Screate_simple"); + + /* + * Define hyperslab in the file dataspace. + */ + start[0] = 0; + count[0] = SPACE12_CHUNK_DIM0; + status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, start, NULL, count, NULL); + CHECK(status, FAIL, "H5Sselect_hyperslab"); + + /* Loop through retrieving data from file, checking it against data written */ + for(u = 0; u < SPACE12_DIM0; u += SPACE12_CHUNK_DIM0) { + /* Set the offset of the file selection */ + offset[0] = u; + status = H5Soffset_simple(dataspace, offset); + CHECK(status, FAIL, "H5Soffset_simple"); + + /* Read in buffer of data */ + status = H5Dread(dataset, H5T_NATIVE_UINT, memspace, dataspace, + H5P_DEFAULT, data_in); + CHECK(status, FAIL, "H5Dread"); + + /* Check data read in */ + for(v = 0; v < SPACE12_CHUNK_DIM0; v++) + if(data_out[u + v] != data_in[v]) + TestErrPrintf("Error! data_out[%u]=%u, data_in[%u]=%u\n",(unsigned)(u + v), data_out[u + v], v, data_in[v]); + } /* end for */ + + status = H5Dclose(dataset); + CHECK(status, FAIL, "H5Dclose"); + + status = H5Sclose(dataspace); + CHECK(status, FAIL, "H5Sclose"); + + status = H5Sclose(memspace); + CHECK(status, FAIL, "H5Sclose"); + + status = H5Fclose(file); + CHECK(status, FAIL, "H5Fclose"); +} /* test_select_hyper_chunk_offset2() */ + +/**************************************************************** +** +** test_select_bounds(): Tests selection bounds on dataspaces, +** both with and without offsets. +** +****************************************************************/ +static void +test_select_bounds(void) +{ + hid_t sid; /* Dataspace ID */ + const hsize_t dims[SPACE11_RANK] = {SPACE11_DIM1, SPACE11_DIM2}; /* Dataspace dimensions */ + hsize_t coord[SPACE11_NPOINTS][SPACE11_RANK]; /* Coordinates for point selection */ + hsize_t start[SPACE11_RANK]; /* The start of the hyperslab */ + hsize_t stride[SPACE11_RANK]; /* The stride between block starts for the hyperslab */ + hsize_t count[SPACE11_RANK]; /* The number of blocks for the hyperslab */ + hsize_t block[SPACE11_RANK]; /* The size of each block for the hyperslab */ + hssize_t offset[SPACE11_RANK]; /* Offset amount for selection */ + hsize_t low_bounds[SPACE11_RANK]; /* The low bounds for the selection */ + hsize_t high_bounds[SPACE11_RANK]; /* The high bounds for the selection */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing selection bounds\n")); + + /* Create dataspace */ + sid = H5Screate_simple (SPACE11_RANK, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Get bounds for 'all' selection */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 0, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 0, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], SPACE11_DIM1 - 1, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], SPACE11_DIM2 - 1, "H5Sget_select_bounds"); + + /* Set offset for selection */ + offset[0] = 1; offset[1] = 1; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for 'all' selection with offset (which should be ignored) */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 0, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 0, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], SPACE11_DIM1 - 1, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], SPACE11_DIM2 - 1, "H5Sget_select_bounds"); + + /* Reset offset for selection */ + offset[0] = 0; offset[1] = 0; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Set 'none' selection */ + ret = H5Sselect_none(sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Get bounds for 'none' selection */ + H5E_BEGIN_TRY { + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + } H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_select_bo unds"); + + /* Set point selection */ + coord[0][0] = 3; coord[0][1] = 3; + coord[1][0] = 3; coord[1][1] = 96; + coord[2][0] = 96; coord[2][1] = 3; + coord[3][0] = 96; coord[3][1] = 96; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)SPACE11_NPOINTS, (const hsize_t *)coord); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Get bounds for point selection */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 3, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 3, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], SPACE11_DIM1 - 4, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], SPACE11_DIM2 - 4, "H5Sget_select_bounds"); + + /* Set bad offset for selection */ + offset[0] = 5; offset[1] = -5; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for hyperslab selection with negative offset */ + H5E_BEGIN_TRY { + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + } H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_select_bounds"); + + /* Set valid offset for selection */ + offset[0] = 2; offset[1] = -2; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for point selection with offset */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 5, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 1, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], SPACE11_DIM1 - 2, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], SPACE11_DIM2 - 6, "H5Sget_select_bounds"); + + /* Reset offset for selection */ + offset[0] = 0; offset[1] = 0; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Set "regular" hyperslab selection */ + start[0] = 2; start[1] = 2; + stride[0] = 10; stride[1] = 10; + count[0] = 4; count[1] = 4; + block[0] = 5; block[1] = 5; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Get bounds for hyperslab selection */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 2, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 2, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], 36, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], 36, "H5Sget_select_bounds"); + + /* Set bad offset for selection */ + offset[0] = 5; offset[1] = -5; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for hyperslab selection with negative offset */ + H5E_BEGIN_TRY { + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + } H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_select_bounds"); + + /* Set valid offset for selection */ + offset[0] = 5; offset[1] = -2; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for hyperslab selection with offset */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 7, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 0, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], 41, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], 34, "H5Sget_select_bounds"); + + /* Reset offset for selection */ + offset[0] = 0; offset[1] = 0; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Make "irregular" hyperslab selection */ + start[0] = 20; start[1] = 20; + stride[0] = 20; stride[1] = 20; + count[0] = 2; count[1] = 2; + block[0] = 10; block[1] = 10; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Get bounds for hyperslab selection */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 2, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 2, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], 49, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], 49, "H5Sget_select_bounds"); + + /* Set bad offset for selection */ + offset[0] = 5; offset[1] = -5; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for hyperslab selection with negative offset */ + H5E_BEGIN_TRY { + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + } H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_select_bounds"); + + /* Set valid offset for selection */ + offset[0] = 5; offset[1] = -2; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Get bounds for hyperslab selection with offset */ + ret = H5Sget_select_bounds(sid, low_bounds, high_bounds); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(low_bounds[0], 7, "H5Sget_select_bounds"); + VERIFY(low_bounds[1], 0, "H5Sget_select_bounds"); + VERIFY(high_bounds[0], 54, "H5Sget_select_bounds"); + VERIFY(high_bounds[1], 47, "H5Sget_select_bounds"); + + /* Reset offset for selection */ + offset[0] = 0; offset[1] = 0; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_select_bounds() */ + + +/**************************************************************** +** +** test_hyper_regular(): Tests query operations on regular hyperslabs +** +****************************************************************/ +static void +test_hyper_regular(void) +{ + hid_t sid; /* Dataspace ID */ + const hsize_t dims[SPACE13_RANK] = {SPACE13_DIM1, SPACE13_DIM2, SPACE13_DIM3}; /* Dataspace dimensions */ + hsize_t coord[SPACE13_NPOINTS][SPACE13_RANK]; /* Coordinates for point selection */ + hsize_t start[SPACE13_RANK]; /* The start of the hyperslab */ + hsize_t stride[SPACE13_RANK]; /* The stride between block starts for the hyperslab */ + hsize_t count[SPACE13_RANK]; /* The number of blocks for the hyperslab */ + hsize_t block[SPACE13_RANK]; /* The size of each block for the hyperslab */ + hsize_t t_start[SPACE13_RANK]; /* Temporary start of the hyperslab */ + hsize_t t_count[SPACE13_RANK]; /* Temporary number of blocks for the hyperslab */ + hsize_t q_start[SPACE13_RANK]; /* The queried start of the hyperslab */ + hsize_t q_stride[SPACE13_RANK]; /* The queried stride between block starts for the hyperslab */ + hsize_t q_count[SPACE13_RANK]; /* The queried number of blocks for the hyperslab */ + hsize_t q_block[SPACE13_RANK]; /* The queried size of each block for the hyperslab */ + htri_t is_regular; /* Whether a hyperslab selection is regular */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing queries on regular hyperslabs\n")); + + /* Create dataspace */ + sid = H5Screate_simple(SPACE13_RANK, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Query if 'all' selection is regular hyperslab (should fail) */ + H5E_BEGIN_TRY { + is_regular = H5Sis_regular_hyperslab(sid); + } H5E_END_TRY; + VERIFY(is_regular, FAIL, "H5Sis_regular_hyperslab"); + + /* Query regular hyperslab selection info (should fail) */ + H5E_BEGIN_TRY { + ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); + } H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_regular_hyperslab"); + + /* Set 'none' selection */ + ret = H5Sselect_none(sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Query if 'none' selection is regular hyperslab (should fail) */ + H5E_BEGIN_TRY { + is_regular = H5Sis_regular_hyperslab(sid); + } H5E_END_TRY; + VERIFY(is_regular, FAIL, "H5Sis_regular_hyperslab"); + + /* Query regular hyperslab selection info (should fail) */ + H5E_BEGIN_TRY { + ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); + } H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_regular_hyperslab"); + + /* Set point selection */ + coord[0][0] = 3; coord[0][1] = 3; coord[0][2] = 3; + coord[1][0] = 3; coord[1][1] = 48; coord[1][2] = 48; + coord[2][0] = 48; coord[2][1] = 3; coord[2][2] = 3; + coord[3][0] = 48; coord[3][1] = 48; coord[3][2] = 48; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)SPACE13_NPOINTS, (const hsize_t *)coord); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Query if 'point' selection is regular hyperslab (should fail) */ + H5E_BEGIN_TRY { + is_regular = H5Sis_regular_hyperslab(sid); + } H5E_END_TRY; + VERIFY(is_regular, FAIL, "H5Sis_regular_hyperslab"); + + /* Query regular hyperslab selection info (should fail) */ + H5E_BEGIN_TRY { + ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); + } H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_regular_hyperslab"); + + /* Set "regular" hyperslab selection */ + start[0] = 2; start[1] = 2; start[2] = 2; + stride[0] = 5; stride[1] = 5; stride[2] = 5; + count[0] = 3; count[1] = 3; count[2] = 3; + block[0] = 4; block[1] = 4; block[2] = 4; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Query if 'hyperslab' selection is regular hyperslab (should be TRUE) */ + is_regular = H5Sis_regular_hyperslab(sid); + VERIFY(is_regular, TRUE, "H5Sis_regular_hyperslab"); + + /* Retrieve the hyperslab parameters */ + ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); + CHECK(ret, FAIL, "H5Sget_regular_hyperslab"); + + /* Verify the hyperslab parameters */ + for(u = 0; u < SPACE13_RANK; u++) { + if(start[u] != q_start[u]) + ERROR("H5Sget_regular_hyperslab, start"); + if(stride[u] != q_stride[u]) + ERROR("H5Sget_regular_hyperslab, stride"); + if(count[u] != q_count[u]) + ERROR("H5Sget_regular_hyperslab, count"); + if(block[u] != q_block[u]) + ERROR("H5Sget_regular_hyperslab, block"); + } /* end for */ + + /* 'OR' in another point */ + t_start[0] = 0; t_start[1] = 0; t_start[2] = 0; + t_count[0] = 1; t_count[1] = 1; t_count[2] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, t_start, NULL, t_count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Query if 'hyperslab' selection is regular hyperslab (should be FALSE) */ + is_regular = H5Sis_regular_hyperslab(sid); + VERIFY(is_regular, FALSE, "H5Sis_regular_hyperslab"); + + /* Query regular hyperslab selection info (should fail) */ + H5E_BEGIN_TRY { + ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); + } H5E_END_TRY; + VERIFY(ret, FAIL, "H5Sget_regular_hyperslab"); + + /* 'XOR' in the point again, to remove it, which should make it regular again */ + t_start[0] = 0; t_start[1] = 0; t_start[2] = 0; + t_count[0] = 1; t_count[1] = 1; t_count[2] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_XOR, t_start, NULL, t_count, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Query if 'hyperslab' selection is regular hyperslab (should be TRUE) */ + is_regular = H5Sis_regular_hyperslab(sid); + VERIFY(is_regular, TRUE, "H5Sis_regular_hyperslab"); + + /* Retrieve the hyperslab parameters */ + ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); + CHECK(ret, FAIL, "H5Sget_regular_hyperslab"); + + /* Verify the hyperslab parameters */ + for(u = 0; u < SPACE13_RANK; u++) { + if(start[u] != q_start[u]) + ERROR("H5Sget_regular_hyperslab, start"); + if(stride[u] != q_stride[u]) + ERROR("H5Sget_regular_hyperslab, stride"); + if(count[u] != q_count[u]) + ERROR("H5Sget_regular_hyperslab, count"); + if(block[u] != q_block[u]) + ERROR("H5Sget_regular_hyperslab, block"); + } /* end for */ + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_hyper_regular() */ + +/**************************************************************** +** +** test_hyper_unlim(): Tests unlimited hyperslab selections +** +****************************************************************/ +static void +test_hyper_unlim_check(hid_t sid, hsize_t *dims, hssize_t enpoints, + hssize_t enblocks, hsize_t *eblock1, hsize_t *eblock2) +{ + hid_t lim_sid; + hsize_t start[3]; + H5S_sel_type sel_type; + hssize_t npoints; + hssize_t nblocks; + hsize_t blocklist[12]; + herr_t ret; + + HDassert(enblocks <= 2); + + /* Copy sid to lim_sid */ + lim_sid = H5Scopy(sid); + CHECK(lim_sid, FAIL, "H5Scopy"); + + /* "And" lim_sid with dims to create limited selection */ + HDmemset(start, 0, sizeof(start)); + ret = H5Sselect_hyperslab(lim_sid, H5S_SELECT_AND, start, NULL, dims, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Check number of elements */ + npoints = H5Sget_select_npoints(lim_sid); + CHECK(npoints, FAIL, "H5Sget_select_npoints"); + VERIFY(npoints, enpoints, "H5Sget_select_npoints"); + + /* Get selection type */ + sel_type = H5Sget_select_type(lim_sid); + CHECK(sel_type, H5S_SEL_ERROR, "H5Sget_select_type"); + + /* Only examine blocks for hyperslab selection */ + if(sel_type == H5S_SEL_HYPERSLABS) { + /* Get number of blocks */ + nblocks = H5Sget_select_hyper_nblocks(lim_sid); + CHECK(nblocks, FAIL, "H5Sget_select_hyper_nblocks"); + VERIFY(nblocks, enblocks, "H5Sget_select_hyper_nblocks"); + + if(nblocks > 0) { + /* Get blocklist */ + ret = H5Sget_select_hyper_blocklist(lim_sid, (hsize_t)0, (hsize_t)nblocks, blocklist); + CHECK(ret, FAIL, "H5Sget_select_hyper_blocklist"); + + /* Verify blocklist */ + if(nblocks == (hssize_t)1) { + if(HDmemcmp(blocklist, eblock1, 6 * sizeof(eblock1[0]))) + ERROR("H5Sget_select_hyper_blocklist"); + } /* end if */ + else { + HDassert(nblocks == (hssize_t)2); + if(HDmemcmp(blocklist, eblock1, 6 * sizeof(eblock1[0]))) { + if(HDmemcmp(blocklist, eblock2, 6 * sizeof(eblock2[0]))) + ERROR("H5Sget_select_hyper_blocklist"); + if(HDmemcmp(&blocklist[6], eblock1, 6 * sizeof(eblock1[0]))) + ERROR("H5Sget_select_hyper_blocklist"); + } /* end if */ + else + if(HDmemcmp(&blocklist[6], eblock2, 6 * sizeof(eblock2[0]))) + ERROR("H5Sget_select_hyper_blocklist"); + } /* end else */ + } /* end if */ + } /* end if */ + else + if(sel_type != H5S_SEL_NONE) + ERROR("H5Sget_select_type"); + + /* Close the limited dataspace */ + ret = H5Sclose(lim_sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* end test_hyper_unlim_check() */ + +static void +test_hyper_unlim(void) +{ + hid_t sid; + hsize_t dims[3] = {4, 4, 7}; + hsize_t mdims[3] = {4, H5S_UNLIMITED, 7}; + hsize_t start[3] = {1, 2, 1}; + hsize_t stride[3] = {1, 1, 3}; + hsize_t count[3] = {1, 1, 2}; + hsize_t block[3] = {2, H5S_UNLIMITED, 2}; + hsize_t start2[3]; + hsize_t count2[3]; + hsize_t eblock1[6] = {1, 2, 1, 2, 3, 2}; + hsize_t eblock2[6] = {1, 2, 4, 2, 3, 5}; + hssize_t offset[3] = {0, -1, 0}; + hssize_t ssize_out; + herr_t ret; + + /* Output message about test being performed */ + MESSAGE(6, ("Testing unlimited hyperslab selections\n")); + + /* Create dataspace */ + sid = H5Screate_simple(3, dims, mdims); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Select unlimited hyperslab */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Check with unlimited dimension clipped to 4 */ + test_hyper_unlim_check(sid, dims, (hssize_t)16, (hssize_t)2, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 3 */ + dims[1] = 3; + eblock1[4] = 2; + eblock2[4] = 2; + test_hyper_unlim_check(sid, dims, (hssize_t)8, (hssize_t)2, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 2 */ + dims[1] = 2; + test_hyper_unlim_check(sid, dims, (hssize_t)0, (hssize_t)0, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 1 */ + dims[1] = 1; + test_hyper_unlim_check(sid, dims, (hssize_t)0, (hssize_t)0, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 7 */ + dims[1] = 7; + eblock1[4] = 6; + eblock2[4] = 6; + test_hyper_unlim_check(sid, dims, (hssize_t)40, (hssize_t)2, eblock1, eblock2); + + /* Set offset of selection */ + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Check with adjusted offset (should not affect result) */ + test_hyper_unlim_check(sid, dims, (hssize_t)40, (hssize_t)2, eblock1, eblock2); + + /* Reset offset of selection */ + offset[1] = (hssize_t)0; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* + * Now try with multiple blocks in unlimited dimension + */ + stride[1] = 3; + stride[2] = 1; + count[1] = H5S_UNLIMITED; + count[2] = 1; + block[1] = 2; + + /* Select unlimited hyperslab */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Check with new selection */ + eblock1[1] = 2; + eblock1[4] = 3; + eblock2[1] = 5; + eblock2[2] = 1; + eblock2[4] = 6; + eblock2[5] = 2; + test_hyper_unlim_check(sid, dims, (hssize_t)16, (hssize_t)2, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 3 */ + dims[1] = 3; + eblock1[4] = 2; + test_hyper_unlim_check(sid, dims, (hssize_t)4, (hssize_t)1, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 4 */ + dims[1] = 4; + eblock1[4] = 3; + test_hyper_unlim_check(sid, dims, (hssize_t)8, (hssize_t)1, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 5 */ + dims[1] = 5; + eblock1[4] = 3; + test_hyper_unlim_check(sid, dims, (hssize_t)8, (hssize_t)1, eblock1, eblock2); + + /* Check with unlimited dimension clipped to 6 */ + dims[1] = 6; + eblock1[4] = 3; + eblock2[4] = 5; + test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + + /* Set offset of selection */ + offset[1] = (hssize_t)-1; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Check with adjusted offset (should not affect result) */ + test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + + /* Set offset of selection */ + offset[1] = (hssize_t)3; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* Check with adjusted offset (should not affect result) */ + test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + + /* Reset offset of selection */ + offset[1] = (hssize_t)0; + ret = H5Soffset_simple(sid, offset); + CHECK(ret, FAIL, "H5Soffset_simple"); + + /* + * Now try invalid operations + */ + H5E_BEGIN_TRY { + /* Try multiple unlimited dimensions */ + start[0] = 1; + start[1] = 2; + start[2] = 1; + stride[0] = 1; + stride[1] = 3; + stride[2] = 3; + count[0] = 1; + count[1] = H5S_UNLIMITED; + count[2] = H5S_UNLIMITED; + block[0] = 2; + block[1] = 2; + block[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + + /* Try unlimited count and block */ + count[2] = 2; + block[1] = H5S_UNLIMITED; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + } H5E_END_TRY + + /* Try operations with two unlimited selections */ + block[1] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + H5E_BEGIN_TRY { + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, NULL, count, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_AND, start, NULL, count, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_XOR, start, NULL, count, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTB, start, NULL, count, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTA, start, NULL, count, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + } H5E_END_TRY + + /* Try invalid combination operations */ + H5E_BEGIN_TRY { + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, NULL, block, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_XOR, start, NULL, block, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTB, start, NULL, block, NULL); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + } H5E_END_TRY + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL, block, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + H5E_BEGIN_TRY { + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, stride, count, block); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_XOR, start, stride, count, block); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTA, start, stride, count, block); + VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + } H5E_END_TRY + + /* + * Now test valid combination operations + */ + /* unlim AND non-unlim */ + count[0] = 1; + count[1] = H5S_UNLIMITED; + count[2] = 2; + block[0] = 2; + block[1] = 2; + block[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + start2[0] = 2; + start2[1] = 2; + start2[2] = 0; + count2[0] = 5; + count2[1] = 4; + count2[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_AND, start2, NULL, count2, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + eblock1[0] = 2; + eblock1[3] = 2; + eblock1[1] = 2; + eblock1[4] = 3; + eblock1[2] = 1; + eblock1[5] = 1; + eblock2[0] = 2; + eblock2[3] = 2; + eblock2[1] = 5; + eblock2[4] = 5; + eblock2[2] = 1; + eblock2[5] = 1; + dims[0] = 50; + dims[1] = 50; + dims[2] = 50; + test_hyper_unlim_check(sid, dims, (hssize_t)3, (hssize_t)2, eblock1, eblock2); + + /* unlim NOTA non-unlim */ + count[0] = 1; + count[1] = H5S_UNLIMITED; + count[2] = 2; + block[0] = 2; + block[1] = 2; + block[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + start2[0] = 1; + start2[1] = 5; + start2[2] = 2; + count2[0] = 2; + count2[1] = 2; + count2[2] = 6; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTA, start2, NULL, count2, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + eblock1[0] = 1; + eblock1[3] = 2; + eblock1[1] = 5; + eblock1[4] = 6; + eblock1[2] = 3; + eblock1[5] = 3; + eblock2[0] = 1; + eblock2[3] = 2; + eblock2[1] = 5; + eblock2[4] = 6; + eblock2[2] = 6; + eblock2[5] = 7; + dims[0] = 50; + dims[1] = 50; + dims[2] = 50; + test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + + /* non-unlim AND unlim */ + start2[0] = 2; + start2[1] = 2; + start2[2] = 0; + count2[0] = 5; + count2[1] = 4; + count2[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start2, NULL, count2, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + count[0] = 1; + count[1] = H5S_UNLIMITED; + count[2] = 2; + block[0] = 2; + block[1] = 2; + block[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_AND, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + eblock1[0] = 2; + eblock1[3] = 2; + eblock1[1] = 2; + eblock1[4] = 3; + eblock1[2] = 1; + eblock1[5] = 1; + eblock2[0] = 2; + eblock2[3] = 2; + eblock2[1] = 5; + eblock2[4] = 5; + eblock2[2] = 1; + eblock2[5] = 1; + dims[0] = 50; + dims[1] = 50; + dims[2] = 50; + test_hyper_unlim_check(sid, dims, (hssize_t)3, (hssize_t)2, eblock1, eblock2); + + /* non-unlim NOTB unlim */ + start2[0] = 1; + start2[1] = 5; + start2[2] = 2; + count2[0] = 2; + count2[1] = 2; + count2[2] = 6; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start2, NULL, count2, NULL); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + count[0] = 1; + count[1] = H5S_UNLIMITED; + count[2] = 2; + block[0] = 2; + block[1] = 2; + block[2] = 2; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTB, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + eblock1[0] = 1; + eblock1[3] = 2; + eblock1[1] = 5; + eblock1[4] = 6; + eblock1[2] = 3; + eblock1[5] = 3; + eblock2[0] = 1; + eblock2[3] = 2; + eblock2[1] = 5; + eblock2[4] = 6; + eblock2[2] = 6; + eblock2[5] = 7; + dims[0] = 50; + dims[1] = 50; + dims[2] = 50; + test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + + /* Test H5Sget_select_npoints() */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + ssize_out = H5Sget_select_npoints(sid); + VERIFY(ssize_out, (hssize_t)H5S_UNLIMITED, "H5Sget_select_npoints"); + + /* Test H5Sget_select_hyper_nblocks() */ + ssize_out = H5Sget_select_hyper_nblocks(sid); + VERIFY(ssize_out, (hssize_t)H5S_UNLIMITED, "H5Sget_select_hyper_nblocks"); + + /* Test H5Sget_select_bounds() */ + ret = H5Sget_select_bounds(sid, start2, count2); + CHECK(ret, FAIL, "H5Sget_select_bounds"); + VERIFY(start2[0], start[0], "H5Sget_select_bounds"); + VERIFY(start2[1], start[1], "H5Sget_select_bounds"); + VERIFY(start2[2], start[2], "H5Sget_select_bounds"); + VERIFY(count2[0], (long)(start[0] + (stride[0] * (count[0] - 1)) + block[0] - 1), "H5Sget_select_bounds"); + VERIFY(count2[1], H5S_UNLIMITED, "H5Sget_select_bounds"); + VERIFY(count2[2], (long)(start[2] + (stride[2] * (count[2] - 1)) + block[2] - 1), "H5Sget_select_bounds"); + + /* Close the dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* end test_hyper_unlim() */ + +/**************************************************************** +** +** test_internal_consistency(): Tests selections on dataspace, then +** verify that internal states of data structures of selections are +** consistent. +** +****************************************************************/ +static void +test_internal_consistency(void) +{ + hid_t all_sid; /* Dataspace ID with "all" selection */ + hid_t none_sid; /* Dataspace ID with "none" selection */ + hid_t single_pt_sid; /* Dataspace ID with single point selection */ + hid_t mult_pt_sid; /* Dataspace ID with multiple point selection */ + hid_t single_hyper_sid; /* Dataspace ID with single block hyperslab selection */ + hid_t single_hyper_all_sid; /* Dataspace ID with single block hyperslab + * selection that is the entire dataspace + */ + hid_t single_hyper_pt_sid; /* Dataspace ID with single block hyperslab + * selection that is the same as the single + * point selection + */ + hid_t regular_hyper_sid; /* Dataspace ID with regular hyperslab selection */ + hid_t irreg_hyper_sid; /* Dataspace ID with irregular hyperslab selection */ + hid_t none_hyper_sid; /* Dataspace ID with "no hyperslabs" selection */ + hid_t scalar_all_sid; /* ID for scalar dataspace with "all" selection */ + hid_t scalar_none_sid; /* ID for scalar dataspace with "none" selection */ + hid_t tmp_sid; /* Temporary dataspace ID */ + hsize_t dims[] = {SPACE9_DIM1, SPACE9_DIM2}; + hsize_t coord1[1][SPACE2_RANK]; /* Coordinates for single point selection */ + hsize_t coord2[SPACE9_DIM2][SPACE9_RANK]; /* Coordinates for multiple point selection */ + hsize_t start[SPACE9_RANK]; /* Hyperslab start */ + hsize_t stride[SPACE9_RANK]; /* Hyperslab stride */ + hsize_t count[SPACE9_RANK]; /* Hyperslab block count */ + hsize_t block[SPACE9_RANK]; /* Hyperslab block size */ + htri_t check; /* Shape comparison return value */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing Consistency of Internal States\n")); + assert(SPACE9_DIM2>=POINT1_NPOINTS); + + /* Create dataspace for "all" selection */ + all_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(all_sid, FAIL, "H5Screate_simple"); + + /* Select entire extent for dataspace */ + ret = H5Sselect_all(all_sid); + CHECK(ret, FAIL, "H5Sselect_all"); + + /* Create dataspace for "none" selection */ + none_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(none_sid, FAIL, "H5Screate_simple"); + + /* Un-Select entire extent for dataspace */ + ret = H5Sselect_none(none_sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Create dataspace for single point selection */ + single_pt_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(single_pt_sid, FAIL, "H5Screate_simple"); + + /* Select sequence of ten points for multiple point selection */ + coord1[0][0] = 2; coord1[0][1] = 2; + ret = H5Sselect_elements(single_pt_sid, H5S_SELECT_SET, (size_t)1, (const hsize_t *)coord1); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Create dataspace for multiple point selection */ + mult_pt_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(mult_pt_sid, FAIL, "H5Screate_simple"); + + /* Select sequence of ten points for multiple point selection */ + coord2[0][0]=2; coord2[0][1]=2; + coord2[1][0]=7; coord2[1][1]=2; + coord2[2][0]=1; coord2[2][1]=4; + coord2[3][0]=2; coord2[3][1]=6; + coord2[4][0]=0; coord2[4][1]=8; + coord2[5][0]=3; coord2[5][1]=2; + coord2[6][0]=4; coord2[6][1]=4; + coord2[7][0]=1; coord2[7][1]=0; + coord2[8][0]=5; coord2[8][1]=1; + coord2[9][0]=9; coord2[9][1]=3; + ret = H5Sselect_elements(mult_pt_sid, H5S_SELECT_SET, (size_t)POINT1_NPOINTS, (const hsize_t *)coord2); + CHECK(ret, FAIL, "H5Sselect_elements"); + + /* Create dataspace for single hyperslab selection */ + single_hyper_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(single_hyper_sid, FAIL, "H5Screate_simple"); + + /* Select 10x10 hyperslab for single hyperslab selection */ + start[0]=1; start[1]=1; + stride[0]=1; stride[1]=1; + count[0]=1; count[1]=1; + block[0]=(SPACE9_DIM1-2); block[1]=(SPACE9_DIM2-2); + ret = H5Sselect_hyperslab(single_hyper_sid,H5S_SELECT_SET,start,stride,count,block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for single hyperslab selection with entire extent selected */ + single_hyper_all_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(single_hyper_all_sid, FAIL, "H5Screate_simple"); + + /* Select entire extent for hyperslab selection */ + start[0]=0; start[1]=0; + stride[0]=1; stride[1]=1; + count[0]=1; count[1]=1; + block[0]=SPACE9_DIM1; block[1]=SPACE9_DIM2; + ret = H5Sselect_hyperslab(single_hyper_all_sid,H5S_SELECT_SET,start,stride,count,block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for single hyperslab selection with single point selected */ + single_hyper_pt_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(single_hyper_pt_sid, FAIL, "H5Screate_simple"); + + /* Select entire extent for hyperslab selection */ + start[0]=2; start[1]=2; + stride[0]=1; stride[1]=1; + count[0]=1; count[1]=1; + block[0]=1; block[1]=1; + ret = H5Sselect_hyperslab(single_hyper_pt_sid,H5S_SELECT_SET,start,stride,count,block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for regular hyperslab selection */ + regular_hyper_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(regular_hyper_sid, FAIL, "H5Screate_simple"); + + /* Select regular, strided hyperslab selection */ + start[0]=2; start[1]=2; + stride[0]=2; stride[1]=2; + count[0]=5; count[1]=2; + block[0]=1; block[1]=1; + ret = H5Sselect_hyperslab(regular_hyper_sid,H5S_SELECT_SET,start,stride,count,block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for irregular hyperslab selection */ + irreg_hyper_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(irreg_hyper_sid, FAIL, "H5Screate_simple"); + + /* Create irregular hyperslab selection by OR'ing two blocks together */ + start[0]=2; start[1]=2; + stride[0]=1; stride[1]=1; + count[0]=1; count[1]=1; + block[0]=1; block[1]=1; + ret = H5Sselect_hyperslab(irreg_hyper_sid,H5S_SELECT_SET,start,stride,count,block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + start[0]=4; start[1]=4; + stride[0]=1; stride[1]=1; + count[0]=1; count[1]=1; + block[0]=3; block[1]=3; + ret = H5Sselect_hyperslab(irreg_hyper_sid,H5S_SELECT_OR,start,stride,count,block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create dataspace for "no" hyperslab selection */ + none_hyper_sid = H5Screate_simple(SPACE9_RANK, dims, NULL); + CHECK(none_hyper_sid, FAIL, "H5Screate_simple"); + + /* Create "no" hyperslab selection by XOR'ing same blocks together */ + start[0]=2; start[1]=2; + stride[0]=1; stride[1]=1; + count[0]=1; count[1]=1; + block[0]=1; block[1]=1; + ret = H5Sselect_hyperslab(none_hyper_sid,H5S_SELECT_SET,start,stride,count,block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + ret = H5Sselect_hyperslab(none_hyper_sid,H5S_SELECT_XOR,start,stride,count,block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); + + /* Create scalar dataspace for "all" selection */ + scalar_all_sid = H5Screate(H5S_SCALAR); + CHECK(scalar_all_sid, FAIL, "H5Screate"); + + /* Create scalar dataspace for "none" selection */ + scalar_none_sid = H5Screate(H5S_SCALAR); + CHECK(scalar_none_sid, FAIL, "H5Screate"); + + /* Un-Select entire extent for dataspace */ + ret = H5Sselect_none(scalar_none_sid); + CHECK(ret, FAIL, "H5Sselect_none"); + + /* Test all the selections created */ + + /* Test the copy of itself */ + tmp_sid=H5Scopy(all_sid); + CHECK(tmp_sid, FAIL, "H5Scopy"); + + check = H5S__internal_consistency_test(tmp_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + ret = H5Sclose(tmp_sid); + CHECK(ret, FAIL, "H5Sclose"); + + /* Test "none" selection */ + check = H5S__internal_consistency_test(none_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test single point selection */ + check = H5S__internal_consistency_test(single_pt_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test multiple point selection */ + check = H5S__internal_consistency_test(mult_pt_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test "plain" single hyperslab selection */ + check = H5S__internal_consistency_test(single_hyper_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test "all" single hyperslab selection */ + check = H5S__internal_consistency_test(single_hyper_all_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test "single point" single hyperslab selection */ + check = H5S__internal_consistency_test(single_hyper_pt_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test regular, strided hyperslab selection */ + check = H5S__internal_consistency_test(regular_hyper_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test irregular hyperslab selection */ + check = H5S__internal_consistency_test(irreg_hyper_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test "no" hyperslab selection */ + check = H5S__internal_consistency_test(none_hyper_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test scalar "all" hyperslab selection */ + check = H5S__internal_consistency_test(scalar_all_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Test scalar "none" hyperslab selection */ + check = H5S__internal_consistency_test(scalar_none_sid); + VERIFY(check, TRUE, "H5S__internal_consistency_test"); + + /* Close dataspaces */ + ret = H5Sclose(all_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(none_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_pt_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(mult_pt_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_hyper_all_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(single_hyper_pt_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(regular_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(irreg_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(none_hyper_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(scalar_all_sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(scalar_none_sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_internal_consistency() */ + +/**************************************************************** +** +** test_irreg_io(): Tests unusual selections on datasets, to stress the +** new hyperslab code. +** +****************************************************************/ +static void +test_irreg_io(void) +{ + hid_t fid; /* File ID */ + hid_t did; /* Dataset ID */ + hid_t dcpl_id; /* Dataset creation property list ID */ + hid_t sid; /* File dataspace ID */ + hid_t mem_sid; /* Memory dataspace ID */ + hsize_t dims[] = {6, 12}; /* Dataspace dimensions */ + hsize_t chunk_dims[] = {2, 2}; /* Chunk dimensions */ + hsize_t mem_dims[] = {32}; /* Memory dataspace dimensions */ + hsize_t start[2]; /* Hyperslab start */ + hsize_t stride[2]; /* Hyperslab stride */ + hsize_t count[2]; /* Hyperslab block count */ + hsize_t block[2]; /* Hyperslab block size */ + unsigned char wbuf[72]; /* Write buffer */ + unsigned char rbuf[32]; /* Read buffer */ + unsigned u; /* Local index variable */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(6, ("Testing Irregular Hyperslab I/O\n")); + + /* Create file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fcreate"); + + /* Create dataspace for dataset */ + sid = H5Screate_simple(2, dims, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); + + /* Set chunk dimensions for dataset */ + dcpl_id = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl_id, FAIL, "H5Pcreate"); + ret = H5Pset_chunk(dcpl_id, 2, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); + + /* Create a dataset */ + did = H5Dcreate2(fid, SPACE1_NAME, H5T_NATIVE_UCHAR, sid, H5P_DEFAULT, dcpl_id, H5P_DEFAULT); + CHECK(did, FAIL, "H5Dcreate2"); - /* Retrieve the hyperslab parameters */ - ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); - CHECK(ret, FAIL, "H5Sget_regular_hyperslab"); + /* Initialize the write buffer */ + for(u = 0; u < 72; u++) + wbuf[u] = (unsigned char)u; - /* Verify the hyperslab parameters */ - for(u = 0; u < SPACE13_RANK; u++) { - if(start[u] != q_start[u]) - ERROR("H5Sget_regular_hyperslab, start"); - if(stride[u] != q_stride[u]) - ERROR("H5Sget_regular_hyperslab, stride"); - if(count[u] != q_count[u]) - ERROR("H5Sget_regular_hyperslab, count"); - if(block[u] != q_block[u]) - ERROR("H5Sget_regular_hyperslab, block"); - } /* end for */ + /* Write entire dataset to disk */ + ret = H5Dwrite(did, H5T_NATIVE_UCHAR, H5S_ALL, H5S_ALL, H5P_DEFAULT, wbuf); + CHECK(ret, FAIL, "H5Dwrite"); - /* 'OR' in another point */ - t_start[0] = 0; t_start[1] = 0; t_start[2] = 0; - t_count[0] = 1; t_count[1] = 1; t_count[2] = 1; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, t_start, NULL, t_count, NULL); - CHECK(ret, FAIL, "H5Sselect_hyperslab"); + /* Close the DCPL */ + ret = H5Pclose(dcpl_id); + CHECK(ret, FAIL, "H5Pclose"); - /* Query if 'hyperslab' selection is regular hyperslab (should be FALSE) */ - is_regular = H5Sis_regular_hyperslab(sid); - VERIFY(is_regular, FALSE, "H5Sis_regular_hyperslab"); + /* Create dataspace for memory selection */ + mem_sid = H5Screate_simple(1, mem_dims, NULL); + CHECK(mem_sid, FAIL, "H5Screate_simple"); - /* Query regular hyperslab selection info (should fail) */ - H5E_BEGIN_TRY { - ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); - } H5E_END_TRY; - VERIFY(ret, FAIL, "H5Sget_regular_hyperslab"); + /* Select 'L'-shaped region within dataset */ + start[0] = 0; start[1] = 10; + stride[0] = 1; stride[1] = 1; + count[0] = 4; count[1] = 2; + block[0] = 1; block[1] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* 'XOR' in the point again, to remove it, which should make it regular again */ - t_start[0] = 0; t_start[1] = 0; t_start[2] = 0; - t_count[0] = 1; t_count[1] = 1; t_count[2] = 1; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_XOR, t_start, NULL, t_count, NULL); + start[0] = 4; start[1] = 0; + stride[0] = 1; stride[1] = 1; + count[0] = 2; count[1] = 12; + block[0] = 1; block[1] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, stride, count, block); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Query if 'hyperslab' selection is regular hyperslab (should be TRUE) */ - is_regular = H5Sis_regular_hyperslab(sid); - VERIFY(is_regular, TRUE, "H5Sis_regular_hyperslab"); + /* Reset the buffer */ + HDmemset(rbuf, 0, sizeof(rbuf)); - /* Retrieve the hyperslab parameters */ - ret = H5Sget_regular_hyperslab(sid, q_start, q_stride, q_count, q_block); - CHECK(ret, FAIL, "H5Sget_regular_hyperslab"); + /* Read selection from disk */ + ret = H5Dread(did, H5T_NATIVE_UCHAR, mem_sid, sid, H5P_DEFAULT, rbuf); + CHECK(ret, FAIL, "H5Dread"); - /* Verify the hyperslab parameters */ - for(u = 0; u < SPACE13_RANK; u++) { - if(start[u] != q_start[u]) - ERROR("H5Sget_regular_hyperslab, start"); - if(stride[u] != q_stride[u]) - ERROR("H5Sget_regular_hyperslab, stride"); - if(count[u] != q_count[u]) - ERROR("H5Sget_regular_hyperslab, count"); - if(block[u] != q_block[u]) - ERROR("H5Sget_regular_hyperslab, block"); - } /* end for */ - /* Close the dataspace */ + /* Close everything */ + ret = H5Sclose(mem_sid); + CHECK(ret, FAIL, "H5Sclose"); ret = H5Sclose(sid); CHECK(ret, FAIL, "H5Sclose"); -} /* test_hyper_regular() */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* test_irreg_io() */ /**************************************************************** ** -** test_hyper_unlim(): Tests unlimited hyperslab selections +** test_select_intersect_block(): Test selections on dataspace, +** verify that "intersect block" routine is working correctly. ** ****************************************************************/ static void -test_hyper_unlim_check(hid_t sid, hsize_t *dims, hssize_t enpoints, - hssize_t enblocks, hsize_t *eblock1, hsize_t *eblock2) +test_select_intersect_block(void) { - hid_t lim_sid; - hsize_t start[3]; - H5S_sel_type sel_type; - hssize_t npoints; - hssize_t nblocks; - hsize_t blocklist[12]; - herr_t ret; + hid_t sid; /* Dataspace ID */ + hsize_t dims1[] = {6, 12}; /* 2-D Dataspace dimensions */ + hsize_t block_start[] = {1, 3}; /* Start offset for block */ + hsize_t block_end[] = {2, 5}; /* End offset for block */ + hsize_t block_end2[] = {0, 5}; /* Bad end offset for block */ + hsize_t block_end3[] = {2, 2}; /* Another bad end offset for block */ + hsize_t block_end4[] = {1, 3}; /* End offset that makes a single element block */ + hsize_t coord[10][2]; /* Coordinates for point selection */ + hsize_t start[2]; /* Starting location of hyperslab */ + hsize_t stride[2]; /* Stride of hyperslab */ + hsize_t count[2]; /* Element count of hyperslab */ + hsize_t block[2]; /* Block size of hyperslab */ + htri_t status; /* Intersection status */ + herr_t ret; /* Generic return value */ - HDassert(enblocks <= 2); + /* Output message about test being performed */ + MESSAGE(6, ("Testing Dataspace Selection Block Intersection\n")); - /* Copy sid to lim_sid */ - lim_sid = H5Scopy(sid); - CHECK(lim_sid, FAIL, "H5Scopy"); + /* Create dataspace */ + sid = H5Screate_simple(2, dims1, NULL); + CHECK(sid, FAIL, "H5Screate_simple"); - /* "And" lim_sid with dims to create limited selection */ - HDmemset(start, 0, sizeof(start)); - ret = H5Sselect_hyperslab(lim_sid, H5S_SELECT_AND, start, NULL, dims, NULL); - CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Check number of elements */ - npoints = H5Sget_select_npoints(lim_sid); - CHECK(npoints, FAIL, "H5Sget_select_npoints"); - VERIFY(npoints, enpoints, "H5Sget_select_npoints"); + /* Try intersection calls with bad parameters */ + H5E_BEGIN_TRY { /* Bad dataspace ID */ + status = H5Sselect_intersect_block(H5I_INVALID_HID, block_start, block_end); + } H5E_END_TRY; + VERIFY(status, FAIL, "H5Sselect_intersect_block"); + H5E_BEGIN_TRY { /* Bad start pointer */ + status = H5Sselect_intersect_block(sid, NULL, block_end); + } H5E_END_TRY; + VERIFY(status, FAIL, "H5Sselect_intersect_block"); + H5E_BEGIN_TRY { /* Bad end pointer */ + status = H5Sselect_intersect_block(sid, block_start, NULL); + } H5E_END_TRY; + VERIFY(status, FAIL, "H5Sselect_intersect_block"); + H5E_BEGIN_TRY { /* Invalid block */ + status = H5Sselect_intersect_block(sid, block_start, block_end2); + } H5E_END_TRY; + VERIFY(status, FAIL, "H5Sselect_intersect_block"); + H5E_BEGIN_TRY { /* Another invalid block */ + status = H5Sselect_intersect_block(sid, block_start, block_end3); + } H5E_END_TRY; + VERIFY(status, FAIL, "H5Sselect_intersect_block"); - /* Get selection type */ - sel_type = H5Sget_select_type(lim_sid); - CHECK(sel_type, H5S_SEL_ERROR, "H5Sget_select_type"); - /* Only examine blocks for hyperslab selection */ - if(sel_type == H5S_SEL_HYPERSLABS) { - /* Get number of blocks */ - nblocks = H5Sget_select_hyper_nblocks(lim_sid); - CHECK(nblocks, FAIL, "H5Sget_select_hyper_nblocks"); - VERIFY(nblocks, enblocks, "H5Sget_select_hyper_nblocks"); + /* Set selection to 'none' */ + ret = H5Sselect_none(sid); + CHECK(ret, FAIL, "H5Sselect_none"); - if(nblocks > 0) { - /* Get blocklist */ - ret = H5Sget_select_hyper_blocklist(lim_sid, (hsize_t)0, (hsize_t)nblocks, blocklist); - CHECK(ret, FAIL, "H5Sget_select_hyper_blocklist"); + /* Test block intersection with 'none' selection (always false) */ + status = H5Sselect_intersect_block(sid, block_start, block_end); + VERIFY(status, FALSE, "H5Sselect_intersect_block"); - /* Verify blocklist */ - if(nblocks == (hssize_t)1) { - if(HDmemcmp(blocklist, eblock1, 6 * sizeof(eblock1[0]))) - ERROR("H5Sget_select_hyper_blocklist"); - } /* end if */ - else { - HDassert(nblocks == (hssize_t)2); - if(HDmemcmp(blocklist, eblock1, 6 * sizeof(eblock1[0]))) { - if(HDmemcmp(blocklist, eblock2, 6 * sizeof(eblock2[0]))) - ERROR("H5Sget_select_hyper_blocklist"); - if(HDmemcmp(&blocklist[6], eblock1, 6 * sizeof(eblock1[0]))) - ERROR("H5Sget_select_hyper_blocklist"); - } /* end if */ - else - if(HDmemcmp(&blocklist[6], eblock2, 6 * sizeof(eblock2[0]))) - ERROR("H5Sget_select_hyper_blocklist"); - } /* end else */ - } /* end if */ - } /* end if */ - else - if(sel_type != H5S_SEL_NONE) - ERROR("H5Sget_select_type"); - /* Close the limited dataspace */ - ret = H5Sclose(lim_sid); - CHECK(ret, FAIL, "H5Sclose"); -} /* end test_hyper_unlim_check() */ + /* Set selection to 'all' */ + ret = H5Sselect_all(sid); + CHECK(ret, FAIL, "H5Sselect_all"); -static void -test_hyper_unlim(void) -{ - hid_t sid; - hsize_t dims[3] = {4, 4, 7}; - hsize_t mdims[3] = {4, H5S_UNLIMITED, 7}; - hsize_t start[3] = {1, 2, 1}; - hsize_t stride[3] = {1, 1, 3}; - hsize_t count[3] = {1, 1, 2}; - hsize_t block[3] = {2, H5S_UNLIMITED, 2}; - hsize_t start2[3]; - hsize_t count2[3]; - hsize_t eblock1[6] = {1, 2, 1, 2, 3, 2}; - hsize_t eblock2[6] = {1, 2, 4, 2, 3, 5}; - hssize_t offset[3] = {0, -1, 0}; - hssize_t ssize_out; - herr_t ret; + /* Test block intersection with 'all' selection (always true) */ + status = H5Sselect_intersect_block(sid, block_start, block_end); + VERIFY(status, TRUE, "H5Sselect_intersect_block"); + + + /* Select sequence of ten points */ + coord[0][0] = 0; coord[0][1] = 10; + coord[1][0] = 1; coord[1][1] = 2; + coord[2][0] = 2; coord[2][1] = 4; + coord[3][0] = 0; coord[3][1] = 6; + coord[4][0] = 1; coord[4][1] = 8; + coord[5][0] = 2; coord[5][1] = 11; + coord[6][0] = 0; coord[6][1] = 4; + coord[7][0] = 1; coord[7][1] = 0; + coord[8][0] = 2; coord[8][1] = 1; + coord[9][0] = 0; coord[9][1] = 3; + ret = H5Sselect_elements(sid, H5S_SELECT_SET, (size_t)10, (const hsize_t *)coord); + CHECK(ret, FAIL, "H5Sselect_elements"); - /* Output message about test being performed */ - MESSAGE(6, ("Testing unlimited hyperslab selections\n")); + /* Test block intersection with 'point' selection */ + status = H5Sselect_intersect_block(sid, block_start, block_end); + VERIFY(status, TRUE, "H5Sselect_intersect_block"); + status = H5Sselect_intersect_block(sid, block_start, block_end4); + VERIFY(status, FALSE, "H5Sselect_intersect_block"); - /* Create dataspace */ - sid = H5Screate_simple(3, dims, mdims); - CHECK(sid, FAIL, "H5Screate_simple"); - /* Select unlimited hyperslab */ + /* Select single 4x6 hyperslab block at (2,1) */ + start[0] = 2; start[1] = 1; + stride[0] = 1; stride[1] = 1; + count[0] = 4; count[1] = 6; + block[0] = 1; block[1] = 1; ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Check with unlimited dimension clipped to 4 */ - test_hyper_unlim_check(sid, dims, (hssize_t)16, (hssize_t)2, eblock1, eblock2); - - /* Check with unlimited dimension clipped to 3 */ - dims[1] = 3; - eblock1[4] = 2; - eblock2[4] = 2; - test_hyper_unlim_check(sid, dims, (hssize_t)8, (hssize_t)2, eblock1, eblock2); - - /* Check with unlimited dimension clipped to 2 */ - dims[1] = 2; - test_hyper_unlim_check(sid, dims, (hssize_t)0, (hssize_t)0, eblock1, eblock2); - - /* Check with unlimited dimension clipped to 1 */ - dims[1] = 1; - test_hyper_unlim_check(sid, dims, (hssize_t)0, (hssize_t)0, eblock1, eblock2); - - /* Check with unlimited dimension clipped to 7 */ - dims[1] = 7; - eblock1[4] = 6; - eblock2[4] = 6; - test_hyper_unlim_check(sid, dims, (hssize_t)40, (hssize_t)2, eblock1, eblock2); - - /* Set offset of selection */ - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); - - /* Check with adjusted offset (should not affect result) */ - test_hyper_unlim_check(sid, dims, (hssize_t)40, (hssize_t)2, eblock1, eblock2); + /* Test block intersection with single 'hyperslab' selection */ + status = H5Sselect_intersect_block(sid, block_start, block_end); + VERIFY(status, TRUE, "H5Sselect_intersect_block"); + status = H5Sselect_intersect_block(sid, block_start, block_end4); + VERIFY(status, FALSE, "H5Sselect_intersect_block"); - /* Reset offset of selection */ - offset[1] = (hssize_t)0; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + /* 'OR' another hyperslab block in, making an irregular hyperslab selection */ + start[0] = 3; start[1] = 2; + stride[0] = 1; stride[1] = 1; + count[0] = 4; count[1] = 6; + block[0] = 1; block[1] = 1; + ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, stride, count, block); + CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* - * Now try with multiple blocks in unlimited dimension - */ - stride[1] = 3; - stride[2] = 1; - count[1] = H5S_UNLIMITED; - count[2] = 1; - block[1] = 2; + /* Test block intersection with 'hyperslab' selection */ + status = H5Sselect_intersect_block(sid, block_start, block_end); + VERIFY(status, TRUE, "H5Sselect_intersect_block"); + status = H5Sselect_intersect_block(sid, block_start, block_end4); + VERIFY(status, FALSE, "H5Sselect_intersect_block"); - /* Select unlimited hyperslab */ + /* Select regular, strided hyperslab selection */ + start[0] = 2; start[1] = 1; + stride[0] = 2; stride[1] = 2; + count[0] = 2; count[1] = 4; + block[0] = 1; block[1] = 1; ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - /* Check with new selection */ - eblock1[1] = 2; - eblock1[4] = 3; - eblock2[1] = 5; - eblock2[2] = 1; - eblock2[4] = 6; - eblock2[5] = 2; - test_hyper_unlim_check(sid, dims, (hssize_t)16, (hssize_t)2, eblock1, eblock2); + /* Test block intersection with single 'hyperslab' selection */ + status = H5Sselect_intersect_block(sid, block_start, block_end); + VERIFY(status, TRUE, "H5Sselect_intersect_block"); + status = H5Sselect_intersect_block(sid, block_start, block_end4); + VERIFY(status, FALSE, "H5Sselect_intersect_block"); - /* Check with unlimited dimension clipped to 3 */ - dims[1] = 3; - eblock1[4] = 2; - test_hyper_unlim_check(sid, dims, (hssize_t)4, (hssize_t)1, eblock1, eblock2); - /* Check with unlimited dimension clipped to 4 */ - dims[1] = 4; - eblock1[4] = 3; - test_hyper_unlim_check(sid, dims, (hssize_t)8, (hssize_t)1, eblock1, eblock2); + /* Close dataspace */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); +} /* test_select_intersect_block() */ - /* Check with unlimited dimension clipped to 5 */ - dims[1] = 5; - eblock1[4] = 3; - test_hyper_unlim_check(sid, dims, (hssize_t)8, (hssize_t)1, eblock1, eblock2); + +/**************************************************************** +** +** test_hyper_io_1d(): +** Test to verify all the selected 10th element in the 1-d file +** dataspace is read correctly into the 1-d contiguous memory space. +** This is modeled after the test scenario described in HDFFV-10585 +** that demonstrated the hyperslab slowness. A fix to speed up +** performance is in place to handle the special case for 1-d disjoint +** file dataspace into 1-d single block contiguous memory space. +** +****************************************************************/ +static void +test_hyper_io_1d(void) +{ + hid_t fid; /* File ID */ + hid_t did; /* Dataset ID */ + hid_t sid, mid; /* Dataspace IDs */ + hid_t dcpl; /* Dataset creation property list ID */ + hsize_t dims[1], maxdims[1], dimsm[1]; /* Dataset dimension sizes */ + hsize_t chunk_dims[1]; /* Chunk dimension size */ + hsize_t offset[1]; /* Starting offset for hyperslab */ + hsize_t stride[1]; /* Distance between blocks in the hyperslab selection */ + hsize_t count[1]; /* # of blocks in the the hyperslab selection */ + hsize_t block[1]; /* Size of block in the hyperslab selection */ + unsigned int wdata[CHUNKSZ]; /* Data to be written */ + unsigned int rdata[NUM_ELEMENTS/10]; /* Data to be read */ + herr_t ret; /* Generic return value */ + unsigned i; /* Local index variable */ - /* Check with unlimited dimension clipped to 6 */ - dims[1] = 6; - eblock1[4] = 3; - eblock2[4] = 5; - test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + /* Output message about test being performed */ + MESSAGE(6, ("Testing Hyperslab I/O for 1-d single block memory space\n")); - /* Set offset of selection */ - offset[1] = (hssize_t)-1; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + for (i = 0; i < CHUNKSZ; i++) + wdata[i] = i; + + /* Create the file file */ + fid = H5Fcreate(FILENAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + CHECK(fid, H5I_INVALID_HID, "H5Fcreate"); - /* Check with adjusted offset (should not affect result) */ - test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + /* Create file dataspace */ + dims[0] = CHUNKSZ; + maxdims[0] = H5S_UNLIMITED; + sid = H5Screate_simple(RANK, dims, maxdims); + CHECK(sid, H5I_INVALID_HID, "H5Pcreate"); - /* Set offset of selection */ - offset[1] = (hssize_t)3; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + /* Create memory dataspace */ + dimsm[0] = CHUNKSZ; + mid = H5Screate_simple(RANK, dimsm, NULL); + CHECK(mid, H5I_INVALID_HID, "H5Pcreate"); - /* Check with adjusted offset (should not affect result) */ - test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + /* Set up to create a chunked dataset */ + dcpl = H5Pcreate(H5P_DATASET_CREATE); + CHECK(dcpl, H5I_INVALID_HID, "H5Pcreate"); - /* Reset offset of selection */ - offset[1] = (hssize_t)0; - ret = H5Soffset_simple(sid, offset); - CHECK(ret, FAIL, "H5Soffset_simple"); + chunk_dims[0] = CHUNKSZ; + ret = H5Pset_chunk(dcpl, RANK, chunk_dims); + CHECK(ret, FAIL, "H5Pset_chunk"); - /* - * Now try invalid operations - */ - H5E_BEGIN_TRY { - /* Try multiple unlimited dimensions */ - start[0] = 1; - start[1] = 2; - start[2] = 1; - stride[0] = 1; - stride[1] = 3; - stride[2] = 3; - count[0] = 1; - count[1] = H5S_UNLIMITED; - count[2] = H5S_UNLIMITED; - block[0] = 2; - block[1] = 2; - block[2] = 2; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); + /* Create a chunked dataset */ + did = H5Dcreate2(fid, DNAME, H5T_NATIVE_INT, sid, H5P_DEFAULT, dcpl, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dcreate2"); - /* Try unlimited count and block */ - count[2] = 2; - block[1] = H5S_UNLIMITED; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); - } H5E_END_TRY + /* Set up hyperslab selection for file dataspace */ + offset[0] = 0; + stride[0] = 1; + count[0] = 1; + block[0] = CHUNKSZ; - /* Try operations with two unlimited selections */ - block[1] = 2; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + /* Write to each chunk in the dataset */ + for (i = 0; i < NUMCHUNKS; i++) { + /* Set the hyperslab selection */ + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, offset, stride, count, block); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - H5E_BEGIN_TRY { - ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, NULL, count, NULL); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); - ret = H5Sselect_hyperslab(sid, H5S_SELECT_AND, start, NULL, count, NULL); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); - ret = H5Sselect_hyperslab(sid, H5S_SELECT_XOR, start, NULL, count, NULL); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); - ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTB, start, NULL, count, NULL); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); - ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTA, start, NULL, count, NULL); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); - } H5E_END_TRY - /* Try invalid combination operations */ - H5E_BEGIN_TRY { - ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, NULL, block, NULL); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); - ret = H5Sselect_hyperslab(sid, H5S_SELECT_XOR, start, NULL, block, NULL); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); - ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTB, start, NULL, block, NULL); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); - } H5E_END_TRY - ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, NULL, block, NULL); - CHECK(ret, FAIL, "H5Sselect_hyperslab"); - H5E_BEGIN_TRY { - ret = H5Sselect_hyperslab(sid, H5S_SELECT_OR, start, stride, count, block); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); - ret = H5Sselect_hyperslab(sid, H5S_SELECT_XOR, start, stride, count, block); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); - ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTA, start, stride, count, block); - VERIFY(ret, FAIL, "H5Sselect_hyperslab"); - } H5E_END_TRY + /* Write to the dataset */ + ret = H5Dwrite(did, H5T_NATIVE_INT, mid, sid, H5P_DEFAULT, wdata); + CHECK(ret, FAIL, "H5Dwrite"); - /* - * Now test valid combination operations - */ - /* unlim AND non-unlim */ - count[0] = 1; - count[1] = H5S_UNLIMITED; - count[2] = 2; - block[0] = 2; - block[1] = 2; - block[2] = 2; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); - CHECK(ret, FAIL, "H5Sselect_hyperslab"); - start2[0] = 2; - start2[1] = 2; - start2[2] = 0; - count2[0] = 5; - count2[1] = 4; - count2[2] = 2; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_AND, start2, NULL, count2, NULL); - CHECK(ret, FAIL, "H5Sselect_hyperslab"); - eblock1[0] = 2; - eblock1[3] = 2; - eblock1[1] = 2; - eblock1[4] = 3; - eblock1[2] = 1; - eblock1[5] = 1; - eblock2[0] = 2; - eblock2[3] = 2; - eblock2[1] = 5; - eblock2[4] = 5; - eblock2[2] = 1; - eblock2[5] = 1; - dims[0] = 50; - dims[1] = 50; - dims[2] = 50; - test_hyper_unlim_check(sid, dims, (hssize_t)3, (hssize_t)2, eblock1, eblock2); + /* Extend the dataset's dataspace */ + if(i < (NUMCHUNKS - 1)) { + offset[0] = offset[0] + CHUNKSZ; + dims[0] = dims[0] + CHUNKSZ; + ret = H5Dset_extent(did, dims); + CHECK(ret, FAIL, "H5Dset_extent"); + + /* Get the dataset's current dataspace */ + sid = H5Dget_space(did); + CHECK(sid, H5I_INVALID_HID, "H5Dget_space"); + } + } - /* unlim NOTA non-unlim */ - count[0] = 1; - count[1] = H5S_UNLIMITED; - count[2] = 2; - block[0] = 2; - block[1] = 2; - block[2] = 2; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); - CHECK(ret, FAIL, "H5Sselect_hyperslab"); - start2[0] = 1; - start2[1] = 5; - start2[2] = 2; - count2[0] = 2; - count2[1] = 2; - count2[2] = 6; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTA, start2, NULL, count2, NULL); - CHECK(ret, FAIL, "H5Sselect_hyperslab"); - eblock1[0] = 1; - eblock1[3] = 2; - eblock1[1] = 5; - eblock1[4] = 6; - eblock1[2] = 3; - eblock1[5] = 3; - eblock2[0] = 1; - eblock2[3] = 2; - eblock2[1] = 5; - eblock2[4] = 6; - eblock2[2] = 6; - eblock2[5] = 7; - dims[0] = 50; - dims[1] = 50; - dims[2] = 50; - test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + /* Closing */ + ret = H5Sclose(sid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Sclose(mid); + CHECK(ret, FAIL, "H5Sclose"); + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Pclose(dcpl); + CHECK(ret, FAIL, "H5Pclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); - /* non-unlim AND unlim */ - start2[0] = 2; - start2[1] = 2; - start2[2] = 0; - count2[0] = 5; - count2[1] = 4; - count2[2] = 2; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start2, NULL, count2, NULL); - CHECK(ret, FAIL, "H5Sselect_hyperslab"); - count[0] = 1; - count[1] = H5S_UNLIMITED; - count[2] = 2; - block[0] = 2; - block[1] = 2; - block[2] = 2; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_AND, start, stride, count, block); - CHECK(ret, FAIL, "H5Sselect_hyperslab"); - eblock1[0] = 2; - eblock1[3] = 2; - eblock1[1] = 2; - eblock1[4] = 3; - eblock1[2] = 1; - eblock1[5] = 1; - eblock2[0] = 2; - eblock2[3] = 2; - eblock2[1] = 5; - eblock2[4] = 5; - eblock2[2] = 1; - eblock2[5] = 1; - dims[0] = 50; - dims[1] = 50; - dims[2] = 50; - test_hyper_unlim_check(sid, dims, (hssize_t)3, (hssize_t)2, eblock1, eblock2); + /* Open the file */ + fid = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, H5I_INVALID_HID, "H5Fopen"); - /* non-unlim NOTB unlim */ - start2[0] = 1; - start2[1] = 5; - start2[2] = 2; - count2[0] = 2; - count2[1] = 2; - count2[2] = 6; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start2, NULL, count2, NULL); - CHECK(ret, FAIL, "H5Sselect_hyperslab"); - count[0] = 1; - count[1] = H5S_UNLIMITED; - count[2] = 2; - block[0] = 2; - block[1] = 2; - block[2] = 2; - ret = H5Sselect_hyperslab(sid, H5S_SELECT_NOTB, start, stride, count, block); - CHECK(ret, FAIL, "H5Sselect_hyperslab"); - eblock1[0] = 1; - eblock1[3] = 2; - eblock1[1] = 5; - eblock1[4] = 6; - eblock1[2] = 3; - eblock1[5] = 3; - eblock2[0] = 1; - eblock2[3] = 2; - eblock2[1] = 5; - eblock2[4] = 6; - eblock2[2] = 6; - eblock2[5] = 7; - dims[0] = 50; - dims[1] = 50; - dims[2] = 50; - test_hyper_unlim_check(sid, dims, (hssize_t)12, (hssize_t)2, eblock1, eblock2); + /* Open the dataset */ + did = H5Dopen2(fid, DNAME, H5P_DEFAULT); + CHECK(did, H5I_INVALID_HID, "H5Dopen"); - /* Test H5Sget_select_npoints() */ - ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, start, stride, count, block); + /* Set up to read every 10th element in file dataspace */ + offset[0] = 1; + stride[0] = 10; + count[0] = NUM_ELEMENTS/10; + block[0] = 1; + + /* Get the dataset's dataspace */ + sid = H5Dget_space(did); + CHECK(sid, H5I_INVALID_HID, "H5Pcreate"); + ret = H5Sselect_hyperslab(sid, H5S_SELECT_SET, offset, stride, count, block); CHECK(ret, FAIL, "H5Sselect_hyperslab"); - ssize_out = H5Sget_select_npoints(sid); - VERIFY(ssize_out, (hssize_t)H5S_UNLIMITED, "H5Sget_select_npoints"); - /* Test H5Sget_select_hyper_nblocks() */ - ssize_out = H5Sget_select_hyper_nblocks(sid); - VERIFY(ssize_out, (hssize_t)H5S_UNLIMITED, "H5Sget_select_hyper_nblocks"); + /* Set up contiguous memory dataspace for the selected elements */ + dimsm[0] = count[0]; + mid = H5Screate_simple(RANK, dimsm, NULL); + CHECK(mid, H5I_INVALID_HID, "H5Screate"); - /* Test H5Sget_select_bounds() */ - ret = H5Sget_select_bounds(sid, start2, count2); - CHECK(ret, FAIL, "H5Sget_select_bounds"); - VERIFY(start2[0], start[0], "H5Sget_select_bounds"); - VERIFY(start2[1], start[1], "H5Sget_select_bounds"); - VERIFY(start2[2], start[2], "H5Sget_select_bounds"); - VERIFY(count2[0], (long)(start[0] + (stride[0] * (count[0] - 1)) + block[0] - 1), "H5Sget_select_bounds"); - VERIFY(count2[1], H5S_UNLIMITED, "H5Sget_select_bounds"); - VERIFY(count2[2], (long)(start[2] + (stride[2] * (count[2] - 1)) + block[2] - 1), "H5Sget_select_bounds"); + /* Read all the selected 10th elements in the dataset into "rdata" */ + ret = H5Dread(did, H5T_NATIVE_INT, mid, sid, H5P_DEFAULT, rdata); + CHECK(ret, FAIL, "H5Dread"); - /* Close the dataspace */ + /* Verify data read is correct */ + for(i = 0; i < 6; i += 2) { + VERIFY(rdata[i], 1, "H5Dread\n"); + VERIFY(rdata[i+1], 11, "H5Dread\n"); + } + + /* Closing */ + ret = H5Sclose(mid); + CHECK(ret, FAIL, "H5Sclose"); ret = H5Sclose(sid); CHECK(ret, FAIL, "H5Sclose"); -} /* end test_hyper_unlim() */ + ret = H5Dclose(did); + CHECK(ret, FAIL, "H5Dclose"); + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); + +} /* test_hyper_io_1d() */ + /**************************************************************** ** ** test_select(): Main H5S selection testing routine. @@ -13676,10 +15267,12 @@ test_select(void) test_select_hyper_offset2();/* Test more selection offset code with hyperslabs */ test_select_point_offset(); /* Test selection offset code with elements */ test_select_hyper_union(); /* Test hyperslab union code */ -#ifdef NEW_HYPERSLAB_API + + /* Fancy hyperslab API tests */ test_select_hyper_union_stagger(); /* Test hyperslab union code for staggered slabs */ test_select_hyper_union_3d(); /* Test hyperslab union code for 3-D dataset */ -#endif /* NEW_HYPERSLAB_API */ + test_select_hyper_valid_combination(); /* Test different input combinations */ + test_select_hyper_and_2d(); /* Test hyperslab intersection (AND) code for 2-D dataset */ test_select_hyper_xor_2d(); /* Test hyperslab XOR code for 2-D dataset */ test_select_hyper_notb_2d(); /* Test hyperslab NOTB code for 2-D dataset */ @@ -13755,6 +15348,8 @@ test_select(void) /* Test "re-build" routine */ test_space_rebuild(); + /* Test "update diminfo" routine */ + test_space_update_diminfo(); /* Test point selections in chunked datasets */ test_select_point_chunk(); @@ -13775,6 +15370,18 @@ test_select(void) /* Test unlimited hyperslab selections */ test_hyper_unlim(); + /* Test the consistency of internal data structures of selection */ + test_internal_consistency(); + + /* Test irregular selection I/O */ + test_irreg_io(); + + /* Test selection intersection with block */ + test_select_intersect_block(); + + /* Test reading of 1-d disjoint file space to 1-d single block memory space */ + test_hyper_io_1d(); + } /* test_select() */ diff --git a/testpar/t_shapesame.c b/testpar/t_shapesame.c index 0eb4838..b0c4a4e 100644 --- a/testpar/t_shapesame.c +++ b/testpar/t_shapesame.c @@ -783,12 +783,12 @@ hs_dr_pio_test__takedown( struct hs_dr_pio_test_vars_t * tv_ptr) * selections of different rank in the parallel. * * Verify that we can read from disk correctly using - * selections of different rank that H5S_select_shape_same() + * selections of different rank that H5Sselect_shape_same() * views as being of the same shape. * * In this function, we test this by reading small_rank - 1 * slices from the on disk large cube, and verifying that the - * data read is correct. Verify that H5S_select_shape_same() + * data read is correct. Verify that H5Sselect_shape_same() * returns true on the memory and file selections. * * Return: void @@ -933,12 +933,11 @@ contig_hs_dr_pio_test__d2m_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) "H5Sselect_hyperslab(file_large_cube_sid) succeeded"); - /* verify that H5S_select_shape_same() reports the two + /* verify that H5Sselect_shape_same() reports the two * selections as having the same shape. */ - check = H5S_select_shape_same_test(tv_ptr->small_ds_slice_sid, - tv_ptr->file_large_ds_sid_0); - VRFY((check == TRUE), "H5S_select_shape_same_test passed"); + check = H5Sselect_shape_same(tv_ptr->small_ds_slice_sid, tv_ptr->file_large_ds_sid_0); + VRFY((check == TRUE), "H5Sselect_shape_same passed"); /* Read selection from disk */ @@ -1020,7 +1019,7 @@ contig_hs_dr_pio_test__d2m_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) * selections of different rank in the parallel. * * Verify that we can read from disk correctly using - * selections of different rank that H5S_select_shape_same() + * selections of different rank that H5Sselect_shape_same() * views as being of the same shape. * * In this function, we test this by reading slices of the @@ -1197,12 +1196,11 @@ contig_hs_dr_pio_test__d2m_s2l(struct hs_dr_pio_test_vars_t * tv_ptr) "H5Sselect_hyperslab(mem_large_ds_sid) succeeded"); - /* verify that H5S_select_shape_same() reports the two + /* verify that H5Sselect_shape_same() reports the two * selections as having the same shape. */ - check = H5S_select_shape_same_test(tv_ptr->file_small_ds_sid_0, - tv_ptr->mem_large_ds_sid); - VRFY((check == TRUE), "H5S_select_shape_same_test passed"); + check = H5Sselect_shape_same(tv_ptr->file_small_ds_sid_0, tv_ptr->mem_large_ds_sid); + VRFY((check == TRUE), "H5Sselect_shape_same passed"); /* Read selection from disk */ @@ -1299,14 +1297,14 @@ contig_hs_dr_pio_test__d2m_s2l(struct hs_dr_pio_test_vars_t * tv_ptr) * selections of different rank in the parallel. * * Verify that we can write from memory to file using - * selections of different rank that H5S_select_shape_same() + * selections of different rank that H5Sselect_shape_same() * views as being of the same shape. * * Do this by writing small_rank - 1 dimensional slices from * the in memory large data set to the on disk small cube * dataset. After each write, read the slice of the small * dataset back from disk, and verify that it contains - * the expected data. Verify that H5S_select_shape_same() + * the expected data. Verify that H5Sselect_shape_same() * returns true on the memory and file selections. * * Return: void @@ -1341,12 +1339,12 @@ contig_hs_dr_pio_test__m2d_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) /* now we go in the opposite direction, verifying that we can write * from memory to file using selections of different rank that - * H5S_select_shape_same() views as being of the same shape. + * H5Sselect_shape_same() views as being of the same shape. * * Start by writing small_rank - 1 dimensional slices from the in memory large * data set to the on disk small cube dataset. After each write, read the * slice of the small dataset back from disk, and verify that it contains - * the expected data. Verify that H5S_select_shape_same() returns true on + * the expected data. Verify that H5Sselect_shape_same() returns true on * the memory and file selections. */ @@ -1507,13 +1505,12 @@ contig_hs_dr_pio_test__m2d_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) "H5Sselect_hyperslab() mem_large_ds_sid succeeded."); - /* verify that H5S_select_shape_same() reports the in + /* verify that H5Sselect_shape_same() reports the in * memory slice through the cube selection and the * on disk full square selections as having the same shape. */ - check = H5S_select_shape_same_test(tv_ptr->file_small_ds_sid_0, - tv_ptr->mem_large_ds_sid); - VRFY((check == TRUE), "H5S_select_shape_same_test passed."); + check = H5Sselect_shape_same(tv_ptr->file_small_ds_sid_0, tv_ptr->mem_large_ds_sid); + VRFY((check == TRUE), "H5Sselect_shape_same passed."); /* write the slice from the in memory large data set to the @@ -1623,7 +1620,7 @@ contig_hs_dr_pio_test__m2d_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) * selections of different rank in the parallel. * * Verify that we can write from memory to file using - * selections of different rank that H5S_select_shape_same() + * selections of different rank that H5Sselect_shape_same() * views as being of the same shape. * * Do this by writing the contents of the process's slice of @@ -1632,7 +1629,7 @@ contig_hs_dr_pio_test__m2d_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) * slice of the large data set back into memory, and verify * that it contains the expected data. * - * Verify that H5S_select_shape_same() returns true on the + * Verify that H5Sselect_shape_same() returns true on the * memory and file selections. * * Return: void @@ -1668,7 +1665,7 @@ contig_hs_dr_pio_test__m2d_s2l(struct hs_dr_pio_test_vars_t * tv_ptr) * small data set to slices of the on disk large data set. After * each write, read the process's slice of the large data set back * into memory, and verify that it contains the expected data. - * Verify that H5S_select_shape_same() returns true on the memory + * Verify that H5Sselect_shape_same() returns true on the memory * and file selections. */ @@ -1835,14 +1832,13 @@ contig_hs_dr_pio_test__m2d_s2l(struct hs_dr_pio_test_vars_t * tv_ptr) "H5Sselect_hyperslab() target large ds slice succeeded"); - /* verify that H5S_select_shape_same() reports the in + /* verify that H5Sselect_shape_same() reports the in * memory small data set slice selection and the * on disk slice through the large data set selection * as having the same shape. */ - check = H5S_select_shape_same_test(tv_ptr->mem_small_ds_sid, - tv_ptr->file_large_ds_sid_0); - VRFY((check == TRUE), "H5S_select_shape_same_test passed"); + check = H5Sselect_shape_same(tv_ptr->mem_small_ds_sid, tv_ptr->file_large_ds_sid_0); + VRFY((check == TRUE), "H5Sselect_shape_same passed"); /* write the small data set slice from memory to the @@ -2084,12 +2080,12 @@ contig_hs_dr_pio_test__run_test(const int test_num, #endif /* CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG */ /* first, verify that we can read from disk correctly using selections - * of different rank that H5S_select_shape_same() views as being of the + * of different rank that H5Sselect_shape_same() views as being of the * same shape. * * Start by reading small_rank - 1 dimensional slice from the on disk * large cube, and verifying that the data read is correct. Verify that - * H5S_select_shape_same() returns true on the memory and file selections. + * H5Sselect_shape_same() returns true on the memory and file selections. */ #if CONTIG_HS_DR_PIO_TEST__RUN_TEST__DEBUG @@ -2115,12 +2111,12 @@ contig_hs_dr_pio_test__run_test(const int test_num, /* now we go in the opposite direction, verifying that we can write * from memory to file using selections of different rank that - * H5S_select_shape_same() views as being of the same shape. + * H5Sselect_shape_same() views as being of the same shape. * * Start by writing small_rank - 1 D slices from the in memory large data * set to the on disk small cube dataset. After each write, read the * slice of the small dataset back from disk, and verify that it contains - * the expected data. Verify that H5S_select_shape_same() returns true on + * the expected data. Verify that H5Sselect_shape_same() returns true on * the memory and file selections. */ @@ -2136,7 +2132,7 @@ contig_hs_dr_pio_test__run_test(const int test_num, * small data set to slices of the on disk large data set. After * each write, read the process's slice of the large data set back * into memory, and verify that it contains the expected data. - * Verify that H5S_select_shape_same() returns true on the memory + * Verify that H5Sselect_shape_same() returns true on the memory * and file selections. */ @@ -2932,12 +2928,12 @@ ckrbrd_hs_dr_pio_test__verify_data(uint32_t * buf_ptr, * * Verify that we can read from disk correctly using checker * board selections of different rank that - * H5S_select_shape_same() views as being of the same shape. + * H5Sselect_shape_same() views as being of the same shape. * * In this function, we test this by reading small_rank - 1 * checker board slices from the on disk large cube, and * verifying that the data read is correct. Verify that - * H5S_select_shape_same() returns true on the memory and + * H5Sselect_shape_same() returns true on the memory and * file selections. * * Return: void @@ -2969,12 +2965,12 @@ ckrbrd_hs_dr_pio_test__d2m_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) /* first, verify that we can read from disk correctly using selections - * of different rank that H5S_select_shape_same() views as being of the + * of different rank that H5Sselect_shape_same() views as being of the * same shape. * * Start by reading a (small_rank - 1)-D checker board slice from this * processes slice of the on disk large data set, and verifying that the - * data read is correct. Verify that H5S_select_shape_same() returns + * data read is correct. Verify that H5Sselect_shape_same() returns * true on the memory and file selections. * * The first step is to set up the needed checker board selection in the @@ -3118,12 +3114,11 @@ ckrbrd_hs_dr_pio_test__d2m_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) tv_ptr->start ); - /* verify that H5S_select_shape_same() reports the two + /* verify that H5Sselect_shape_same() reports the two * selections as having the same shape. */ - check = H5S_select_shape_same_test(tv_ptr->small_ds_slice_sid, - tv_ptr->file_large_ds_sid_0); - VRFY((check == TRUE), "H5S_select_shape_same_test passed"); + check = H5Sselect_shape_same(tv_ptr->small_ds_slice_sid, tv_ptr->file_large_ds_sid_0); + VRFY((check == TRUE), "H5Sselect_shape_same passed"); /* Read selection from disk */ @@ -3203,7 +3198,7 @@ ckrbrd_hs_dr_pio_test__d2m_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) * selections of different rank in the parallel. * * Verify that we can read from disk correctly using - * selections of different rank that H5S_select_shape_same() + * selections of different rank that H5Sselect_shape_same() * views as being of the same shape. * * In this function, we test this by reading checker board @@ -3380,12 +3375,11 @@ ckrbrd_hs_dr_pio_test__d2m_s2l(struct hs_dr_pio_test_vars_t * tv_ptr) ); - /* verify that H5S_select_shape_same() reports the two + /* verify that H5Sselect_shape_same() reports the two * selections as having the same shape. */ - check = H5S_select_shape_same_test(tv_ptr->file_small_ds_sid_0, - tv_ptr->mem_large_ds_sid); - VRFY((check == TRUE), "H5S_select_shape_same_test passed"); + check = H5Sselect_shape_same(tv_ptr->file_small_ds_sid_0, tv_ptr->mem_large_ds_sid); + VRFY((check == TRUE), "H5Sselect_shape_same passed"); /* Read selection from disk */ @@ -3529,14 +3523,14 @@ ckrbrd_hs_dr_pio_test__d2m_s2l(struct hs_dr_pio_test_vars_t * tv_ptr) * * Verify that we can write from memory to file using checker * board selections of different rank that - * H5S_select_shape_same() views as being of the same shape. + * H5Sselect_shape_same() views as being of the same shape. * * Do this by writing small_rank - 1 dimensional checker * board slices from the in memory large data set to the on * disk small cube dataset. After each write, read the * slice of the small dataset back from disk, and verify * that it contains the expected data. Verify that - * H5S_select_shape_same() returns true on the memory and + * H5Sselect_shape_same() returns true on the memory and * file selections. * * Return: void @@ -3573,12 +3567,12 @@ ckrbrd_hs_dr_pio_test__m2d_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) /* now we go in the opposite direction, verifying that we can write * from memory to file using selections of different rank that - * H5S_select_shape_same() views as being of the same shape. + * H5Sselect_shape_same() views as being of the same shape. * * Start by writing small_rank - 1 D slices from the in memory large data * set to the on disk small dataset. After each write, read the slice of * the small dataset back from disk, and verify that it contains the - * expected data. Verify that H5S_select_shape_same() returns true on + * expected data. Verify that H5Sselect_shape_same() returns true on * the memory and file selections. */ @@ -3759,14 +3753,13 @@ ckrbrd_hs_dr_pio_test__m2d_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) ); - /* verify that H5S_select_shape_same() reports the in + /* verify that H5Sselect_shape_same() reports the in * memory checkerboard selection of the slice through the * large dataset and the checkerboard selection of the process * slice of the small data set as having the same shape. */ - check = H5S_select_shape_same_test(tv_ptr->file_small_ds_sid_1, - tv_ptr->mem_large_ds_sid); - VRFY((check == TRUE), "H5S_select_shape_same_test passed."); + check = H5Sselect_shape_same(tv_ptr->file_small_ds_sid_1, tv_ptr->mem_large_ds_sid); + VRFY((check == TRUE), "H5Sselect_shape_same passed."); /* write the checker board selection of the slice from the in @@ -3886,7 +3879,7 @@ ckrbrd_hs_dr_pio_test__m2d_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) * board hyperslab selections of different rank in the parallel. * * Verify that we can write from memory to file using - * selections of different rank that H5S_select_shape_same() + * selections of different rank that H5Sselect_shape_same() * views as being of the same shape. * * Do this by writing checker board selections of the contents @@ -3895,7 +3888,7 @@ ckrbrd_hs_dr_pio_test__m2d_l2s(struct hs_dr_pio_test_vars_t * tv_ptr) * read the process's slice of the large data set back into * memory, and verify that it contains the expected data. * - * Verify that H5S_select_shape_same() returns true on the + * Verify that H5Sselect_shape_same() returns true on the * memory and file selections. * * Return: void @@ -3934,7 +3927,7 @@ ckrbrd_hs_dr_pio_test__m2d_s2l(struct hs_dr_pio_test_vars_t * tv_ptr) * small data set to slices of the on disk large data set. After * each write, read the process's slice of the large data set back * into memory, and verify that it contains the expected data. - * Verify that H5S_select_shape_same() returns true on the memory + * Verify that H5Sselect_shape_same() returns true on the memory * and file selections. */ @@ -4110,14 +4103,13 @@ ckrbrd_hs_dr_pio_test__m2d_s2l(struct hs_dr_pio_test_vars_t * tv_ptr) ); - /* verify that H5S_select_shape_same() reports the in + /* verify that H5Sselect_shape_same() reports the in * memory small data set slice selection and the * on disk slice through the large data set selection * as having the same shape. */ - check = H5S_select_shape_same_test(tv_ptr->mem_small_ds_sid, - tv_ptr->file_large_ds_sid_1); - VRFY((check == TRUE), "H5S_select_shape_same_test passed"); + check = H5Sselect_shape_same(tv_ptr->mem_small_ds_sid, tv_ptr->file_large_ds_sid_1); + VRFY((check == TRUE), "H5Sselect_shape_same passed"); /* write the small data set slice from memory to the @@ -4369,12 +4361,12 @@ ckrbrd_hs_dr_pio_test__run_test(const int test_num, /* first, verify that we can read from disk correctly using selections - * of different rank that H5S_select_shape_same() views as being of the + * of different rank that H5Sselect_shape_same() views as being of the * same shape. * * Start by reading a (small_rank - 1)-D slice from this processes slice * of the on disk large data set, and verifying that the data read is - * correct. Verify that H5S_select_shape_same() returns true on the + * correct. Verify that H5Sselect_shape_same() returns true on the * memory and file selections. * * The first step is to set up the needed checker board selection in the @@ -4394,12 +4386,12 @@ ckrbrd_hs_dr_pio_test__run_test(const int test_num, /* now we go in the opposite direction, verifying that we can write * from memory to file using selections of different rank that - * H5S_select_shape_same() views as being of the same shape. + * H5Sselect_shape_same() views as being of the same shape. * * Start by writing small_rank - 1 D slices from the in memory large data * set to the on disk small dataset. After each write, read the slice of * the small dataset back from disk, and verify that it contains the - * expected data. Verify that H5S_select_shape_same() returns true on + * expected data. Verify that H5Sselect_shape_same() returns true on * the memory and file selections. */ @@ -4410,7 +4402,7 @@ ckrbrd_hs_dr_pio_test__run_test(const int test_num, * small data set to slices of the on disk large data set. After * each write, read the process's slice of the large data set back * into memory, and verify that it contains the expected data. - * Verify that H5S_select_shape_same() returns true on the memory + * Verify that H5Sselect_shape_same() returns true on the memory * and file selections. */ diff --git a/testpar/t_span_tree.c b/testpar/t_span_tree.c index 0466839..eb3b0f7 100644 --- a/testpar/t_span_tree.c +++ b/testpar/t_span_tree.c @@ -2289,11 +2289,11 @@ lower_dim_size_comp_test__run_test(const int chunk_edge_size, large_sel_start); - /* verify that H5S_select_shape_same() reports the two + /* verify that H5Sselect_shape_same() reports the two * selections as having the same shape. */ - check = H5S_select_shape_same_test(mem_large_ds_sid, file_small_ds_sid); - VRFY((check == TRUE), "H5S_select_shape_same_test passed (1)"); + check = H5Sselect_shape_same(mem_large_ds_sid, file_small_ds_sid); + VRFY((check == TRUE), "H5Sselect_shape_same passed (1)"); ret = H5Dread(small_dataset, @@ -2409,11 +2409,11 @@ lower_dim_size_comp_test__run_test(const int chunk_edge_size, large_sel_start); - /* verify that H5S_select_shape_same() reports the two + /* verify that H5Sselect_shape_same() reports the two * selections as having the same shape. */ - check = H5S_select_shape_same_test(mem_small_ds_sid, file_large_ds_sid); - VRFY((check == TRUE), "H5S_select_shape_same_test passed (2)"); + check = H5Sselect_shape_same(mem_small_ds_sid, file_large_ds_sid); + VRFY((check == TRUE), "H5Sselect_shape_same passed (2)"); ret = H5Dread(large_dataset, -- cgit v0.12