From 320eaf91b9adb36bb0fed9264d460e4a808200b7 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Thu, 14 Feb 2019 16:20:32 -0600 Subject: More changes to align with incoming selection improvements. --- fortran/src/H5Sf.c | 161 - fortran/src/H5Sff.F90 | 304 -- fortran/src/H5f90proto.h | 3 - src/H5Dmpio.c | 4 +- src/H5Sall.c | 148 +- src/H5Shyper.c | 12028 ++++++++++++++++++++------------------------- src/H5Smpio.c | 7 +- src/H5Snone.c | 116 +- src/H5Spkg.h | 4 +- src/H5Spoint.c | 279 +- src/H5Sprivate.h | 8 +- src/H5Spublic.h | 10 - src/H5Sselect.c | 87 +- test/tselect.c | 366 -- 14 files changed, 5774 insertions(+), 7751 deletions(-) diff --git a/fortran/src/H5Sf.c b/fortran/src/H5Sf.c index 2eae0d9..96540f7 100644 --- a/fortran/src/H5Sf.c +++ b/fortran/src/H5Sf.c @@ -995,167 +995,6 @@ done: } -#ifdef NEW_HYPERSLAB_API -/****if* H5Sf/h5scombine_hyperslab_c - * NAME - * h5scombine_hyperslab_c - * PURPOSE - * Call H5Scombine_hyperslab - * INPUTS - * space_id - identifier of the dataspace - * operator - defines how the new selection is combined - * start - offset of start of hyperslab - * count - number of blocks included in the hyperslab - * stride - hyperslab stride (interval between blocks) - * block - size of block in the hyperslab - * OUTPUTS - * hyper_id - identifier for the new dataspace - * RETURNS - * 0 on success, -1 on failure - * AUTHOR - * Elena Pourmal - * Monday, October 7, 2002 - * HISTORY - * - * SOURCE -*/ - -int_f -h5scombine_hyperslab_c ( hid_t_f *space_id , int_f *op, hsize_t_f *start, hsize_t_f *count, hsize_t_f *stride, hsize_t_f *block, hid_t_f *hyper_id) -/******/ -{ - int ret_value = -1; - hid_t c_space_id; - hid_t c_hyper_id; - hsize_t *c_start = NULL; - hsize_t *c_count = NULL; - hsize_t *c_stride = NULL; - hsize_t *c_block = NULL; - - H5S_seloper_t c_op; - herr_t status; - int rank; - int i; - - rank = H5Sget_simple_extent_ndims(*space_id); - if (rank < 0 ) return ret_value; - c_start = (hsize_t *)HDmalloc(sizeof(hsize_t)*rank); - if (c_start == NULL) goto DONE; - - c_count = (hsize_t *)HDmalloc(sizeof(hsize_t)*rank); - if (c_count == NULL) goto DONE; - - c_stride = (hsize_t *)HDmalloc(sizeof(hsize_t)*rank); - if (c_stride == NULL) goto DONE; - - c_block = (hsize_t *)HDmalloc(sizeof(hsize_t)*rank); - if (c_block == NULL) goto DONE; - - - /* - * Reverse dimensions due to C-FORTRAN storage order. - */ - - for (i=0; i < rank; i++) { - int t= (rank - i) - 1; - c_start[i] = (hsize_t)start[t]; - c_count[i] = (hsize_t)count[t]; - c_stride[i] = (hsize_t)stride[t]; - c_block[i] = (hsize_t)block[t]; - } - - c_op = (H5S_seloper_t)*op; - - c_space_id = (hid_t)*space_id; - c_hyper_id = H5Scombine_hyperslab(c_space_id, c_op, c_start, c_stride, c_count, c_block); - if ( c_hyper_id < 0 ) goto DONE; - *hyper_id = (hid_t_f)c_hyper_id; - ret_value = 0; -DONE: - if(c_start != NULL) HDfree(c_start); - if(c_count != NULL) HDfree(c_count); - if(c_stride!= NULL) HDfree(c_stride); - if(c_block != NULL) HDfree(c_block); - return ret_value; -} -/****if* H5Sf/h5scombine_select_c - * NAME - * h5scombine_select_c - * PURPOSE - * Call H5Scombine_ select - * INPUTS - * space1_id - identifier of the first dataspace - * operator - defines how the new selection is combined - * space2_id - identifier of the second dataspace - * OUTPUTS - * ds_id - identifier for the new dataspace - * RETURNS - * 0 on success, -1 on failure - * AUTHOR - * Elena Pourmal - * Monday, October 7, 2002 - * HISTORY - * - * SOURCE -*/ - -int_f -h5scombine_select_c ( hid_t_f *space1_id , int_f *op, hid_t_f *space2_id, hid_t_f *ds_id) -/******/ -{ - int ret_value = -1; - hid_t c_space1_id; - hid_t c_space2_id; - hid_t c_ds_id; - H5S_seloper_t c_op; - - c_op = (H5S_seloper_t)*op; - - c_space1_id = (hid_t)*space1_id; - c_space2_id = (hid_t)*space2_id; - c_ds_id = H5Scombine_select(c_space1_id, c_op, c_space2_id); - if ( c_ds_id < 0 ) return ret_value; - *ds_id = (hid_t_f)c_ds_id; - ret_value = 0; - return ret_value; -} -/****if* H5Sf/h5sselect_select_c - * NAME - * h5sselect_select_c - * PURPOSE - * Call H5Sselect_ select - * INPUTS - * space1_id - identifier of the first dataspace to modify - * operator - defines how the new selection is combined - * space2_id - identifier of the second dataspace - * RETURNS - * 0 on success, -1 on failure - * AUTHOR - * Elena Pourmal - * Monday, October 7, 2002 - * HISTORY - * - * SOURCE -*/ - -int_f -h5sselect_select_c ( hid_t_f *space1_id , int_f *op, hid_t_f *space2_id) -/******/ -{ - int ret_value = -1; - hid_t c_space1_id; - hid_t c_space2_id; - H5S_seloper_t c_op; - - c_op = (H5S_seloper_t)*op; - - c_space1_id = (hid_t)*space1_id; - c_space2_id = (hid_t)*space2_id; - if( H5Sselect_select(c_space1_id, c_op, c_space2_id)< 0) return ret_value; - ret_value = 0; - return ret_value; -} -#endif /*NEW_HYPERSLAB_API*/ /****if* H5Sf/h5sget_select_type_c * NAME * h5sget_select_type_c diff --git a/fortran/src/H5Sff.F90 b/fortran/src/H5Sff.F90 index 3434fba..3af7755 100644 --- a/fortran/src/H5Sff.F90 +++ b/fortran/src/H5Sff.F90 @@ -1275,310 +1275,6 @@ CONTAINS DEALLOCATE(def_stride) END SUBROUTINE h5sselect_hyperslab_f -! !$! -! !$!****s* H5S/h5scombine_hyperslab_f -! !$! -! !$! NAME -! !$! h5scombine_hyperslab_f -! !$! -! !$! PURPOSE -! !$! Combine a hyperslab selection with the current -! !$! selection for a dataspace -! !$! -! !$! INPUTS -! !$! space_id - dataspace of selection to use -! !$! operator - flag, valid values are: -! !$! H5S_SELECT_NOOP_F -! !$! H5S_SELECT_SET_F -! !$! H5S_SELECT_OR_F -! !$! H5S_SELECT_AND_F -! !$! H5S_SELECT_XOR_F -! !$! H5S_SELECT_NOTB_F -! !$! H5S_SELECT_NOTA_F -! !$! H5S_SELECT_APPEND_F -! !$! H5S_SELECT_PREPEND_F -! !$! start - array with hyperslab offsets -! !$! count - number of blocks included in the -! !$! hyperslab -! !$! OUTPUTS -! !$! hyper_id - identifier for the new hyperslab -! !$! hdferr: - error code -! !$! Success: 0 -! !$! Failure: -1 -! !$! OPTIONAL PARAMETERS -! !$! stride - array with hyperslab strides -! !$! block - array with hyperslab block sizes -! !$! -! !$! AUTHOR -! !$! Elena Pourmal -! !$! October 7, 2002 -! !$! -! !$! HISTORY -! !$! -! !$! -! !$! NOTES -! !$! Commented out until 1.6 ? 10/08/2002 -! !$! -! !$! SOURCE -! SUBROUTINE h5scombine_hyperslab_f(space_id, operator, start, count, & -! hyper_id, hdferr, stride, block) -! IMPLICIT NONE -! INTEGER(HID_T), INTENT(IN) :: space_id ! Dataspace identifier -! INTEGER, INTENT(IN) :: operator ! Flag, valid values are: - ! H5S_SELECT_NOOP_F - ! H5S_SELECT_SET_F - ! H5S_SELECT_OR_F - ! H5S_SELECT_AND_F - ! H5S_SELECT_XOR_F - ! H5S_SELECT_NOTB_F - ! H5S_SELECT_NOTA_F - ! H5S_SELECT_APPEND_F - ! H5S_SELECT_PREPEND_F - ! -! INTEGER(HSIZE_T), DIMENSION(*), INTENT(IN) :: start - ! Starting coordinates of the hyperslab -! INTEGER(HSIZE_T), DIMENSION(*), INTENT(IN) :: count - ! Number of blocks to select - ! from dataspace -! INTEGER(HID_T), INTENT(OUT) :: hyper_id ! New hyperslab identifier -! INTEGER, INTENT(OUT) :: hdferr ! Error code -! INTEGER(HSIZE_T), DIMENSION(:), OPTIONAL, INTENT(IN) :: stride - ! Array of how many elements to move - ! in each direction -! INTEGER(HSIZE_T), DIMENSION(:), OPTIONAL, INTENT(IN) :: block - ! Sizes of element block -! INTEGER(HSIZE_T), DIMENSION(:), ALLOCATABLE :: def_block -! INTEGER(HSIZE_T), DIMENSION(:), ALLOCATABLE :: def_stride -! INTEGER :: rank -! INTEGER :: error1, error2 - -! INTERFACE -! INTEGER FUNCTION h5scombine_hyperslab_c(space_id, operator, & -! start, count, stride, block, hyper_id) -! USE H5GLOBAL -! !DEC$IF DEFINED(HDF5F90_WINDOWS) -! !DEC$ATTRIBUTES C,reference,decorate,alias:'H5SCOMBINE_HYPERSLAB_C'::h5scombine_hyperslab_c -! !DEC$ENDIF -! INTEGER(HID_T), INTENT(IN) :: space_id -! INTEGER, INTENT(IN) :: operator -! INTEGER(HSIZE_T), DIMENSION(*), INTENT(IN) :: start -! INTEGER(HSIZE_T), DIMENSION(*), INTENT(IN) :: count -! INTEGER(HSIZE_T), DIMENSION(*), OPTIONAL, INTENT(IN) :: stride -! INTEGER(HSIZE_T), DIMENSION(*), OPTIONAL, INTENT(IN) :: block -! INTEGER(HID_T), INTENT(OUT) :: hyper_id -! END FUNCTION h5scombine_hyperslab_c -! END INTERFACE - -! if (present(stride).and. present(block)) then -! hdferr = h5scombine_hyperslab_c(space_id, operator, start, count, & -! stride, block, hyper_id) -! return -! endif - ! Case of optional parameters. - ! - ! Find the rank of the dataspace to allocate memory for - ! default stride and block arrays. - ! -! CALL h5sget_simple_extent_ndims_f(space_id, rank, hdferr) -! if( hdferr .EQ. -1) return - ! -! if (present(stride).and. .not.present(block)) then -! allocate(def_block(rank), stat=error1) -! if (error1.NE.0) then -! hdferr = -1 -! return -! endif -! def_block = 1 -! hdferr = h5scombine_hyperslab_c(space_id, operator, start, count, & -! stride, def_block, hyper_id) -! deallocate(def_block) -! return -! endif - -! if (.not.present(stride).and. present(block)) then -! allocate(def_stride(rank), stat=error2) -! if (error2.NE.0) then -! hdferr = -1 -! return -! endif -! def_stride = 1 -! hdferr = h5scombine_hyperslab_c(space_id, operator, start, count, & -! def_stride, block, hyper_id) -! deallocate(def_stride) -! return -! endif -! allocate(def_block(rank), stat=error1) -! allocate(def_stride(rank), stat=error2) -! if ((error1.NE.0) .OR. (error2.NE.0)) then -! hdferr = -1 -! return -! endif -! def_block = 1 -! def_stride = 1 -! hdferr = h5scombine_hyperslab_c(space_id, operator, start, count, & -! def_stride, def_block, hyper_id) -! deallocate(def_block) -! deallocate(def_stride) - -! END SUBROUTINE h5scombine_hyperslab_f - -! !$! -! !$!****s* H5S/ -! !$! -! !$! NAME -! !$! h5scombine_select_f -! !$! -! !$! PURPOSE -! !$! Combine two hyperslab selections with an operation -! !$! and return a dataspace with resulting selection. -! !$! -! !$! INPUTS -! !$! space1_id - dataspace of selection to use -! !$! operator - flag, valid values are: -! !$! H5S_SELECT_NOOP_F -! !$! H5S_SELECT_SET_F -! !$! H5S_SELECT_OR_F -! !$! H5S_SELECT_AND_F -! !$! H5S_SELECT_XOR_F -! !$! H5S_SELECT_NOTB_F -! !$! H5S_SELECT_NOTA_F -! !$! H5S_SELECT_APPEND_F -! !$! H5S_SELECT_PREPEND_F -! !$! space2_id - dataspace of selection to use -! !$! OUTPUTS -! !$! ds_id - idataspace identifier with the new selection -! !$! hdferr: - error code -! !$! Success: 0 -! !$! Failure: -1 -! !$! OPTIONAL PARAMETERS - NONE -! !$! -! !$! AUTHOR -! !$! Elena Pourmal -! !$! October 7, 2002 -! !$! -! !$! HISTORY -! !$! -! !$! -! !$! NOTES commented out until 1.6 release(?) 10/08/2002 -! !$! - -! ! SOURCE -! !$ SUBROUTINE h5scombine_select_f(space1_id, operator, space2_id, & -! ds_id, hdferr) -! IMPLICIT NONE -! INTEGER(HID_T), INTENT(IN) :: space1_id ! First dataspace identifier -! INTEGER(HID_T), INTENT(IN) :: space2_id ! Second dataspace identifier -! INTEGER, INTENT(IN) :: operator ! Flag, valid values are: - ! H5S_SELECT_NOOP_F - ! H5S_SELECT_SET_F - ! H5S_SELECT_OR_F - ! H5S_SELECT_AND_F - ! H5S_SELECT_XOR_F - ! H5S_SELECT_NOTB_F - ! H5S_SELECT_NOTA_F - ! H5S_SELECT_APPEND_F - ! H5S_SELECT_PREPEND_F - ! -! INTEGER(HID_T), INTENT(OUT) :: ds_id ! New dataspace identifier -! INTEGER, INTENT(OUT) :: hdferr ! Error code -! -! INTERFACE -! INTEGER FUNCTION h5scombine_select_c(space1_id, operator, & -! space2_id, ds_id) -! USE H5GLOBAL -! !DEC$IF DEFINED(HDF5F90_WINDOWS) -! !DEC$ATTRIBUTES C,reference,decorate,alias:'H5SCOMBINE_SELECT_C'::h5scombine_select_c -! !DEC$ENDIF -! INTEGER(HID_T), INTENT(IN) :: space1_id -! INTEGER(HID_T), INTENT(IN) :: space2_id -! INTEGER, INTENT(IN) :: operator -! INTEGER(HID_T), INTENT(OUT) :: ds_id -! END FUNCTION h5scombine_select_c -! END INTERFACE - -! hdferr = h5scombine_select_c(space1_id, operator, space2_id, & -! ds_id) -! return - -! END SUBROUTINE h5scombine_select_f - -! !$! -! !$!****s* H5S/ -! !$! -! !$! NAME -! !$! h5sselect_select_f -! !$! -! !$! PURPOSE -! !$! Refine a hyperslab selection with an operation -! !$! using second hyperslab -! !$! -! !$! INPUTS -! !$! space1_id - dataspace of selection to modify -! !$! operator - flag, valid values are: -! !$! H5S_SELECT_NOOP_F -! !$! H5S_SELECT_SET_F -! !$! H5S_SELECT_OR_F -! !$! H5S_SELECT_AND_F -! !$! H5S_SELECT_XOR_F -! !$! H5S_SELECT_NOTB_F -! !$! H5S_SELECT_NOTA_F -! !$! H5S_SELECT_APPEND_F -! !$! H5S_SELECT_PREPEND_F -! !$! space2_id - dataspace of selection to use -! !$! -! !$! OUTPUTS -! !$! hdferr: - error code -! !$! Success: 0 -! !$! Failure: -1 -! !$! OPTIONAL PARAMETERS - NONE -! !$! -! !$! AUTHOR -! !$! Elena Pourmal -! !$! October 7, 2002 -! !$! -! !$! HISTORY -! !$! -! !$! -! !$! NOTESCommented out until 1.6 release(?) 10/08/2002 EIP -! !$! - -! ! SOURCE -! SUBROUTINE h5sselect_select_f(space1_id, operator, space2_id, & -! hdferr) -! IMPLICIT NONE -! INTEGER(HID_T), INTENT(INOUT) :: space1_id ! Dataspace identifier to - ! modify -! INTEGER(HID_T), INTENT(IN) :: space2_id ! Second dataspace identifier -! INTEGER, INTENT(IN) :: operator ! Flag, valid values are: - ! H5S_SELECT_NOOP_F - ! H5S_SELECT_SET_F - ! H5S_SELECT_OR_F - ! H5S_SELECT_AND_F - ! H5S_SELECT_XOR_F - ! H5S_SELECT_NOTB_F - ! H5S_SELECT_NOTA_F - ! H5S_SELECT_APPEND_F - ! H5S_SELECT_PREPEND_F - ! -! INTEGER, INTENT(OUT) :: hdferr ! Error code - -! INTERFACE -! INTEGER FUNCTION h5sselect_select_c(space1_id, operator, & -! space2_id) -! USE H5GLOBAL -! !DEC$IF DEFINED(HDF5F90_WINDOWS) -! !DEC$ATTRIBUTES C,reference,decorate,alias:'H5SSELECT_SELECT_C'::h5sselect_select_c -! !DEC$ENDIF -! INTEGER(HID_T), INTENT(INOUT) :: space1_id -! INTEGER(HID_T), INTENT(IN) :: space2_id -! INTEGER, INTENT(IN) :: operator -! END FUNCTION h5sselect_select_c -! END INTERFACE - -! hdferr = h5sselect_select_c(space1_id, operator, space2_id) -! return - -! END SUBROUTINE h5sselect_select_f ! !****s* H5S/h5sget_select_type_f diff --git a/fortran/src/H5f90proto.h b/fortran/src/H5f90proto.h index 56b7f22..fada004 100644 --- a/fortran/src/H5f90proto.h +++ b/fortran/src/H5f90proto.h @@ -120,9 +120,6 @@ H5_FCDLL int_f h5sset_extent_none_c( hid_t_f *space_id ); H5_FCDLL int_f h5sselect_hyperslab_c( hid_t_f *space_id , int_f *op, hsize_t_f *start, hsize_t_f *count, hsize_t_f *stride, hsize_t_f *block); H5_FCDLL int_f h5sget_select_type_c( hid_t_f *space_id , int_f *op); H5_FCDLL int_f h5sselect_elements_c( hid_t_f *space_id , int_f *op, size_t_f *nelements, hsize_t_f *coord); -H5_FCDLL int_f h5scombine_hyperslab_c( hid_t_f *space_id , int_f *op, hsize_t_f *start, hsize_t_f *count, hsize_t_f *stride, hsize_t_f *block, hid_t_f *hyper_id); -H5_FCDLL int_f h5scombine_select_c( hid_t_f *space1_id , int_f *op, hid_t_f *space2_id, hid_t_f *ds_id); -H5_FCDLL int_f h5sselect_select_c( hid_t_f *space1_id , int_f *op, hid_t_f *space2_id); H5_FCDLL int_f h5sdecode_c( _fcd buf, hid_t_f *obj_id ); H5_FCDLL int_f h5sencode_c(_fcd buf, hid_t_f *obj_id, size_t_f *nalloc ); H5_FCDLL int_f h5sextent_equal_c( hid_t_f * space1_id, hid_t_f *space2_id, hid_t_f *c_equal); diff --git a/src/H5Dmpio.c b/src/H5Dmpio.c index 01cf932..2a6c05f 100644 --- a/src/H5Dmpio.c +++ b/src/H5Dmpio.c @@ -2869,7 +2869,7 @@ H5D__chunk_redistribute_shared_chunks(const H5D_io_info_t *io_info, const H5D_ty 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, chunk_info->mspace, 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 */ @@ -3214,7 +3214,7 @@ H5D__filtered_collective_chunk_entry_io(H5D_filtered_collective_io_info_t *chunk 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, chunk_info->mspace, 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) diff --git a/src/H5Sall.c b/src/H5Sall.c index 76181d1..0aa2f05 100644 --- a/src/H5Sall.c +++ b/src/H5Sall.c @@ -362,6 +362,80 @@ H5S__all_iter_next_block(H5S_sel_iter_t H5_ATTR_UNUSED *iter) /*-------------------------------------------------------------------------- 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() */ + + +/*-------------------------------------------------------------------------- + NAME H5S__all_iter_release PURPOSE Release "all" selection iterator information for a dataspace @@ -993,77 +1067,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 e9354ca..c9fab38 100644 --- a/src/H5Shyper.c +++ b/src/H5Shyper.c @@ -80,9 +80,6 @@ static herr_t H5S__hyper_generate_spans(H5S_t *space); 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[]); -#ifdef NEW_HYPERSLAB_API -static herr_t H5S_select_select (H5S_t *space1, H5S_seloper_t op, H5S_t *space2); -#endif /*NEW_HYPERSLAB_API*/ 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, @@ -1082,8161 +1079,7036 @@ H5S__hyper_iter_next_block(H5S_sel_iter_t *iter) /*-------------------------------------------------------------------------- NAME - H5S__hyper_iter_release + H5S__hyper_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_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 + 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_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) { + 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 */ + FUNC_ENTER_STATIC_NOERR /* Check args */ + HDassert(space); 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); + /* Set the rank of the fastest changing dimension */ + ndims = space->extent.rank; + fast_dim = (ndims - 1); - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_iter_release() */ + /* 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; - -/*-------------------------------------------------------------------------- - 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 */ + /* 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; - FUNC_ENTER_STATIC + /* 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]; + } /* end for */ - /* 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++) + /* Compute the sequential element offset */ + loc_off += ((hsize_t)((hssize_t)abs_arr[u] + off_arr[u])) * slab[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; + /* Range check against number of elements left in selection */ + HDassert(io_bytes_left <= (iter->elmt_left * elem_size)); - /* Increment the reference count of the 'down span' if there is one */ - if(ret_value->down) - ret_value->down->count++; + /* 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 */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_new_span() */ + /* 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); - -/*-------------------------------------------------------------------------- - 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 + /* Check number of bytes against upper bounds allowed */ + if(span_size > io_bytes_left) + span_size = io_bytes_left; - /* 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_bytes_left -= span_size; - /* 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_bytes_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; + } /* end if */ + } /* end if */ + else { + /* Advance the hyperslab iterator */ + abs_arr[fast_dim] += span_size / elem_size; - 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) { + iter->u.hyp.span[fast_dim] = curr_span; + } /* end if */ + /* If we walked off that span, advance to the next span */ + else { + /* Advance span in this dimension */ + curr_span = curr_span->next; - -/*-------------------------------------------------------------------------- - 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 + /* 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 */ - HDassert(spans); + /* Adjust iterator pointers */ - /* Call the helper routine to actually do the work */ - H5S__hyper_span_precompute_helper(spans, elmt_size); + if(NULL == curr_span) { +/* Same as code in main loop */ + /* Start at the next fastest dim */ + curr_dim = (int)(fast_dim - 1); - /* Reset the scratch pointers for the next routine which needs them */ - H5S__hyper_span_scratch(spans); + /* Work back up through the dimensions */ + while(curr_dim >= 0) { + /* Reset the current span */ + curr_span = iter->u.hyp.span[curr_dim]; - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_span_precompute() */ + /* Increment absolute position */ + abs_arr[curr_dim]++; - -/*-------------------------------------------------------------------------- - 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 - - HDassert(spans); + /* 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 we've already set this down span tree */ - if(spans->scratch != NULL) { - H5S_hyper_span_t *span; /* Hyperslab span */ + /* 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; - /* Reset the tree's scratch pointer */ - spans->scratch = NULL; + /* Reset absolute position */ + abs_arr[curr_dim] = curr_span->low; - /* 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 */ + else + /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */ + curr_dim--; + } /* end else */ + } /* end while */ - /* Advance to next span */ - span = span->next; - } /* end while */ - } /* end if */ + /* 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); - FUNC_LEAVE_NOAPI_VOID -} /* end H5S__hyper_span_scratch() */ + /* Increment current dimension */ + curr_dim++; - -/*-------------------------------------------------------------------------- - 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 */ + /* Set the new span_info & span for this dimension */ + iter->u.hyp.span[curr_dim] = curr_span->down->head; - FUNC_ENTER_STATIC + /* Advance span down the tree */ + curr_span = curr_span->down->head; - /* Sanity checks */ - HDassert(spans); - HDassert(spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)); + /* Reset the absolute offset for the dim */ + abs_arr[curr_dim] = curr_span->low; + } /* end while */ - /* 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; + /* Verify that the curr_span points to the fastest dim */ + HDassert(curr_span == iter->u.hyp.span[fast_dim]); - /* Increment the reference count of the span tree */ - ret_value->count++; + /* 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 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 */ - 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") - /* Copy the span_info information */ - ret_value->count = 1; + /* 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); - /* Set the scratch pointer in the node being copied to the newly allocated node */ - spans->scratch = ret_value; + /* Adjust location offset of destination to compensate for initial increment below */ + loc_off -= curr_span->pstride; - /* 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") + /* Loop over all the spans in the fastest changing dimension */ + while(curr_span != NULL) { + /* Move location offset of destination */ + loc_off += curr_span->pstride; - /* Append to list of spans */ - if(NULL == prev_span) - ret_value->head = new_span; - else - prev_span->next = new_span; + /* Compute the number of elements to attempt in this span */ + H5_CHECKED_ASSIGN(span_size, size_t, curr_span->nelem, hsize_t); - /* Copy the pstride */ - new_span->pstride = span->pstride; + /* 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; - /* 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 */ +/* COMMON */ + /* Store the I/O information for the span */ - /* Update the previous (new) span */ - prev_span = new_span; + /* 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; - /* Advance to next span */ - span = span->next; - } /* end while */ - } /* end else */ + /* Increment the number of sequences in arrays */ + curr_seq++; + } /* end else */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_copy_span_helper() */ + /* Set the location of the last span's end */ + last_span_end = loc_off + span_size; +/* end COMMON */ - -/*-------------------------------------------------------------------------- - 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 - Non-negative on success, negative 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 */ + /* 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_STATIC +/* COMMON */ + /* Store the I/O information for the span */ - /* Sanity check */ - HDassert(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; - /* 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") + /* Increment the number of sequences in arrays */ + curr_seq++; + } /* end else */ - /* Reset the scratch pointers for the next routine which needs them */ - H5S__hyper_span_scratch(spans); + /* Set the location of the last span's end */ + last_span_end = loc_off + span_size; +/* end COMMON */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_copy_span() */ + /* If the sequence & offset arrays are full, do what? */ + if(curr_seq >= maxseq) + /* Break out now, we are finished with sequences */ + break; + } /* end else */ - -/*-------------------------------------------------------------------------- - 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 */ + /* Move to next span in fastest changing dimension */ + curr_span = curr_span->next; + } /* end while */ - FUNC_ENTER_STATIC_NOERR + /* 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); - /* Check for redundant comparison (or both spans being NULL) */ - if(span_info1 == span_info2) - ret_value = TRUE; - else { - /* Check for one span being NULL */ - if(span_info1 == NULL || span_info2 == NULL) - ret_value = FALSE; - else { - const H5S_hyper_span_t *span1; - const H5S_hyper_span_t *span2; + /* 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 */ + else { + /* Advance span in this dimension */ + curr_span = curr_span->next; - /* Get the pointers to the actual lists of spans */ - span1 = span_info1->head; - span2 = span_info2->head; + /* 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 */ + } /* end else */ + } /* end if */ - /* Sanity checking */ - HDassert(span1); - HDassert(span2); + /* 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; + } /* 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; - /* 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 */ + else + /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */ + curr_dim--; + } /* end else */ + } /* end while */ - /* Advance to the next nodes in the span list */ - span1 = span1->next; - span2 = span2->next; - } /* end while */ - } /* end else */ - } /* end else */ + /* 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); - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_cmp_spans() */ + /* Increment current dimension to the next dimension down */ + curr_dim++; - -/*-------------------------------------------------------------------------- - 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 */ + /* Set the new span for the next dimension down */ + iter->u.hyp.span[curr_dim] = curr_span->down->head; - FUNC_ENTER_STATIC + /* Advance span down the tree */ + curr_span = curr_span->down->head; - HDassert(span_info); + /* Reset the absolute offset for the dim */ + abs_arr[curr_dim] = curr_span->low; + } /* end while */ - /* Decrement the span tree's reference count */ - span_info->count--; + /* Verify that the curr_span points to the fastest dim */ + HDassert(curr_span == iter->u.hyp.span[fast_dim]); + } /* end else */ - /* Free the span tree if the reference count drops to zero */ - if(span_info->count == 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]; + } /* end while */ - /* 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; - } /* end while */ + /* Decrement number of elements left in iterator */ + io_used = (io_left - (io_bytes_left / elem_size)); + iter->elmt_left -= io_used; - /* Free this span info */ - span_info = H5FL_FREE(H5S_hyper_span_info_t, span_info); - } /* end if */ + /* Set the number of sequences generated */ + *nseq = curr_seq; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_free_span_info() */ + /* Set the number of elements used */ + *nelem = io_used; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_get_seq_list_gen() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_free_span + H5S__hyper_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_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 + 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_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) { - herr_t ret_value = SUCCEED; - - FUNC_ENTER_STATIC - - HDassert(span); - - /* 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") - - /* Free this span */ - span = H5FL_FREE(H5S_hyper_span_t, span); - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_free_span() */ - - -/*-------------------------------------------------------------------------- - 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. - - 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 */ - - FUNC_ENTER_STATIC + 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 */ - /* Sanity check */ - HDassert(src); - HDassert(dst); + FUNC_ENTER_STATIC_NOERR - /* 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") + /* Check args */ + HDassert(space); + HDassert(iter); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); - /* Set temporary pointers */ - dst_hslab = dst->select.sel_info.hslab; - src_hslab = src->select.sel_info.hslab; + /* Set the local copy of the diminfo pointer */ + tdiminfo = iter->u.hyp.diminfo; - /* Copy the hyperslab information */ - dst_hslab->diminfo_valid = src_hslab->diminfo_valid; - if(src_hslab->diminfo_valid) { - size_t u; /* Local index variable */ + /* 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; - for(u=0; uextent.rank; u++) { - dst_hslab->opt_diminfo[u]=src_hslab->opt_diminfo[u]; - dst_hslab->app_diminfo[u]=src_hslab->app_diminfo[u]; - } /* end for */ - } /* end if */ - dst->select.sel_info.hslab->span_lst=src->select.sel_info.hslab->span_lst; + /* Set the local copy of the selection offset */ + sel_off = iter->u.hyp.sel_off; - /* 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 - /* Copy the hyperslab span information */ - dst->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(src->select.sel_info.hslab->span_lst); + /* Set up the pointer to the size of the memory space */ + mem_size = iter->u.hyp.size; } /* end if */ - else - dst->select.sel_info.hslab->span_lst = NULL; + else { + /* Set the aliases for a few important dimension ranks */ + ndims = space->extent.rank; + fast_dim = ndims - 1; - /* 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; + /* Set the local copy of the selection offset */ + sel_off = space->select.offset; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_copy() */ + /* Set up the pointer to the size of the memory space */ + mem_size = space->extent.size; + } /* end else */ - -/*-------------------------------------------------------------------------- - 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 */ + /* 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 */ - FUNC_ENTER_STATIC_NOERR + /* 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); - HDassert(spans); - HDassert(offset); - HDassert(size); + /* 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))); - /* 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) + /* 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. + */ - /* 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) + /* Keep the number of elements we started with */ + start_io_left = io_left; - /* Advance to next node */ - curr = curr->next; - } /* end while */ + /* Compute the arrays to perform I/O on */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_is_valid_helper() */ + /* 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]); - -/*-------------------------------------------------------------------------- - 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 */ + /* 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 */ - FUNC_ENTER_STATIC_NOERR + /* Compute the initial buffer offset */ + for(u = 0, loc = 0; u < ndims; u++) + loc += offset[u] * slab[u]; - HDassert(space); + /* Set the number of elements to write each time */ + H5_CHECKED_ASSIGN(actual_elem, size_t, tdiminfo[fast_dim].block, hsize_t); - /* Check for unlimited selection */ - if(space->select.sel_info.hslab->unlim_dim >= 0) - HGOTO_DONE(FALSE) + /* Set the number of actual bytes */ + actual_bytes = actual_elem * elem_size; - /* Check for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid) { - const H5S_hyper_dim_t *diminfo=space->select.sel_info.hslab->opt_diminfo; /* local alias for diminfo */ - hssize_t end; /* The high bound of a region in a dimension */ - unsigned u; /* Counter */ + /* 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]); - /* 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) + /* 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); - /* 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]; + /* Don't go over the maximum number of sequences allowed */ + tot_blk_count = MIN(tot_blk_count, (maxseq - curr_seq)); - /* 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); + /* 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]; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_is_valid() */ + /* Compute the amount to skip between blocks */ + for(u = 0; u < ndims; u++) + skip[u] = (tdiminfo[u].stride - tdiminfo[u].block) * slab[u]; - -/*-------------------------------------------------------------------------- - 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 - RETURNS - Number of blocks in span tree on success; negative on failure - DESCRIPTION - Counts the number of blocks described by the spans in a span tree. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static hsize_t -H5S__hyper_span_nblocks(const H5S_hyper_span_info_t *spans) -{ - hsize_t ret_value = 0; /* Return value */ + /* 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); - FUNC_ENTER_STATIC_NOERR + /* Make certain this entire row will fit into buffer */ + fast_dim_count = MIN(fast_dim_count, tot_blk_count); - /* Count the number of elements in the span tree */ - if(spans != NULL) { - H5S_hyper_span_t *span; /* Hyperslab span */ + /* Number of blocks to sequence over */ + act_blk_count = fast_dim_count; - span = spans->head; - 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 */ - else - ret_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; - /* Advance to next span */ - span = span->next; + /* 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 */ - } /* end else */ - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_span_nblocks() */ + /* Decrement number of elements left */ + io_left -= actual_elem * act_blk_count; - -/*-------------------------------------------------------------------------- - NAME - H5S__get_select_hyper_nblocks - PURPOSE - Get the number of hyperslab blocks in current hyperslab selection - USAGE - hsize_t H5S__get_select_hyper_nblocks(space) - H5S_t *space; IN: Dataspace ptr of selection to query - RETURNS - The number of hyperslab blocks in selection on success, negative on failure - DESCRIPTION - Returns the number of hyperslab blocks in current selection for dataspace. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static hsize_t -H5S__get_select_hyper_nblocks(const H5S_t *space) -{ - hsize_t ret_value = 0; /* Return value */ + /* Decrement number of blocks left */ + tot_blk_count -= act_blk_count; - FUNC_ENTER_STATIC_NOERR + /* Increment information to reflect block just processed */ + tmp_count[fast_dim] += act_blk_count; - HDassert(space); - HDassert(space->select.sel_info.hslab->unlim_dim < 0); + /* 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 for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid) { - unsigned u; /* Local index variable */ + /* 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; - /* Check each dimension */ - for(ret_value = 1, u = 0; u < space->extent.rank; u++) - ret_value *= space->select.sel_info.hslab->app_diminfo[u].count; + /* 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 */ - 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() */ + /* 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); - -/*-------------------------------------------------------------------------- - NAME - H5Sget_select_hyper_nblocks - PURPOSE - Get the number of hyperslab blocks in current hyperslab selection - USAGE - hssize_t H5Sget_select_hyper_nblocks(dsid) - hid_t dsid; IN: Dataspace ID of selection to query - RETURNS - The number of hyperslab blocks in selection on success, negative on failure - DESCRIPTION - Returns the number of hyperslab blocks in current selection for dataspace. - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -hssize_t -H5Sget_select_hyper_nblocks(hid_t spaceid) -{ - H5S_t *space; /* Dataspace to modify selection of */ - hssize_t ret_value; /* return value */ + /* Reset copy of number of blocks in fastest dimension */ + H5_CHECKED_ASSIGN(fast_dim_count, size_t, tdiminfo[fast_dim].count, hsize_t); - FUNC_ENTER_API(FAIL) - H5TRACE1("Hs", "i", spaceid); + /* Read in data until an entire sequence can't be written out any longer */ + while(curr_rows > 0) { - /* 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") +#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; - ret_value = (hssize_t)H5S__get_select_hyper_nblocks(space); +#ifdef NO_DUFFS_DEVICE + /* Loop over all the blocks in the fastest changing dimension */ + while(fast_dim_count > 0) { + DUFF_GUTS -done: - FUNC_LEAVE_API(ret_value) -} /* end H5Sget_select_hyper_nblocks() */ + /* Decrement number of blocks */ + fast_dim_count--; + } /* end while */ +#else /* NO_DUFFS_DEVICE */ + { + size_t duffs_index; /* Counting index for Duff's device */ - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_serial_size - PURPOSE - Determine the number of bytes needed to store the serialized hyperslab - selection information. - USAGE - hssize_t H5S__hyper_serial_size(space) - H5S_t *space; IN: Dataspace pointer to query - RETURNS - The number of bytes required on success, negative on an error. - DESCRIPTION - 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 ---------------------------------------------------------------------------*/ -static hssize_t -H5S__hyper_serial_size(const H5S_t *space) -{ - hsize_t block_count; /* block counter for regular hyperslabs */ - unsigned u; /* Counter */ - hssize_t ret_value = -1; /* return value */ + 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 + case 7: + DUFF_GUTS + case 6: + DUFF_GUTS + case 5: + DUFF_GUTS + case 4: + DUFF_GUTS + case 3: + DUFF_GUTS + case 2: + DUFF_GUTS + case 1: + DUFF_GUTS + } while (--duffs_index > 0); + } /* end switch */ + } +#endif /* NO_DUFFS_DEVICE */ +#undef DUFF_GUTS - FUNC_ENTER_STATIC_NOERR + /* Increment offset in destination buffer */ + loc += wrap[fast_dim]; - HDassert(space); + /* 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]++; - /* Check for version (right now, an unlimited dimension is the only thing - * that would bump the version) */ - if(space->select.sel_info.hslab->unlim_dim >= 0) - /* Version 2 */ - /* Size required is always: - * + + + - * + + - * (4 (start/stride/count/block) * * ) = - * 17 + (4 * rank * 8) bytes - */ - ret_value = (hssize_t)17 + ((hssize_t)4 * (hssize_t)space->extent.rank - * (hssize_t)8); - else { - /* Version 1 */ - /* Basic number of bytes required to serialize hyperslab selection: - * + + + - * + + <# of blocks (4 bytes)> - * = 24 bytes - */ - ret_value = 24; + /* 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 for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid) { - /* Check each dimension */ - for(block_count = 1, u = 0; u < space->extent.rank; u++) - block_count *= space->select.sel_info.hslab->opt_diminfo[u].count; - } /* end if */ - else - /* Spin through hyperslab spans, adding 8 * rank bytes for each block */ - block_count = H5S__hyper_span_nblocks(space->select.sel_info.hslab->span_lst); + /* 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 */ - H5_CHECK_OVERFLOW((8 * space->extent.rank * block_count), hsize_t, hssize_t); - ret_value += (hssize_t)(8 * block_count * space->extent.rank); - } /* end else */ + /* Decrement dimension count */ + temp_dim--; + } /* end while */ - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_serial_size() */ + /* Decrement the number of rows left */ + curr_rows--; + } /* end while */ - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_serialize_helper - PURPOSE - Serialize the current selection into a user-provided buffer. - 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 - RETURNS - None - DESCRIPTION - Serializes the current element selection into a buffer. (Primarily for - storing on disk). - 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) -{ - H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */ - uint8_t *pp = (*p); /* Local pointer for decoding */ + /* Adjust the number of blocks & elements left to transfer */ - FUNC_ENTER_STATIC_NOERR + /* 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 checks */ - HDassert(spans); - HDassert(start); - HDassert(end); - HDassert(rank < H5S_MAX_RANK); - HDassert(p && pp); + /* 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); - /* 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; + /* 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; - /* Recurse down to the next dimension */ - H5S__hyper_serialize_helper(curr->down, start, end, rank + 1, &pp); - } /* end if */ - else { - hsize_t u; /* Index variable */ + /* 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; - /* Encode all the previous dimensions starting & ending points */ + /* Increment sequence count */ + curr_seq++; - /* Encode previous starting points */ - for(u = 0; u < rank; u++) - UINT32ENCODE(pp, (uint32_t)start[u]); + /* Increment information to reflect block just processed */ + loc += fast_dim_buf_off; - /* Encode starting point for this span */ - UINT32ENCODE(pp, (uint32_t)curr->low); + /* Decrement number of blocks */ + fast_dim_count--; + } /* end while */ - /* Encode previous ending points */ - for(u = 0; u < rank; u++) - UINT32ENCODE(pp, (uint32_t)end[u]); + /* Decrement number of elements left */ + io_left -= actual_elem * tot_blk_count; - /* Encode starting point for this span */ - UINT32ENCODE(pp, (uint32_t)curr->high); - } /* end else */ + /* Increment information to reflect block just processed */ + offset[fast_dim] += (fast_dim_stride * tot_blk_count); /* move the offset in the fastest dimension */ - /* Advance to next node */ - curr = curr->next; - } /* end while */ + /* 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; - /* Update encoding pointer */ - *p = pp; + /* Store the sequence information */ + off[curr_seq] = loc; + len[curr_seq] = actual_bytes; - FUNC_LEAVE_NOAPI_VOID -} /* end H5S__hyper_serialize_helper() */ + /* 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_get_seq_list_opt() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_serialize + H5S__hyper_get_seq_list_single PURPOSE - Serialize the current selection into a user-provided buffer. + Create a list of offsets & lengths for a selection 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. + 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 RETURNS - Non-negative on success/Negative on failure + Non-negative on success/Negative on failure. DESCRIPTION - Serializes the current element selection into a buffer. (Primarily for - storing on disk). + 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_serialize(const H5S_t *space, uint8_t **p) +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) { - uint8_t *pp; /* Local pointer for decoding */ - uint8_t *lenp; /* 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; /* Block counter for regular hyperslabs */ + 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 */ FUNC_ENTER_STATIC_NOERR - /* Sanity checks */ + /* Check args */ HDassert(space); - HDassert(p); - pp = (*p); - HDassert(pp); - - /* Calculate version */ - if(space->select.sel_info.hslab->unlim_dim >= 0) { - version = 2; - flags |= H5S_SELECT_FLAG_UNLIM; - } /* end if */ - else - version = 1; - - /* 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 >= 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 */ + HDassert(iter); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); - /* Encode number of dimensions */ - UINT32ENCODE(pp, (uint32_t)space->extent.rank); - len += 4; + /* Set a local copy of the diminfo pointer */ + tdiminfo = iter->u.hyp.diminfo; - /* If there is an unlimited dimension, only encode opt_unlim_diminfo */ - if(flags & H5S_SELECT_FLAG_UNLIM) { - unsigned i; + /* 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; - HDassert(H5S_UNLIMITED == HSIZE_UNDEF); + /* Set the local copy of the selection offset */ + sel_off = iter->u.hyp.sel_off; - /* Iterate over dimensions */ - for(i = 0; i < space->extent.rank; i++) { - /* Encode start/stride/block/count */ - UINT64ENCODE(pp, space->select.sel_info.hslab->opt_diminfo[i].start); - UINT64ENCODE(pp, space->select.sel_info.hslab->opt_diminfo[i].stride); - UINT64ENCODE(pp, space->select.sel_info.hslab->opt_diminfo[i].count); - UINT64ENCODE(pp, space->select.sel_info.hslab->opt_diminfo[i].block); - } /* end for */ + /* Set up the pointer to the size of the memory space */ + mem_size = iter->u.hyp.size; } /* end if */ - /* Check for a "regular" hyperslab selection */ - else if(space->select.sel_info.hslab->diminfo_valid) { - const H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */ - hsize_t offset[H5S_MAX_RANK]; /* Offset of element in dataspace */ - hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary hyperslab counts */ - 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 done; /* Whether we are done with the iteration */ - - /* Set some convenience values */ + else { + /* Set the aliases for a few important dimension ranks */ ndims = space->extent.rank; - fast_dim = ndims - 1; - diminfo = space->select.sel_info.hslab->opt_diminfo; - /* Check each dimension */ - for(block_count = 1, u = 0; u < ndims; u++) - block_count *= diminfo[u].count; + /* Set the local copy of the selection offset */ + sel_off = space->select.offset; - /* Encode number of hyperslabs */ - H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t); - UINT32ENCODE(pp, (uint32_t)block_count); - len += 4; + /* Set up the pointer to the size of the memory space */ + mem_size = space->extent.size; + } /* end else */ + fast_dim = ndims - 1; - /* Now serialize the information for the regular hyperslab */ + /* 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 */ - /* 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 */ + /* 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]); - /* We're not done with the iteration */ - done = FALSE; + /* 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]); - /* 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; + /* Compute the initial buffer offset */ + for(u = 0, loc = 0; u < ndims; u++) + loc += offset[u] * slab[u]; - /* Encode hyperslab starting location */ - for(u = 0; u < ndims; u++) - UINT32ENCODE(pp, (uint32_t)offset[u]); + /* Set local copies of information for the fastest changing dimension */ + fast_dim_block = tdiminfo[fast_dim].block; - /* Encode hyperslab ending location */ - for(u = 0; u < ndims; u++) - UINT32ENCODE(pp, (uint32_t)(offset[u] + (diminfo[u].block - 1))); + /* 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); - /* Move the offset to the next sequence to start */ - offset[fast_dim]+=diminfo[fast_dim].stride; + /* 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); - /* Decrement the block count */ - tmp_count[fast_dim]--; - } /* end while */ + /* Don't go over the maximum number of sequences allowed */ + tot_blk_count = MIN(tot_blk_count, maxseq); - /* Work on other dimensions if necessary */ - if(fast_dim > 0) { - int temp_dim; /* Temporary rank holder */ + /* Set the number of elements to write each time */ + H5_CHECKED_ASSIGN(actual_elem, size_t, fast_dim_block, hsize_t); - /* Reset the block counts */ - tmp_count[fast_dim] = diminfo[fast_dim].count; + /* Check for blocks to operate on */ + if(tot_blk_count > 0) { + size_t actual_bytes; /* The actual number of bytes to copy */ - /* 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]--; + /* Set the number of actual bytes */ + actual_bytes = actual_elem * elem_size; - /* Check if we have more blocks left */ - if(tmp_count[temp_dim] > 0) - break; + /* Check for 1-dim selection */ + if(0 == fast_dim) { + /* Sanity checks */ + HDassert(1 == tot_blk_count); + HDassert(io_left == actual_elem); - /* Check for getting out of iterator */ - if(temp_dim == 0) - done = TRUE; + /* 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 */ - /* Reset the block count in this dimension */ - tmp_count[temp_dim] = diminfo[temp_dim].count; + /* 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]; - /* Wrapped a dimension, go up to next dimension */ - temp_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 - break; /* Break out now, for 1-D selections */ + 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 */ - /* 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 { - hsize_t start[H5S_MAX_RANK]; /* Location of start of hyperslab */ - hsize_t end[H5S_MAX_RANK]; /* Location of end of hyperslab */ - - /* Encode number of hyperslabs */ - block_count = H5S__hyper_span_nblocks(space->select.sel_info.hslab->span_lst); - H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t); - UINT32ENCODE(pp, (uint32_t)block_count); - len += 4; + /* Set the starting block location */ + for(u = 0; u < ndims; u++) + tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start; - /* Add 8 bytes times the rank for each hyperslab selected */ - H5_CHECK_OVERFLOW((8 * space->extent.rank * block_count), hsize_t, size_t); - len += (uint32_t)(8 * space->extent.rank * block_count); + /* Compute the amount to skip between sequences */ + for(u = 0; u < ndims; u++) + skip[u] = (mem_size[u] - tdiminfo[u].block) * slab[u]; - /* Encode each hyperslab in selection */ - H5S__hyper_serialize_helper(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, &pp); - } /* end else */ + /* 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; - /* Encode length */ - UINT32ENCODE(lenp, (uint32_t)len); /* Store the length of the extra information */ + /* Set temporary dimension for advancing offsets */ + temp_dim = (int)skip_dim; - /* Update encoding pointer */ - *p = pp; + /* Increment offset in destination buffer */ + loc += skip_slab; - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_serialize() */ + /* 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]++; - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_deserialize - PURPOSE - Deserialize the current selection from a user-provided buffer. - USAGE - herr_t H5S__hyper_deserialize(space, p) - H5S_t *space; IN/OUT: Dataspace pointer to place - selection into - uint32_t version IN: Selection version - uint8_t flags IN: Selection flags - 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 - 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_deserialize(H5S_t *space, uint32_t H5_ATTR_UNUSED version, uint8_t flags, - const uint8_t **p) -{ - unsigned rank; /* Rank of points */ - const uint8_t *pp; /* Local pointer for decoding */ - hsize_t start[H5S_MAX_RANK]; /* Hyperslab start information */ - hsize_t block[H5S_MAX_RANK]; /* Hyperslab block information */ - unsigned u; /* Local counting variable */ - herr_t ret_value = FAIL; /* Return value */ + /* 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 */ - FUNC_ENTER_STATIC + /* Decrement dimension count */ + temp_dim--; + } /* end while */ - /* Check args */ - HDassert(space); - HDassert(p); - pp = (*p); - HDassert(pp); + /* Decrement block count */ + blk_count--; + } /* end while */ + } /* end else */ + } /* end else */ - /* Deserialize slabs to select */ - /* (The header and rank have already beed decoded) */ - rank = space->extent.rank; /* Retrieve rank from space */ + /* Update the iterator, if there were any blocks used */ - /* If there is an unlimited dimension, only encode opt_unlim_diminfo */ - if(flags & H5S_SELECT_FLAG_UNLIM) { - hsize_t stride[H5S_MAX_RANK]; /* Hyperslab stride information */ - hsize_t count[H5S_MAX_RANK]; /* Hyperslab count information */ + /* Decrement the number of elements left in selection */ + iter->elmt_left -= tot_blk_count * actual_elem; - /* Sanity checks */ - HDassert(H5S_UNLIMITED == HSIZE_UNDEF); - HDassert(version >= 2); + /* 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 */ - /* 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 */ + /* Increment the number of sequences generated */ + *nseq += tot_blk_count; - /* Select the hyperslab to the current selection */ - if((ret_value = H5S_select_hyperslab(space, H5S_SELECT_SET, start, stride, count, block)) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't change selection") + /* Increment the number of elements used */ + *nelem += tot_blk_count * actual_elem; } /* 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 block_count; /* Number of blocks in selection */ - unsigned v; /* Local counting variable */ - /* Decode the number of blocks */ - UINT32DECODE(pp, block_count); + /* 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 */ - /* Set the count & stride for all blocks */ - stride = count = H5S_hyper_ones_g; + /* Compute elements left */ + elmt_remainder = io_left - (tot_blk_count * actual_elem); + HDassert(elmt_remainder < fast_dim_block); + HDassert(elmt_remainder > 0); - /* Retrieve the coordinates from the buffer */ - for(u = 0; u < block_count; u++) { - /* Decode the starting points */ - for(tstart = start, v = 0; v < rank; v++, tstart++) - UINT32DECODE(pp, *tstart); + /* Store the sequence information */ + *off++ = loc; + *len++ = elmt_remainder * elem_size; - /* Decode the ending points */ - for(tend = end, v = 0; v < rank; v++, tend++) - UINT32DECODE(pp, *tend); + /* Update the iterator with the location we stopped */ + iter->u.hyp.off[fast_dim] += (hsize_t)elmt_remainder; - /* 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; + /* Decrement the number of elements left in selection */ + iter->elmt_left -= elmt_remainder; - /* Select or add the hyperslab to the current selection */ - if((ret_value = H5S_select_hyperslab(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 */ + /* Increment the number of sequences generated */ + (*nseq)++; - /* Update decoding pointer */ - *p = pp; + /* Increment the number of elements used */ + *nelem += elmt_remainder; + } /* end if */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_deserialize() */ + /* Sanity check */ + HDassert(*nseq > 0); + HDassert(*nelem > 0); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_get_seq_list_single() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_span_blocklist + H5S__hyper_get_seq_list PURPOSE - Get a list of hyperslab blocks currently selected + Create a list of offsets & lengths for a 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 + 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 (in bytes) + size_t *len; OUT: Array of lengths (in bytes) RETURNS - Non-negative on success/Negative on failure + Non-negative 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. + 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_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) +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) { - 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 + herr_t ret_value = FAIL; /* return value */ - /* Sanity checks */ - HDassert(spans); - HDassert(rank < H5S_MAX_RANK); - HDassert(start); - HDassert(end); - HDassert(startblock); - HDassert(numblocks && *numblocks > 0); - HDassert(buf && *buf); + FUNC_ENTER_STATIC_NOERR - /* 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; + /* 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); - /* 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") + /* Check for the special case of just one H5Sselect_hyperslab call made */ + if(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 */ + + /* 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 { - /* Skip this block if we haven't skipped all the startblocks yet */ - if(*startblock > 0) { - /* Decrement the starting block */ - (*startblock)--; + /* 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; + + /* 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 */ + + + /* 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 */ - /* Process this block */ else { - /* Encode all the previous dimensions starting & ending points */ + 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 */ - /* Copy previous starting points */ - for(u = 0; u < rank; u++, (*buf)++) - HDmemcpy(*buf, &start[u], sizeof(hsize_t)); + /* Make certain that we don't write too many */ + actual_elem = MIN3(leftover, (size_t)iter->elmt_left, maxelem); - /* Copy starting point for this span */ - HDmemcpy(*buf, &curr->low, sizeof(hsize_t)); - (*buf)++; + /* 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 */ - /* Copy previous ending points */ - for(u = 0; u < rank; u++, (*buf)++) - HDmemcpy(*buf, &end[u], sizeof(hsize_t)); + /* 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]; - /* Copy starting point for this span */ - HDmemcpy(*buf, &curr->high, sizeof(hsize_t)); - (*buf)++; + /* Add a new sequence */ + off[0] = loc; + H5_CHECKED_ASSIGN(len[0], size_t, actual_elem * elem_size, hsize_t); - /* Decrement the number of blocks processed */ - (*numblocks)--; - } /* end else */ + /* 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 */ - /* Advance to next node */ - curr = curr->next; - } /* end while */ + /* 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_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 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_span_blocklist() */ +} /* end H5S__hyper_get_seq_list() */ /*-------------------------------------------------------------------------- NAME - H5S__get_select_hyper_blocklist + H5S__hyper_iter_release PURPOSE - Get the list of hyperslab blocks currently selected + Release hyperslab selection iterator information for a dataspace 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 + 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 + Non-negative 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. + Releases all information for a dataspace hyperslab selection iterator 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) +H5S__hyper_iter_release(H5S_sel_iter_t *iter) { - herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_STATIC_NOERR - HDassert(space); - HDassert(buf); - HDassert(space->select.sel_info.hslab->unlim_dim < 0); + /* Check args */ + HDassert(iter); - /* Check for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid) { - 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 */ + /* Free the copy of the hyperslab selection span tree */ + if(iter->u.hyp.spans != NULL) + H5S__hyper_free_span_info(iter->u.hyp.spans); - /* Set some convienence values */ - ndims = space->extent.rank; - fast_dim = ndims - 1; + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_iter_release() */ - /* 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->opt_diminfo; - else - if(space->select.sel_info.hslab->unlim_dim >= 0) - /* - * There is an unlimited dimension so we must use opt_diminfo as - * it has been "clipped" to the current extent. - */ - diminfo = space->select.sel_info.hslab->opt_diminfo; - 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->app_diminfo; + +/*-------------------------------------------------------------------------- + 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 new 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 */ - /* 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_ENTER_STATIC - /* 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 */ - - /* Iterate over the blocks in the fastest dimension */ - while(tmp_count[fast_dim] > 0 && numblocks > 0) { - - /* Check if we should copy this block information */ - if(startblock == 0) { - /* Copy the starting location */ - HDmemcpy(buf, offset, sizeof(hsize_t) * ndims); - buf += ndims; - - /* Compute the ending location */ - HDmemcpy(buf, offset, sizeof(hsize_t) * ndims); - for(u = 0; u < ndims; u++) - buf[u] += (diminfo[u].block - 1); - buf += ndims; + /* 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") - /* Decrement the number of blocks to retrieve */ - numblocks--; - } /* end if */ - else - startblock--; + /* 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; - /* Move the offset to the next sequence to start */ - offset[fast_dim] += diminfo[fast_dim].stride; + /* Increment the reference count of the 'down span' if there is one */ + if(ret_value->down) + ret_value->down->count++; - /* Decrement the block count */ - tmp_count[fast_dim]--; - } /* end while */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_new_span() */ - /* Work on other dimensions if necessary */ - if(fast_dim > 0 && numblocks > 0) { - int temp_dim; /* Temporary rank holder */ + +/*-------------------------------------------------------------------------- + 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 - /* Reset the block counts */ - tmp_count[fast_dim] = diminfo[fast_dim].count; + /* Sanity checks */ + HDassert(spans); + HDassert(spans->scratch == (H5S_hyper_span_info_t *)~((size_t)NULL) || + spans->scratch == NULL); - /* 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'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 */ - /* Check if we have more blocks left */ - if(tmp_count[temp_dim] > 0) - break; + /* Set the tree's scratch pointer */ + spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL); - /* Check for getting out of iterator */ - if(temp_dim == 0) - done = TRUE; + /* Set the scratch pointers in all the nodes */ + span = spans->head; - /* Reset the block count in this dimension */ - tmp_count[temp_dim] = diminfo[temp_dim].count; + /* 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); - /* Wrapped a dimension, go up to next dimension */ - temp_dim--; - } /* end while */ - } /* end if */ + /* Change the nelem & pstride values into bytes */ + span->nelem *= elmt_size; + span->pstride *= elmt_size; - /* 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 */ + /* Advance to next span */ + span = span->next; } /* 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 */ - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__get_select_hyper_blocklist() */ + FUNC_LEAVE_NOAPI_VOID +} /* end H5S__hyper_span_precompute_helper() */ /*-------------------------------------------------------------------------- NAME - H5Sget_select_hyper_blocklist + H5S__hyper_span_precompute PURPOSE - Get the list of hyperslab blocks currently selected + Precompute the nelem and pstrides in bytes. 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 + 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 - 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. + 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 --------------------------------------------------------------------------*/ -herr_t -H5Sget_select_hyper_blocklist(hid_t spaceid, hsize_t startblock, - hsize_t numblocks, hsize_t buf[/*numblocks*/]) +static herr_t +H5S__hyper_span_precompute(H5S_hyper_span_info_t *spans, size_t elmt_size) { - H5S_t *space; /* Dataspace to modify selection of */ - herr_t ret_value; /* return value */ + FUNC_ENTER_STATIC_NOERR - FUNC_ENTER_API(FAIL) - H5TRACE4("e", "ihh*[a2]h", spaceid, startblock, numblocks, buf); + HDassert(spans); - /* 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") + /* Call the helper routine to actually do the work */ + H5S__hyper_span_precompute_helper(spans, elmt_size); - /* 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... */ + /* Reset the scratch pointers for the next routine which needs them */ + H5S__hyper_span_scratch(spans); -done: - FUNC_LEAVE_API(ret_value) -} /* end H5Sget_select_hyper_blocklist() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_span_precompute() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_bounds_helper + H5S__hyper_span_scratch PURPOSE - Gets the bounding box containing the selection. + Reset the scratch pointers on hyperslab span trees 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_span_scratch(span_info) + H5S_hyper_span_info_t *span_info; IN: Span tree to reset RETURNS - 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. + Reset the scratch pointers on a hyperslab span tree to NULL. 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_span_scratch(H5S_hyper_span_info_t *spans) { - H5S_hyper_span_t *curr; /* Hyperslab information nodes */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC_NOERR HDassert(spans); - HDassert(offset); - HDassert(rank < H5S_MAX_RANK); - HDassert(start); - HDassert(end); - /* 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]; + /* Check if we've already set this down span tree */ + if(spans->scratch != NULL) { + H5S_hyper_span_t *span; /* Hyperslab span */ - /* 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") - } /* end if */ + /* Reset the tree's scratch pointer */ + spans->scratch = NULL; - /* Advance to next node */ - curr = curr->next; - } /* end while */ + /* 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); -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_bounds_helper() */ + /* Advance to next span */ + span = span->next; + } /* end while */ + } /* end if */ + + FUNC_LEAVE_NOAPI_VOID +} /* end H5S__hyper_span_scratch() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_bounds + H5S__hyper_copy_span_helper PURPOSE - Gets the bounding box containing the selection. + Helper routine to copy a hyperslab span tree 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 + H5S_hyper_span_info_t * H5S__hyper_copy_span_helper(spans) + H5S_hyper_span_info_t *spans; IN: Span tree to copy RETURNS - Non-negative on success, negative on failure + Pointer to the copied span tree on success, NULL 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. + Copy a hyperslab span tree, using reference counting as appropriate. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_bounds(const H5S_t *space, hsize_t *start, hsize_t *end) +static H5S_hyper_span_info_t * +H5S__hyper_copy_span_helper(H5S_hyper_span_info_t *spans) { - unsigned rank; /* Dataspace rank */ - unsigned i; /* index variable */ - herr_t ret_value = SUCCEED; /* Return value */ + 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 check */ - HDassert(space); - HDassert(start); - HDassert(end); + /* Sanity checks */ + HDassert(spans); + HDassert(spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)); - /* 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 */ + /* 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; - /* Check for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid) { - const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->opt_diminfo; /* local alias for diminfo */ + /* 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") - /* 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") + /* Copy the span_info information */ + ret_value->count = 1; - /* Compute the smallest location in this dimension */ - start[i] = diminfo[i].start + (hsize_t)space->select.offset[i]; + /* Set the scratch pointer in the node being copied to the newly allocated node */ + spans->scratch = ret_value; - /* Compute the largest location in this dimension */ - if((int)i == space->select.sel_info.hslab->unlim_dim) - end[i] = H5S_UNLIMITED; + /* 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") + + /* Append to list of spans */ + if(NULL == prev_span) + ret_value->head = new_span; 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 */ + prev_span->next = new_span; + + /* Copy the pstride */ + new_span->pstride = span->pstride; + + /* 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 */ + + /* Update the previous (new) span */ + prev_span = new_span; + + /* Advance to next span */ + span = span->next; + } /* end while */ + } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_bounds() */ +} /* end H5S__hyper_copy_span_helper() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_offset + H5S__hyper_copy_span PURPOSE - Gets the linear offset of the first element for the selection. + Copy a hyperslab span tree 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 + H5S_hyper_span_info_t * H5S__hyper_copy_span(span_info) + H5S_hyper_span_info_t *span_info; IN: Span tree to copy 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. + 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 - 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) +static H5S_hyper_span_info_t * +H5S__hyper_copy_span(H5S_hyper_span_info_t *spans) { - 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 */ + H5S_hyper_span_info_t *ret_value = NULL; /* Return value */ FUNC_ENTER_STATIC - HDassert(space && space->extent.rank>0); - HDassert(offset); - - /* Start at linear offset 0 */ - *offset = 0; - - /* Set up pointers to arrays of values */ - rank = space->extent.rank; - sel_offset = space->select.offset; - dim_size = space->extent.size; - - /* Check for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid) { - const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->opt_diminfo; /* Local alias for diminfo */ - - /* 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 */ - - /* 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") - - /* Add the hyperslab's offset in this dimension to the total linear offset */ - *offset += (hsize_t)(hyp_offset * (hssize_t)accum); - - /* 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 */ - - /* 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; - - /* Increase the accumulator */ - accum *= dim_size[i]; - } /* end for */ - - /* Get information for the first span, in the slowest changing dimension */ - span = space->select.sel_info.hslab->span_lst->head; - - /* 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 */ - - /* 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") + /* Sanity check */ + HDassert(spans); - /* Add the hyperslab's offset in this dimension to the total linear offset */ - *offset += (hsize_t)(hyp_offset * (hssize_t)dim_accum[i]); + /* 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") - /* 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 */ + /* Reset the scratch pointers for the next routine which needs them */ + H5S__hyper_span_scratch(spans); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_offset() */ +} /* end H5S__hyper_copy_span() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_unlim_dim + H5S__hyper_cmp_spans PURPOSE - Return unlimited dimension of selection, or -1 if none + Check if two hyperslab span trees are the same USAGE - int H5S__hyper_unlim_dim(space) - H5S_t *space; IN: Dataspace pointer to check + 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 - Unlimited dimension of selection, or -1 if none (never fails). + TRUE (1) or FALSE (0) on success, can't fail DESCRIPTION - Returns the index of the unlimited dimension of the selection, or -1 - if the selection has no unlimited dimension. + 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 int -H5S__hyper_unlim_dim(const H5S_t *space) +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) { - FUNC_ENTER_STATIC_NOERR + hbool_t ret_value = FALSE; /* Return value */ - FUNC_LEAVE_NOAPI(space->select.sel_info.hslab->unlim_dim); -} /* end H5S__hyper_unlim_dim() */ + FUNC_ENTER_STATIC_NOERR - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_num_elem_non_unlim - PURPOSE - Return number of elements in the non-unlimited dimensions + /* Check for redundant comparison (or both spans being NULL) */ + if(span_info1 == span_info2) + ret_value = TRUE; + else { + /* Check for one span being NULL */ + if(span_info1 == NULL || span_info2 == NULL) + ret_value = 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) { + 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 */ + + /* Advance to the next nodes in the span list */ + span1 = span1->next; + span2 = span2->next; + } /* end while */ + } /* end else */ + } /* end else */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_cmp_spans() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_free_span_info + PURPOSE + Free a hyperslab span info node 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_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 + 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. + 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_num_elem_non_unlim(const H5S_t *space, hsize_t *num_elem_non_unlim) +H5S__hyper_free_span_info(H5S_hyper_span_info_t *span_info) { - herr_t ret_value = SUCCEED; + H5S_hyper_span_t *span, *next_span; + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_STATIC - /* Sanity check */ - HDassert(space); - HDassert(num_elem_non_unlim); + HDassert(span_info); - /* 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") + /* Decrement the span tree's reference count */ + span_info->count--; + + /* Free the span tree if the reference count drops to zero */ + if(span_info->count == 0) { + + /* 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; + } /* end while */ + + /* Free this span info */ + span_info = H5FL_FREE(H5S_hyper_span_info_t, span_info); + } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_num_elem_non_unlim() */ +} /* end H5S__hyper_free_span_info() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_is_contiguous + H5S__hyper_free_span PURPOSE - Check if a hyperslab selection is contiguous within the dataspace extent. + Free a hyperslab span node USAGE - htri_t H5S__hyper_is_contiguous(space) - H5S_t *space; IN: Dataspace pointer to check + herr_t H5S__hyper_free_span(span) + H5S_hyper_span_t *span; IN: Span node to free RETURNS - TRUE/FALSE/FAIL + Non-negative on success, negative on failure 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. + 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 --------------------------------------------------------------------------*/ -static H5_ATTR_PURE htri_t -H5S__hyper_is_contiguous(const H5S_t *space) +static herr_t +H5S__hyper_free_span(H5S_hyper_span_t *span) { - 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 */ + herr_t ret_value = SUCCEED; - FUNC_ENTER_STATIC_NOERR + FUNC_ENTER_STATIC - HDassert(space); + HDassert(span); - /* Check for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid) { - const H5S_hyper_dim_t *diminfo=space->select.sel_info.hslab->opt_diminfo; /* local alias for diminfo */ + /* 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") - /* - * 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) - */ + /* Free this span */ + span = H5FL_FREE(H5S_hyper_span_t, span); - /* Initialize flags */ - large_contiguous = TRUE; /* assume true and reset if the dimensions don't match */ - small_contiguous = FALSE; /* assume false initially */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_free_span() */ - /* 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 */ + +/*-------------------------------------------------------------------------- + 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. - /* 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 */ + 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 */ - /* 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 */ + FUNC_ENTER_STATIC - /* - * 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 */ + /* Sanity check */ + HDassert(src); + HDassert(dst); - /* Get information for slowest changing information */ - spans = space->select.sel_info.hslab->span_lst; - span = spans->head; + /* 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") - /* 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; + /* Set temporary pointers */ + dst_hslab = dst->select.sel_info.hslab; + src_hslab = src->select.sel_info.hslab; - /* Cycle down the spans until we run out of down spans or find a non-contiguous span */ - while(spans != NULL) { - span = spans->head; + /* Copy the hyperslab information */ + dst_hslab->diminfo_valid = src_hslab->diminfo_valid; + if(src_hslab->diminfo_valid) { + size_t u; /* Local index variable */ - /* 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; + for(u=0; uextent.rank; u++) { + dst_hslab->opt_diminfo[u]=src_hslab->opt_diminfo[u]; + dst_hslab->app_diminfo[u]=src_hslab->app_diminfo[u]; + } /* end for */ + } /* end if */ + dst->select.sel_info.hslab->span_lst=src->select.sel_info.hslab->span_lst; - /* Increment dimension */ - u++; - } /* end else */ - } /* end else */ - } /* end while */ + /* 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 + /* 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; - /* Indicate true if it's either a large or small contiguous block */ - if(large_contiguous || small_contiguous) - ret_value = TRUE; - } /* end else */ + /* 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) -} /* end H5S__hyper_is_contiguous() */ +} /* end H5S__hyper_copy() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_is_single + H5S__hyper_is_valid_helper PURPOSE - Check if a hyperslab selection is a single block within the dataspace extent. + Check whether the selection fits within the extent, with the current + offset defined. USAGE - htri_t H5S__hyper_is_single(space) - H5S_t *space; IN: Dataspace pointer to check + 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/FALSE/FAIL + TRUE if the selection fits within the extent, FALSE if it does not 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. + 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 H5_ATTR_PURE htri_t -H5S__hyper_is_single(const H5S_t *space) +static hbool_t +H5S__hyper_is_valid_helper(const H5S_hyper_span_info_t *spans, const hssize_t *offset, + const hsize_t *size) { - htri_t ret_value = TRUE; /* return value */ + H5S_hyper_span_t *curr; /* Hyperslab information nodes */ + hbool_t ret_value = TRUE; /* Return value */ FUNC_ENTER_STATIC_NOERR - HDassert(space); - - /* Check for a "single" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid) { - unsigned u; /* index variable */ + HDassert(spans); + HDassert(offset); + HDassert(size); - /* - * For a regular hyperslab to be single, it must have only one - * block (i.e. count==1 in all dimensions) - */ + /* 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) - /* Check for a single block */ - for(u = 0; u < space->extent.rank; u++) - if(space->select.sel_info.hslab->opt_diminfo[u].count > 1) + /* 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) - } /* end if */ - else { - H5S_hyper_span_info_t *spans; /* Hyperslab span info node */ - - /* - * 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; - - /* 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 */ - - 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 */ + /* Advance to next node */ + curr = curr->next; + } /* end while */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_is_single() */ +} /* end H5S__hyper_is_valid_helper() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_is_regular + H5S__hyper_is_valid PURPOSE - Check if a hyperslab selection is "regular" + Check whether the selection fits within the extent, with the current + offset defined. USAGE - htri_t H5S__hyper_is_regular(space) - const H5S_t *space; IN: Dataspace pointer to check + htri_t H5S__hyper_is_valid(space); + H5S_t *space; IN: Dataspace pointer to query RETURNS - TRUE/FALSE/FAIL + TRUE if the selection fits within the extent, FALSE if it does not and + Negative on an error. 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. + Determines if the current selection at the current offset fits within the + extent for the dataspace. 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) +H5S__hyper_is_valid(const H5S_t *space) { - htri_t ret_value = FAIL; /* return value */ + htri_t ret_value = TRUE; /* return value */ FUNC_ENTER_STATIC_NOERR - /* Check args */ HDassert(space); - /* Only simple check for regular hyperslabs for now... */ - if(space->select.sel_info.hslab->diminfo_valid) - ret_value = TRUE; + /* Check for unlimited selection */ + if(space->select.sel_info.hslab->unlim_dim >= 0) + HGOTO_DONE(FALSE) + + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid) { + const H5S_hyper_dim_t *diminfo=space->select.sel_info.hslab->opt_diminfo; /* local alias for diminfo */ + hssize_t end; /* The high bound of a region in a dimension */ + unsigned u; /* Counter */ + + /* 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) + + /* 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]; + + /* 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 - ret_value = FALSE; + /* 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); +done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_is_regular() */ +} /* end H5S__hyper_is_valid() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_release + H5S__hyper_span_nblocks PURPOSE - Release hyperslab selection information for a dataspace + Count the number of blocks in a span tree USAGE - herr_t H5S__hyper_release(space) - H5S_t *space; IN: Pointer to dataspace - RETURNS - Non-negative on success/Negative on failure + hsize_t H5S__hyper_span_nblocks(spans) + const H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to count elements of + RETURNS + Number of blocks in span tree on success; negative on failure DESCRIPTION - Releases all hyperslab selection information for a dataspace + Counts the number of blocks described by the spans in a span tree. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG - * Robb Matzke, 1998-08-25 - * The fields which are freed are set to NULL to prevent them from being - * freed again later. This fixes some allocation problems where - * changing the hyperslab selection of one dataspace causes a core dump - * when closing some other dataspace. --------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_release(H5S_t *space) +static hsize_t +H5S__hyper_span_nblocks(const H5S_hyper_span_info_t *spans) { - herr_t ret_value = SUCCEED; - - FUNC_ENTER_STATIC + hsize_t ret_value = 0; /* Return value */ - /* Check args */ - HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space)); + FUNC_ENTER_STATIC_NOERR - /* Reset the number of points selected */ - space->select.num_elem = 0; + /* Count the number of elements in the span tree */ + if(spans != NULL) { + H5S_hyper_span_t *span; /* Hyperslab span */ - /* 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") + span = spans->head; + 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 */ + else + ret_value++; - /* 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 */ + /* Advance to next span */ + span = span->next; + } /* end while */ + } /* end else */ -done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_release() */ +} /* end H5S__hyper_span_nblocks() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_recover_span + H5S__get_select_hyper_nblocks PURPOSE - Recover a generated span, if appropriate + Get the number of hyperslab blocks in current hyperslab selection 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 + hsize_t H5S__get_select_hyper_nblocks(space) + H5S_t *space; IN: Dataspace ptr 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 - 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. + Returns the number of hyperslab blocks in current selection for dataspace. 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) +static hsize_t +H5S__get_select_hyper_nblocks(const H5S_t *space) { + hsize_t ret_value = 0; /* Return value */ + FUNC_ENTER_STATIC_NOERR - HDassert(recover); - HDassert(curr_span); + HDassert(space); + HDassert(space->select.sel_info.hslab->unlim_dim < 0); - /* Check if the span should be recovered */ - if(*recover) { - H5S__hyper_free_span(*curr_span); - *recover = FALSE; - } /* end if */ + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid) { + unsigned u; /* Local index variable */ - /* Set the current span to next span */ - *curr_span = next_span; + /* Check each dimension */ + for(ret_value = 1, u = 0; u < space->extent.rank; u++) + ret_value *= space->select.sel_info.hslab->app_diminfo[u].count; + } /* end if */ + else + ret_value = H5S__hyper_span_nblocks(space->select.sel_info.hslab->span_lst); - FUNC_LEAVE_NOAPI(SUCCEED) -} /* H5S__hyper_recover_span() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__get_select_hyper_nblocks() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_coord_to_span + H5Sget_select_hyper_nblocks PURPOSE - Create a span tree for a single element + Get the number of hyperslab blocks in current hyperslab 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 + 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 - Create a span tree for a single element + Returns the number of hyperslab blocks in current selection for dataspace. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static H5S_hyper_span_t * -H5S__hyper_coord_to_span(unsigned rank, const hsize_t *coords) +hssize_t +H5Sget_select_hyper_nblocks(hid_t spaceid) { - 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 */ - - FUNC_ENTER_STATIC - - HDassert(rank > 0); - HDassert(coords); - - /* 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") - + H5S_t *space; /* Dataspace to modify selection of */ + hssize_t ret_value; /* return value */ - /* 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 */ + FUNC_ENTER_API(FAIL) + H5TRACE1("Hs", "i", spaceid); - /* 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 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") - /* Set return value */ - ret_value = new_span; + ret_value = (hssize_t)H5S__get_select_hyper_nblocks(space); done: - if(ret_value == NULL && down != NULL) - H5S__hyper_free_span_info(down); - - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_coord_to_span() */ + FUNC_LEAVE_API(ret_value) +} /* end H5Sget_select_hyper_nblocks() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_add_span_element_helper + H5S__hyper_serial_size PURPOSE - Add a single element to a span tree + Determine the number of bytes needed to store the serialized hyperslab + selection information. 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 + 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 - Add a single element to an existing span tree. + Determines the number of bytes required to serialize the current hyperslab + selection information for storage on disk. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS - Assumes that the element is not already covered by the span tree 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) +static hssize_t +H5S__hyper_serial_size(const H5S_t *space) { - 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 */ + hsize_t block_count; /* block counter for regular hyperslabs */ + unsigned u; /* Counter */ + hssize_t ret_value = -1; /* return value */ - FUNC_ENTER_STATIC + FUNC_ENTER_STATIC_NOERR - /* Sanity check */ - HDassert(span_tree); - HDassert(rank > 0); - HDassert(coords); + HDassert(space); - /* 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; + /* Check for version (right now, an unlimited dimension is the only thing + * that would bump the version) */ + if(space->select.sel_info.hslab->unlim_dim >= 0) + /* Version 2 */ + /* Size required is always: + * + + + + * + + + * (4 (start/stride/count/block) * * ) = + * 17 + (4 * rank * 8) bytes + */ + ret_value = (hssize_t)17 + ((hssize_t)4 * (hssize_t)space->extent.rank + * (hssize_t)8); else { - tmp_span=span_tree->head; - HDassert(tmp_span); - span_tree->scratch=(H5S_hyper_span_info_t *)tmp_span; - } /* end else */ + /* Version 1 */ + /* Basic number of bytes required to serialize hyperslab selection: + * + + + + * + + <# of blocks (4 bytes)> + * = 24 bytes + */ + ret_value = 24; - /* 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++; + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid) { + /* Check each dimension */ + for(block_count = 1, u = 0; u < space->extent.rank; u++) + block_count *= space->select.sel_info.hslab->opt_diminfo[u].count; + } /* end if */ + else + /* Spin through hyperslab spans, adding 8 * rank bytes for each block */ + block_count = H5S__hyper_span_nblocks(space->select.sel_info.hslab->span_lst); - /* Remember the span tree we are descending into */ - prev_span_info=tspan_info; - tspan_info=tmp_span->down; + H5_CHECK_OVERFLOW((8 * space->extent.rank * block_count), hsize_t, hssize_t); + ret_value += (hssize_t)(8 * block_count * space->extent.rank); + } /* end else */ - /* 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; - - /* Increment reference count on shared "down tree" */ - tmp_span->down->count++; - } /* end else */ - - /* Found span to merge into, break out now */ - break; - } /* end if */ - - /* Advance to next span to check */ - tmp2_span=tmp2_span->next; - } /* end while */ - - /* 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") - - /* Add new span tree as span */ - HDassert(tmp_span); - tmp_span->next=new_span; - - /* Make scratch pointer point to last span in list */ - HDassert(tspan_info); - tspan_info->scratch=(H5S_hyper_span_info_t *)new_span; - - /* Set the proper 'pstride' for new span */ - new_span->pstride=new_span->low-tmp_span->low; - } /* 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); - - /* Point at earlier span's "down tree" */ - tmp_span->down=tmp2_span->down; - - /* Increment reference count on shared "down tree" */ - tmp_span->down->count++; - } /* end else */ - - /* Found span to merge into, break out now */ - break; - } /* end if */ - - /* 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") - - /* Add new span tree as span */ - HDassert(tmp_span); - tmp_span->next=new_span; - - /* Make scratch pointer point to last span in list */ - tspan_info->scratch=(H5S_hyper_span_info_t *)new_span; - - /* Set the proper 'pstride' for new span */ - new_span->pstride = new_span->low - tmp_span->low; - } /* end else */ - } /* end else */ - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_add_span_element_helper() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_serial_size() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_add_span_element + H5S__hyper_serialize_helper PURPOSE - Add a single element to a span tree + Serialize the current selection into a user-provided buffer. 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 + 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 RETURNS - Non-negative on success, negative on failure + None DESCRIPTION - Add a single element to an existing span tree. + Serializes the current element selection into a buffer. (Primarily for + storing on disk). 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 void +H5S__hyper_serialize_helper(const H5S_hyper_span_info_t *spans, + hsize_t *start, hsize_t *end, hsize_t rank, uint8_t **p) { - 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); + H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */ + uint8_t *pp = (*p); /* Local pointer for decoding */ - /* 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") + FUNC_ENTER_STATIC_NOERR - /* Set the reference count */ - head->count = 1; + /* Sanity checks */ + HDassert(spans); + HDassert(start); + HDassert(end); + HDassert(rank < H5S_MAX_RANK); + HDassert(p && pp); - /* 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") + /* 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; - /* 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") + /* Recurse down to the next dimension */ + H5S__hyper_serialize_helper(curr->down, start, end, rank + 1, &pp); + } /* end if */ + else { + hsize_t u; /* Index variable */ - /* Set the selection to the new span tree */ - space->select.sel_info.hslab->span_lst = head; + /* Encode all the previous dimensions starting & ending points */ - /* Set selection type */ - space->select.type = H5S_sel_hyper; + /* Encode previous starting points */ + for(u = 0; u < rank; u++) + UINT32ENCODE(pp, (uint32_t)start[u]); - /* Reset "regular" hyperslab flag */ - space->select.sel_info.hslab->diminfo_valid = FALSE; + /* Encode starting point for this span */ + UINT32ENCODE(pp, (uint32_t)curr->low); - /* Set unlim_dim */ - space->select.sel_info.hslab->unlim_dim = -1; + /* Encode previous ending points */ + for(u = 0; u < rank; u++) + UINT32ENCODE(pp, (uint32_t)end[u]); - /* 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") + /* Encode starting point for this span */ + UINT32ENCODE(pp, (uint32_t)curr->high); + } /* end else */ - /* Increment # of elements in selection */ - space->select.num_elem++; - } /* end else */ + /* Advance to next node */ + curr = curr->next; + } /* end while */ -done: - if(ret_value < 0) - if(head) - H5S__hyper_free_span_info(head); + /* Update encoding pointer */ + *p = pp; - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_add_span_element() */ + FUNC_LEAVE_NOAPI_VOID +} /* end H5S__hyper_serialize_helper() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_reset_scratch + H5S__hyper_serialize PURPOSE - Reset the scratch information for span tree + Serialize the current selection into a user-provided buffer. USAGE - herr_t H5S_hyper_reset_scratch(space) - H5S_t *space; IN/OUT: Pointer to dataspace to reset scratch pointers + 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 - Resets the "scratch" pointers used for various tasks in computing hyperslab - spans. + Serializes the current element selection into a buffer. (Primarily for + storing on disk). GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -herr_t -H5S_hyper_reset_scratch(H5S_t *space) +static herr_t +H5S__hyper_serialize(const H5S_t *space, uint8_t **p) { - herr_t ret_value = SUCCEED; /* Return value */ + uint8_t *pp; /* Local pointer for decoding */ + uint8_t *lenp; /* 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; /* Block counter for regular hyperslabs */ - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_STATIC_NOERR + /* Sanity checks */ HDassert(space); + HDassert(p); + pp = (*p); + HDassert(pp); - /* 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); + /* Calculate version */ + if(space->select.sel_info.hslab->unlim_dim >= 0) { + version = 2; + flags |= H5S_SELECT_FLAG_UNLIM; + } /* end if */ + else + version = 1; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_reset_scratch() */ + /* 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 >= 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_convert - PURPOSE - Convert a compatible selection to span tree form - USAGE - herr_t H5S_hyper_convert(space) - H5S_t *space; IN/OUT: Pointer to dataspace to convert - RETURNS - Non-negative on success, negative on failure - 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). - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -herr_t -H5S_hyper_convert(H5S_t *space) -{ - herr_t ret_value = SUCCEED; /* Return value */ + /* Encode number of dimensions */ + UINT32ENCODE(pp, (uint32_t)space->extent.rank); + len += 4; - FUNC_ENTER_NOAPI(FAIL) + /* If there is an unlimited dimension, only encode opt_unlim_diminfo */ + if(flags & H5S_SELECT_FLAG_UNLIM) { + unsigned i; - HDassert(space); + HDassert(H5S_UNLIMITED == HSIZE_UNDEF); - /* 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 */ + /* Iterate over dimensions */ + for(i = 0; i < space->extent.rank; i++) { + /* Encode start/stride/block/count */ + UINT64ENCODE(pp, space->select.sel_info.hslab->opt_diminfo[i].start); + UINT64ENCODE(pp, space->select.sel_info.hslab->opt_diminfo[i].stride); + UINT64ENCODE(pp, space->select.sel_info.hslab->opt_diminfo[i].count); + UINT64ENCODE(pp, space->select.sel_info.hslab->opt_diminfo[i].block); + } /* end for */ + } /* end if */ + /* Check for a "regular" hyperslab selection */ + else if(space->select.sel_info.hslab->diminfo_valid) { + const H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */ + hsize_t offset[H5S_MAX_RANK]; /* Offset of element in dataspace */ + hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary hyperslab counts */ + 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 done; /* Whether we are done with the iteration */ - /* 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; + /* Set some convenience values */ + ndims = space->extent.rank; + fast_dim = ndims - 1; + diminfo = space->select.sel_info.hslab->opt_diminfo; - /* 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 each dimension */ + for(block_count = 1, u = 0; u < ndims; u++) + block_count *= diminfo[u].count; - case H5S_SEL_HYPERSLABS: /* Hyperslab selection */ - break; + /* Encode number of hyperslabs */ + H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t); + UINT32ENCODE(pp, (uint32_t)block_count); + len += 4; - 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 */ + /* Now serialize the information for the regular hyperslab */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_convert() */ + /* 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 */ -#ifdef LATER - -/*-------------------------------------------------------------------------- - NAME - H5S_hyper_intersect_helper - PURPOSE - Helper routine to detect intersections in span trees - USAGE - htri_t H5S_hyper_intersect_helper(spans1, spans2) - H5S_hyper_span_info_t *spans1; IN: First span tree to operate with - H5S_hyper_span_info_t *spans2; IN: Second span tree to operate with - RETURNS - Non-negative on success, negative on failure - DESCRIPTION - Quickly detect intersections between two span trees - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -static htri_t -H5S_hyper_intersect_helper (H5S_hyper_span_info_t *spans1, H5S_hyper_span_info_t *spans2) -{ - H5S_hyper_span_t *curr1; /* Pointer to current span in 1st span tree */ - H5S_hyper_span_t *curr2; /* Pointer to current span in 2nd span tree */ - htri_t status; /* Status from recursive call */ - htri_t ret_value=FALSE; /* Return value */ + /* We're not done with the iteration */ + done = FALSE; - FUNC_ENTER_NOAPI_NOINIT + /* 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; - /* Sanity check */ - HDassert((spans1 && spans2) || (spans1 == NULL && spans2 == NULL)); + /* Encode hyperslab starting location */ + for(u = 0; u < ndims; u++) + UINT32ENCODE(pp, (uint32_t)offset[u]); - /* "NULL" span trees compare as overlapping */ - if(spans1==NULL && spans2==NULL) - HGOTO_DONE(TRUE); + /* Encode hyperslab ending location */ + for(u = 0; u < ndims; u++) + UINT32ENCODE(pp, (uint32_t)(offset[u] + (diminfo[u].block - 1))); - /* Get the span lists for each span in this tree */ - curr1=spans1->head; - curr2=spans2->head; - - /* Iterate over the spans in each tree */ - while(curr1!=NULL && curr2!=NULL) { - /* Check for 1st span entirely before 2nd span */ - if(curr1->highlow) - curr1=curr1->next; - /* Check for 2nd span entirely before 1st span */ - else if(curr2->highlow) - curr2=curr2->next; - /* Spans must overlap */ - else { - /* Recursively check spans in next dimension down */ - if((status=H5S_hyper_intersect_helper(curr1->down,curr2->down))<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab intersection check") + /* Move the offset to the next sequence to start */ + offset[fast_dim]+=diminfo[fast_dim].stride; - /* If there is a span intersection in the down dimensions, the span trees overlap */ - if(status==TRUE) - HGOTO_DONE(TRUE); + /* Decrement the block count */ + tmp_count[fast_dim]--; + } /* end while */ - /* No intersection in down dimensions, advance to next span */ - if(curr1->highhigh) - curr1=curr1->next; - else - curr2=curr2->next; - } /* end else */ - } /* end while */ + /* Work on other dimensions if necessary */ + if(fast_dim > 0) { + int temp_dim; /* Temporary rank holder */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5S_hyper_intersect_helper() */ + /* Reset the block counts */ + tmp_count[fast_dim] = diminfo[fast_dim].count; - -/*-------------------------------------------------------------------------- - NAME - H5S_hyper_intersect - PURPOSE - Detect intersections in span trees - USAGE - htri_t H5S_hyper_intersect(space1, space2) - H5S_t *space1; IN: First dataspace to operate on span tree - H5S_t *space2; IN: Second dataspace to operate on span tree - RETURNS - Non-negative on success, negative on failure - DESCRIPTION - Quickly detect intersections between two span trees - GLOBAL VARIABLES - COMMENTS, BUGS, ASSUMPTIONS - EXAMPLES - REVISION LOG ---------------------------------------------------------------------------*/ -htri_t -H5S_hyper_intersect (H5S_t *space1, H5S_t *space2) -{ - htri_t ret_value=FAIL; /* Return value */ + /* 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]--; - FUNC_ENTER_NOAPI_NOINIT + /* Check if we have more blocks left */ + if(tmp_count[temp_dim] > 0) + break; - /* Sanity check */ - HDassert(space1); - HDassert(space2); + /* Check for getting out of iterator */ + if(temp_dim == 0) + done = TRUE; - /* Check that the space selections both have span trees */ - if(space1->select.sel_info.hslab->span_lst==NULL || - space2->select.sel_info.hslab->span_lst==NULL) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") + /* Reset the block count in this dimension */ + tmp_count[temp_dim] = diminfo[temp_dim].count; - /* Check that the dataspaces are both the same rank */ - if(space1->extent.rank!=space2->extent.rank) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "dataspace ranks don't match") + /* Wrapped a dimension, go up to next dimension */ + temp_dim--; + } /* end while */ + } /* end if */ + else + break; /* Break out now, for 1-D selections */ - /* Perform the span-by-span intersection check */ - if((ret_value=H5S_hyper_intersect_helper(space1->select.sel_info.hslab->span_lst,space2->select.sel_info.hslab->span_lst))<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab intersection check") + /* 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 { + hsize_t start[H5S_MAX_RANK]; /* Location of start of hyperslab */ + hsize_t end[H5S_MAX_RANK]; /* Location of end of hyperslab */ -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* H5S_hyper_intersect() */ -#endif /* LATER */ + /* Encode number of hyperslabs */ + block_count = H5S__hyper_span_nblocks(space->select.sel_info.hslab->span_lst); + H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t); + UINT32ENCODE(pp, (uint32_t)block_count); + len += 4; - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_intersect_block_helper - PURPOSE - Helper routine to detect intersections in span trees - USAGE - hbool_t H5S__hyper_intersect_block_helper(spans, start, end) - H5S_hyper_span_info_t *spans; IN: First span tree to operate with - hsize_t *start; IN: Starting coordinate for block - hsize_t *end; IN: Ending coordinate for block - RETURN - Non-negative (TRUE/FALSE) on success, can't fail - DESCRIPTION - Quickly detect intersections between span tree and block - 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) -{ - H5S_hyper_span_t *curr; /* Pointer to current span in 1st span tree */ - hbool_t ret_value = FALSE; /* Return value */ - - FUNC_ENTER_STATIC_NOERR - - /* Sanity check */ - HDassert(spans); - HDassert(start); - HDassert(end); - - /* Get the span list for spans in this tree */ - curr = spans->head; - - /* 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 */ - - /* Recursively check spans in next dimension down */ - status = H5S__hyper_intersect_block_helper(curr->down, start + 1, end + 1); + /* Add 8 bytes times the rank for each hyperslab selected */ + H5_CHECK_OVERFLOW((8 * space->extent.rank * block_count), hsize_t, size_t); + len += (uint32_t)(8 * space->extent.rank * block_count); - /* If there is a span intersection in the down dimensions, the span trees overlap */ - if(status == TRUE) - HGOTO_DONE(TRUE); + /* Encode each hyperslab in selection */ + H5S__hyper_serialize_helper(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, &pp); + } /* end else */ - /* No intersection in down dimensions, advance to next span */ - curr = curr->next; - } /* end else */ - } /* end else */ - } /* end while */ + /* Encode length */ + UINT32ENCODE(lenp, (uint32_t)len); /* Store the length of the extra information */ - /* Fall through with 'FALSE' return value */ + /* Update encoding pointer */ + *p = pp; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_intersect_block_helper() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_serialize() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_intersect_block + H5S__hyper_deserialize PURPOSE - Detect intersections in span trees + Deserialize the current selection from a user-provided buffer. 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 + herr_t H5S__hyper_deserialize(space, p) + H5S_t *space; IN/OUT: Dataspace pointer to place + selection into + uint32_t version IN: Selection version + uint8_t flags IN: Selection flags + 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 + Non-negative on success/Negative on failure DESCRIPTION - Quickly detect intersections between span tree and block + Deserializes the current selection into a buffer. (Primarily for retrieving + from disk). 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 herr_t +H5S__hyper_deserialize(H5S_t *space, uint32_t H5_ATTR_UNUSED version, uint8_t flags, + const uint8_t **p) { - htri_t ret_value = FAIL; /* Return value */ + unsigned rank; /* Rank of points */ + const uint8_t *pp; /* Local pointer for decoding */ + hsize_t start[H5S_MAX_RANK]; /* Hyperslab start information */ + hsize_t block[H5S_MAX_RANK]; /* Hyperslab block information */ + unsigned u; /* Local counting variable */ + herr_t ret_value = FAIL; /* Return value */ - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_STATIC - /* Sanity check */ + /* Check args */ HDassert(space); - HDassert(start); - HDassert(end); + HDassert(p); + pp = (*p); + HDassert(pp); - /* 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); + /* Deserialize slabs to select */ + /* (The header and rank have already beed decoded) */ + rank = space->extent.rank; /* Retrieve rank from space */ - /* 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") + /* If there is an unlimited dimension, only encode opt_unlim_diminfo */ + if(flags & H5S_SELECT_FLAG_UNLIM) { + hsize_t stride[H5S_MAX_RANK]; /* Hyperslab stride information */ + hsize_t count[H5S_MAX_RANK]; /* Hyperslab count information */ - /* Perform the span-by-span intersection check */ - ret_value = H5S__hyper_intersect_block_helper(space->select.sel_info.hslab->span_lst, start, end); + /* Sanity checks */ + HDassert(H5S_UNLIMITED == HSIZE_UNDEF); + HDassert(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(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 block_count; /* Number of blocks in selection */ + unsigned v; /* Local counting variable */ + + /* Decode the number of blocks */ + UINT32DECODE(pp, block_count); + + /* Set the count & stride for all blocks */ + stride = count = H5S_hyper_ones_g; + + /* Retrieve the coordinates from the buffer */ + for(u = 0; u < block_count; 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(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; done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_intersect_block() */ +} /* end H5S__hyper_deserialize() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_adjust_u_helper + H5S__hyper_span_blocklist PURPOSE - Helper routine to adjust offsets in span trees + Get a list of hyperslab blocks currently selected 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 + 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 - None + Non-negative on success/Negative on failure DESCRIPTION - Adjust the location of the spans in a span tree by subtracting an offset + 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 void -H5S__hyper_adjust_u_helper(H5S_hyper_span_info_t *spans, - const hsize_t *offset) +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) { - FUNC_ENTER_STATIC_NOERR + 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(spans->scratch == (H5S_hyper_span_info_t *)~((size_t)NULL) || - spans->scratch == NULL); - HDassert(offset); - - /* 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 < H5S_MAX_RANK); + HDassert(start); + HDassert(end); + HDassert(startblock); + HDassert(numblocks && *numblocks > 0); + HDassert(buf && *buf); - /* Set the tree's scratch pointer */ - spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL); + /* 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; - /* 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; + /* 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 */ - /* Recursively adjust spans in next dimension down */ - if(span->down != NULL) - H5S__hyper_adjust_u_helper(span->down, offset + 1); + /* Copy previous starting points */ + for(u = 0; u < rank; u++, (*buf)++) + HDmemcpy(*buf, &start[u], sizeof(hsize_t)); - /* Advance to next span in this dimension */ - span = span->next; - } /* end while */ - } /* end if */ + /* Copy starting point for this span */ + HDmemcpy(*buf, &curr->low, sizeof(hsize_t)); + (*buf)++; - FUNC_LEAVE_NOAPI_VOID -} /* end H5S__hyper_adjust_u_helper() */ + /* Copy previous ending points */ + for(u = 0; u < rank; u++, (*buf)++) + HDmemcpy(*buf, &end[u], sizeof(hsize_t)); + + /* Copy starting point for this span */ + HDmemcpy(*buf, &curr->high, sizeof(hsize_t)); + (*buf)++; + + /* Decrement the number of blocks processed */ + (*numblocks)--; + } /* end else */ + } /* end else */ + + /* Advance to next node */ + curr = curr->next; + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_span_blocklist() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_adjust_u + H5S__get_select_hyper_blocklist PURPOSE - Adjust a hyperslab selection by subtracting an offset + Get the list of hyperslab blocks currently selected 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 + 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 Non-negative on success, negative on failure DESCRIPTION - Moves a hyperslab selection by subtracting an offset from it. + 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 herr_t -H5S__hyper_adjust_u(H5S_t *space, const hsize_t *offset) +H5S__get_select_hyper_blocklist(H5S_t *space, hbool_t internal, hsize_t startblock, hsize_t numblocks, hsize_t *buf) { + herr_t ret_value = SUCCEED; /* Return value */ + FUNC_ENTER_STATIC_NOERR - /* Sanity check */ HDassert(space); - HDassert(offset); + HDassert(buf); + HDassert(space->select.sel_info.hslab->unlim_dim < 0); - /* Subtract the offset from the "regular" coordinates, if they exist */ + /* Check for a "regular" hyperslab selection */ if(space->select.sel_info.hslab->diminfo_valid) { - unsigned u; /* Local index variable */ + 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 */ - for(u = 0; u < space->extent.rank; u++) { - HDassert(space->select.sel_info.hslab->opt_diminfo[u].start >= offset[u]); - space->select.sel_info.hslab->opt_diminfo[u].start -= offset[u]; - } /* end for */ - } /* end if */ + /* Set some convienence values */ + ndims = space->extent.rank; + fast_dim = ndims - 1; - /* 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); + /* 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->opt_diminfo; + else + if(space->select.sel_info.hslab->unlim_dim >= 0) + /* + * There is an unlimited dimension so we must use opt_diminfo as + * it has been "clipped" to the current extent. + */ + diminfo = space->select.sel_info.hslab->opt_diminfo; + 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->app_diminfo; - /* Reset the scratch pointers for the next routine which needs them */ - H5S__hyper_span_scratch(space->select.sel_info.hslab->span_lst); - } /* end if */ + /* 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(SUCCEED) -} /* end H5S__hyper_adjust_u() */ + /* We're not done with the iteration */ + done = FALSE; - -/*------------------------------------------------------------------------- - * 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 */ + /* Go iterate over the hyperslabs */ + while(!done && numblocks > 0) { + hsize_t temp_off; /* Offset in a given dimension */ - FUNC_ENTER_STATIC_NOERR + /* Iterate over the blocks in the fastest dimension */ + while(tmp_count[fast_dim] > 0 && numblocks > 0) { - /* Check args */ - HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space)); - HDassert(offset); + /* Check if we should copy this block information */ + if(startblock == 0) { + /* Copy the starting location */ + HDmemcpy(buf, offset, sizeof(hsize_t) * ndims); + buf += ndims; - /* Check for a "regular" hyperslab selection */ - if(space->select.sel_info.hslab->diminfo_valid) { - const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->opt_diminfo; /* Alias for dataspace's diminfo information */ - unsigned u; /* Counter */ + /* Compute the ending location */ + HDmemcpy(buf, offset, sizeof(hsize_t) * ndims); + for(u = 0; u < ndims; u++) + buf[u] += (diminfo[u].block - 1); + buf += ndims; - /* 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 */ + /* Decrement the number of blocks to retrieve */ + numblocks--; + } /* end if */ + else + startblock--; - /* 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); + /* Move the offset to the next sequence to start */ + offset[fast_dim] += diminfo[fast_dim].stride; - /* Save the location of the selection in current dimension */ - block[curr_dim] = curr->low; + /* Decrement the block count */ + tmp_count[fast_dim]--; + } /* end while */ - /* Advance down to next dimension */ - curr = curr->down->head; - curr_dim++; - } /* end while */ - } /* end else */ + /* Work on other dimensions if necessary */ + if(fast_dim > 0 && numblocks > 0) { + int temp_dim; /* Temporary rank holder */ - /* Calculate offset of selection in projected buffer */ - *offset = H5VM_array_offset(space->extent.rank, space->extent.size, block); + /* Reset the block counts */ + tmp_count[fast_dim] = diminfo[fast_dim].count; - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_project_scalar() */ + /* 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]--; - -/*------------------------------------------------------------------------- - * 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 if we have more blocks left */ + if(tmp_count[temp_dim] > 0) + break; - FUNC_ENTER_STATIC_NOERR + /* Check for getting out of iterator */ + if(temp_dim == 0) + done = TRUE; - /* 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); + /* Reset the block count in this dimension */ + tmp_count[temp_dim] = diminfo[temp_dim].count; - /* 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); + /* Wrapped a dimension, go up to next dimension */ + temp_dim--; + } /* end while */ + } /* end if */ - /* Advance down to next dimension */ - down = down->head->down; - curr_dim++; - } /* end while */ - HDassert(down); + /* 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 */ - /* Share the underlying hyperslab span information */ - new_space->select.sel_info.hslab->span_lst = down; - new_space->select.sel_info.hslab->span_lst->count++; + ret_value = H5S__hyper_span_blocklist(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, &startblock, &numblocks, &buf); + } /* end else */ - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_project_simple_lower() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__get_select_hyper_blocklist() */ -/*------------------------------------------------------------------------- - * 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) +/*-------------------------------------------------------------------------- + NAME + H5Sget_select_hyper_blocklist + PURPOSE + Get the list of hyperslab blocks currently selected + 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 + RETURNS + Non-negative 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 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 +--------------------------------------------------------------------------*/ +herr_t +H5Sget_select_hyper_blocklist(hid_t spaceid, hsize_t startblock, + hsize_t numblocks, hsize_t buf[/*numblocks*/]) { - 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 */ - herr_t ret_value = SUCCEED; /* Return value */ + H5S_t *space; /* Dataspace to modify selection of */ + herr_t ret_value; /* return value */ - FUNC_ENTER_STATIC + FUNC_ENTER_API(FAIL) + H5TRACE4("e", "ihh*[a2]h", spaceid, startblock, numblocks, buf); /* 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); - - /* 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 */ - - /* 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") - } /* end if */ - - /* Check for linking into higher span */ - if(prev_span) - prev_span->down = new_span_info; - - /* 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") - } /* end if */ - - /* 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; - - /* Remember previous span info */ - prev_span = new_span; - - /* Advance to next dimension */ - curr_dim++; - } /* end while */ - HDassert(new_space->select.sel_info.hslab->span_lst); - HDassert(prev_span); + 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") - /* Share the underlying hyperslab span information */ - prev_span->down = base_space->select.sel_info.hslab->span_lst; - prev_span->down->count++; + /* 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... */ 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") - - 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() */ + FUNC_LEAVE_API(ret_value) +} /* end H5Sget_select_hyper_blocklist() */ -/*------------------------------------------------------------------------- - * 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 - * - *------------------------------------------------------------------------- - */ +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_bounds_helper + PURPOSE + Gets the bounding box containing the selection. + 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 + RETURNS + 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. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ static herr_t -H5S__hyper_project_simple(const H5S_t *base_space, H5S_t *new_space, - hsize_t *offset) +H5S_hyper_bounds_helper(const H5S_hyper_span_info_t *spans, const hssize_t *offset, hsize_t rank, hsize_t *start, hsize_t *end) { - herr_t ret_value = SUCCEED; /* Return value */ + H5S_hyper_span_t *curr; /* Hyperslab information nodes */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_STATIC + FUNC_ENTER_NOAPI_NOINIT - /* Check args */ - HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space)); - HDassert(new_space); + HDassert(spans); HDassert(offset); + HDassert(rank < H5S_MAX_RANK); + HDassert(start); + HDassert(end); - /* 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") + /* 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") - /* 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") + /* 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]; - /* Set unlim_dim */ - new_space->select.sel_info.hslab->unlim_dim = -1; + /* 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") + } /* end if */ - /* Check for a "regular" hyperslab selection */ - if(base_space->select.sel_info.hslab->diminfo_valid) { - 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->opt_diminfo; /* Alias for dataspace's diminfo information */ - hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */ - unsigned u; /* Local index variable */ - - /* 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); - - /* 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); - - /* The offset is zero when projected into higher dimensions */ - *offset = 0; - - /* 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->app_diminfo[new_space_dim].start = 0; - new_space->select.sel_info.hslab->app_diminfo[new_space_dim].stride = 1; - new_space->select.sel_info.hslab->app_diminfo[new_space_dim].count = 1; - new_space->select.sel_info.hslab->app_diminfo[new_space_dim].block = 1; - - new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].start = 0; - new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].stride = 1; - new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].count = 1; - new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].block = 1; - } /* end for */ - - /* Start at beginning of base space's dimension info */ - base_space_dim = 0; - } /* end else */ - - /* Copy the diminfo */ - while(base_space_dim < base_space->extent.rank) { - new_space->select.sel_info.hslab->app_diminfo[new_space_dim].start = - base_space->select.sel_info.hslab->app_diminfo[base_space_dim].start; - new_space->select.sel_info.hslab->app_diminfo[new_space_dim].stride = - base_space->select.sel_info.hslab->app_diminfo[base_space_dim].stride; - new_space->select.sel_info.hslab->app_diminfo[new_space_dim].count = - base_space->select.sel_info.hslab->app_diminfo[base_space_dim].count; - new_space->select.sel_info.hslab->app_diminfo[new_space_dim].block = - base_space->select.sel_info.hslab->app_diminfo[base_space_dim].block; - - new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].start = - base_space->select.sel_info.hslab->opt_diminfo[base_space_dim].start; - new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].stride = - base_space->select.sel_info.hslab->opt_diminfo[base_space_dim].stride; - new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].count = - base_space->select.sel_info.hslab->opt_diminfo[base_space_dim].count; - new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].block = - base_space->select.sel_info.hslab->opt_diminfo[base_space_dim].block; - - /* Advance to next dimensions */ - base_space_dim++; - new_space_dim++; - } /* end for */ - - /* Indicate that the dimension information is valid */ - new_space->select.sel_info.hslab->diminfo_valid = TRUE; - - /* 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 */ - - /* Clear the block buffer */ - HDmemset(block, 0, sizeof(block)); - - /* 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; - - /* Advance down to next dimension */ - curr = curr->down->head; - curr_dim++; - } /* end while */ - - /* Compute the offset for the down-projection */ - *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block); - - /* 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); - - /* The offset is zero when projected into higher dimensions */ - *offset = 0; - - /* 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 */ - - /* Indicate that the dimension information is not valid */ - new_space->select.sel_info.hslab->diminfo_valid = FALSE; - } /* end else */ - - /* Number of elements selected will be the same */ - new_space->select.num_elem = base_space->select.num_elem; - - /* Set selection type */ - new_space->select.type = H5S_sel_hyper; + /* Advance to next node */ + curr = curr->next; + } /* end while */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_project_simple() */ +} /* end H5S_hyper_bounds_helper() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_adjust_s_helper + H5S__hyper_bounds PURPOSE - Helper routine to adjust offsets in span trees + Gets the bounding box containing the selection. 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 + 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 - None + Non-negative on success, negative on failure DESCRIPTION - Adjust the location of the spans in a span tree by subtracting an offset + 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 void -H5S__hyper_adjust_s_helper(H5S_hyper_span_info_t *spans, - const hssize_t *offset) +static herr_t +H5S__hyper_bounds(const H5S_t *space, hsize_t *start, hsize_t *end) { - FUNC_ENTER_STATIC_NOERR + unsigned rank; /* Dataspace rank */ + unsigned i; /* index variable */ + herr_t ret_value = SUCCEED; /* 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 */ + /* Sanity check */ + HDassert(space); + HDassert(start); + HDassert(end); - /* Set the tree's scratch pointer */ - spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL); + /* 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 */ - /* 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); + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid) { + const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->opt_diminfo; /* local alias for diminfo */ - /* Recursively adjust spans in next dimension down */ - if(span->down != NULL) - H5S__hyper_adjust_s_helper(span->down, offset + 1); + /* 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") - /* Advance to next span in this dimension */ - span = span->next; - } /* end while */ + /* Compute the smallest location in this dimension */ + start[i] = diminfo[i].start + (hsize_t)space->select.offset[i]; + + /* 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 */ - FUNC_LEAVE_NOAPI_VOID -} /* end H5S__hyper_adjust_s_helper() */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_bounds() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_adjust_s + H5S__hyper_offset PURPOSE - Adjust a hyperslab selection by subtracting an offset + Gets the linear offset of the first element for the selection. 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_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 - Moves a hyperslab selection by subtracting an offset from it. + 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 --------------------------------------------------------------------------*/ -herr_t -H5S_hyper_adjust_s(H5S_t *space, const hssize_t *offset) +static herr_t +H5S__hyper_offset(const H5S_t *space, hsize_t *offset) { - 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_NOAPI(FAIL) + FUNC_ENTER_STATIC - /* Sanity checks */ - HDassert(space); + HDassert(space && space->extent.rank>0); HDassert(offset); - /* Subtract the offset from the "regular" coordinates, if they exist */ - if(space->select.sel_info.hslab->diminfo_valid) { - unsigned u; /* Local index variable */ + /* Start at linear offset 0 */ + *offset = 0; - for(u = 0; u < space->extent.rank; u++) { - HDassert((hssize_t)space->select.sel_info.hslab->opt_diminfo[u].start >= offset[u]); - space->select.sel_info.hslab->opt_diminfo[u].start = (hsize_t)((hssize_t)space->select.sel_info.hslab->opt_diminfo[u].start - offset[u]); - } /* end for */ - } /* end if */ + /* Set up pointers to arrays of values */ + rank = space->extent.rank; + sel_offset = space->select.offset; + dim_size = space->extent.size; - /* 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 for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid) { + const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->opt_diminfo; /* Local alias for diminfo */ - /* Reset the scratch pointers for the next routine which needs them */ - H5S__hyper_span_scratch(space->select.sel_info.hslab->span_lst); + /* 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 */ + + /* 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") + + /* Add the hyperslab's offset in this dimension to the total linear offset */ + *offset += (hsize_t)(hyp_offset * (hssize_t)accum); + + /* 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 */ + + /* 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; + + /* Increase the accumulator */ + accum *= dim_size[i]; + } /* end for */ + + /* Get information for the first span, in the slowest changing dimension */ + span = space->select.sel_info.hslab->span_lst->head; + + /* 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 */ + + /* 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") + + /* Add the hyperslab's offset in this dimension to the total linear offset */ + *offset += (hsize_t)(hyp_offset * (hssize_t)dim_accum[i]); + + /* 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_adjust_s() */ +} /* end H5S__hyper_offset() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_normalize_offset + H5S__hyper_unlim_dim PURPOSE - "Normalize" a hyperslab selection by adjusting it's coordinates by the - amount of the selection offset. + Return unlimited dimension of selection, or -1 if none USAGE - 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 + int H5S__hyper_unlim_dim(space) + H5S_t *space; IN: Dataspace pointer to check RETURNS - TRUE/FALSE for hyperslab selection, FAIL on error + Unlimited dimension of selection, or -1 if none (never fails). 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. + 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 --------------------------------------------------------------------------*/ -htri_t -H5S_hyper_normalize_offset(H5S_t *space, hssize_t *old_offset) +static int +H5S__hyper_unlim_dim(const H5S_t *space) { - htri_t ret_value = FALSE; /* Return value */ - - FUNC_ENTER_NOAPI(FAIL) - - /* Sanity checks */ - HDassert(space); - HDassert(old_offset); - - /* Check for hyperslab selection & offset changed */ - if(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS && space->select.offset_changed) { - unsigned u; /* Local index variable */ - - /* 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 */ + FUNC_ENTER_STATIC_NOERR -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_hyper_normalize_offset() */ + FUNC_LEAVE_NOAPI(space->select.sel_info.hslab->unlim_dim); +} /* end H5S__hyper_unlim_dim() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_denormalize_offset + H5S__hyper_num_elem_non_unlim PURPOSE - "Denormalize" a hyperslab selection by reverse adjusting it's coordinates - by the amount of the former selection offset. + Return number of elements in the non-unlimited dimensions 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_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 - Subtracts the old offset from the current selection (canceling out the - effect of the "normalize" routine), then restores the old offset into - the dataspace. + 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_denormalize_offset(H5S_t *space, const hssize_t *old_offset) +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 checks */ + /* Sanity check */ HDassert(space); - HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS); - - /* Call the 'adjust' routine */ - if(H5S_hyper_adjust_s(space, old_offset) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection") + HDassert(num_elem_non_unlim); - /* Copy the selection offset over */ - HDmemcpy(space->select.offset, old_offset, sizeof(hssize_t) * space->extent.rank); + /* 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_denormalize_offset() */ +} /* end H5S__hyper_num_elem_non_unlim() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_append_span + H5S__hyper_is_contiguous PURPOSE - Create a new span and append to span list + Check if a hyperslab selection is contiguous within the dataspace extent. 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 + 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 - Create a new span node and append to a span list. Update the previous - span in the list also. + 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 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 H5_ATTR_PURE htri_t +H5S__hyper_is_contiguous(const H5S_t *space) { - H5S_hyper_span_t *new_span = NULL; - 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_STATIC + FUNC_ENTER_STATIC_NOERR - HDassert(prev_span); - HDassert(span_tree); + HDassert(space); - /* 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") + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid) { + const H5S_hyper_dim_t *diminfo=space->select.sel_info.hslab->opt_diminfo; /* local alias for diminfo */ - /* Make first node in span list */ + /* + * 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 that we haven't already allocated a span tree */ - HDassert(*span_tree == NULL); + /* Initialize flags */ + large_contiguous = TRUE; /* assume true and reset if the dimensions don't match */ + small_contiguous = FALSE; /* assume false initially */ - /* 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") + /* 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 */ - /* Set the span tree's basic information */ - (*span_tree)->count = 1; - (*span_tree)->head = new_span; + /* 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 */ - /* Update previous merged span */ - *prev_span = new_span; - } /* 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 */ - -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() */ - - -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_clip_spans - PURPOSE - Clip a new span tree against the current spans in the hyperslab selection - 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. - RETURNS - non-negative 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 ("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 - 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) -{ - 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 */ - - FUNC_ENTER_STATIC - - /* Check args */ - HDassert(a_spans); - HDassert(b_spans); - HDassert(a_not_b); - HDassert(a_and_b); - HDassert(b_not_a); - - /* 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; + /* Indicate true if it's either a large or small contiguous block */ + if(large_contiguous || small_contiguous) + ret_value = TRUE; } /* 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; - - /* Reset the pointers to the previous spans */ - last_a_not_b = last_a_and_b = last_b_not_a = 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 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 */ + H5S_hyper_span_info_t *spans; /* Hyperslab span info node */ + H5S_hyper_span_t *span; /* Hyperslab span node */ - /* 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") + /* + * 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 */ - /* 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' */ + /* Get information for slowest changing information */ + spans = space->select.sel_info.hslab->span_lst; + span = spans->head; - /* 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 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 */ - /* Check for overlaps between upper part of span 'a' and lower part of span 'b' */ + /* Get the span information for the next fastest dimension */ + spans = span->down; - /* 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)); + /* Cycle down the spans until we run out of down spans or find a non-contiguous span */ + while(spans != NULL) { + span = spans->head; - /* 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") + /* Check that this is the only span and it spans the entire dimension */ + if(span->next != NULL) { + large_contiguous = FALSE; + break; } /* 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") - - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_b_not_a); + /* 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 */ - } /* end else */ - - /* Split off upper part of span 'b' at upper span of span 'a' */ + else { + /* Walk down to the next span */ + spans = span->down; - /* 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_recover_span(&recover_a,&span_a,span_a->next); - - /* 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' */ - - /* 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") - - /* Check for overlaps between middle part of span 'a' and 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(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; - - /* 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_b->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_b->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_b->high,down_b_not_a,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_b_not_a); - } /* end if */ - } /* end else */ - - /* Split off upper part of span 'a' at upper span of span 'b' */ - - /* 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") - - /* Make upper part of span 'a' the new span 'a' */ - H5S__hyper_recover_span(&recover_a,&span_a,tmp_span); - recover_a = TRUE; - - /* 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' */ - - /* 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 */ - - /* Check for overlaps between span 'a' and midle 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(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; - - /* 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_a->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!=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") - - /* 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!=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") - - /* Release the down span tree generated */ - H5S__hyper_free_span_info(down_b_not_a); - } /* end if */ - } /* end else */ - - /* 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' */ - - /* 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") - - /* And advance span 'a' */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - - /* 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' */ - - /* 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 */ - - /* Check for overlaps between lower part of span 'a' and upper 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(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; - - /* 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_a->low,span_b->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!=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") - - /* 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_a->low,span_b->high,down_b_not_a,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_b_not_a); - } /* end if */ - } /* end else */ - - /* Split off upper part of span 'a' at upper span of span 'b' */ - - /* 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") - - /* Make upper part of span 'a' into new span 'a' */ - H5S__hyper_recover_span(&recover_a,&span_a,tmp_span); - recover_a=1; - - /* 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 */ - - /* 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") - - /* Advance span 'b', leave span 'a' */ - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end else */ - } /* end while */ - - /* 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 */ - - /* 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 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 */ - - /* 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") - - /* 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 */ - -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_clip_spans() */ - - -/*-------------------------------------------------------------------------- - 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) -{ - H5S_hyper_span_info_t *merged_spans = NULL; /* Pointer to the merged span tree */ - H5S_hyper_span_info_t *ret_value = NULL; /* 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 { - 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 */ - - /* 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) { - H5S_hyper_span_info_t *tmp_spans; /* Pointer to temporary new span tree */ - H5S_hyper_span_t *tmp_span; /* Pointer to temporary new span */ - - /* 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_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - - /* 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_RESOURCE, 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_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - - /* Get merged span tree for overlapped section */ - tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down); - - /* 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_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - - /* Release merged span tree for overlapped section */ - H5S__hyper_free_span_info(tmp_spans); - } /* end else */ - - /* 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' */ - - /* 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_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span") - - /* Advance span 'a' */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - - /* 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_RESOURCE, 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_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - - /* Get merged span tree for overlapped section */ - tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down); - - /* 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_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - - /* Release merged span tree for overlapped section */ - H5S__hyper_free_span_info(tmp_spans); - } /* end else */ - - /* Copy upper part of span 'a' as new span 'a' (remember to free) */ - - /* 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 new span 'a' to tmp_span */ - H5S__hyper_recover_span(&recover_a,&span_a,tmp_span); - recover_a = TRUE; - - /* 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_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 */ - - /* Get merged span tree for overlapped section */ - tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down); - - /* 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_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - - /* Release merged span tree for overlapped section */ - H5S__hyper_free_span_info(tmp_spans); - } /* end else */ - - /* 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) */ - - /* 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 span 'a' */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - - /* 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") + /* 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 { - /* 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") + /* 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 { - /* No lower part of span 'b' , keep going... */ + /* Walk down to the next span */ + spans = span->down; + + /* Increment dimension */ + u++; } /* end else */ + } /* end else */ + } /* end while */ + } /* end if */ - /* Get merged span tree for overlapped section */ - tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down); + /* Indicate true if it's either a large or small contiguous block */ + if(large_contiguous || small_contiguous) + ret_value = TRUE; + } /* end else */ - /* 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") + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_is_contiguous() */ - /* Release merged span tree for overlapped section */ - H5S__hyper_free_span_info(tmp_spans); - } /* end else */ + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_is_single + PURPOSE + Check if a hyperslab selection is a single block within the dataspace extent. + USAGE + htri_t H5S__hyper_is_single(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 a single block. + 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_single(const H5S_t *space) +{ + htri_t ret_value = TRUE; /* return value */ - /* Copy upper part of span 'a' as new span 'a' */ + FUNC_ENTER_STATIC_NOERR - /* 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") + HDassert(space); - /* Set new span 'a' to tmp_span */ - H5S__hyper_recover_span(&recover_a,&span_a,tmp_span); - recover_a = TRUE; + /* Check for a "single" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid) { + unsigned u; /* index variable */ - /* 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") + /* + * For a regular hyperslab to be single, it must have only one + * block (i.e. count==1 in all dimensions) + */ - /* Advance span 'b' */ - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end else */ - } /* end while */ + /* Check for a single block */ + for(u = 0; u < space->extent.rank; u++) + if(space->select.sel_info.hslab->opt_diminfo[u].count > 1) + HGOTO_DONE(FALSE) + } /* end if */ + else { + H5S_hyper_span_info_t *spans; /* Hyperslab span info node */ - /* 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") + /* + * 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; - /* Advance to next 'a' span, until all processed */ - H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - } /* end while */ - } /* end if */ + /* 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 */ - /* 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") + span = spans->head; - /* Advance to next 'b' span, until all processed */ - H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); - } /* end while */ - } /* end if */ + /* 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 */ - /* Set return value */ - ret_value = merged_spans; - 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") - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_merge_spans_helper() */ +} /* end H5S__hyper_is_single() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_merge_spans + H5S__hyper_is_regular PURPOSE - Merge new hyperslab spans to existing hyperslab selection + Check if a hyperslab selection is "regular" 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. + 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 - 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. + 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 + Doesn't check for "regular" hyperslab selections composed of spans EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_merge_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans, hbool_t can_own) +static htri_t +H5S__hyper_is_regular(const H5S_t *space) { + htri_t ret_value = FAIL; /* return value */ + FUNC_ENTER_STATIC_NOERR /* Check args */ HDassert(space); - HDassert(new_spans); - /* 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; + /* Only simple check for regular hyperslabs for now... */ + if(space->select.sel_info.hslab->diminfo_valid) + ret_value = TRUE; + else + ret_value = FALSE; - /* Get the merged spans */ - merged_spans = H5S__hyper_merge_spans_helper(space->select.sel_info.hslab->span_lst, new_spans); + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_is_regular() */ - /* Sanity checking since we started with some spans, we should still have some after the merge */ - HDassert(merged_spans); + +/*-------------------------------------------------------------------------- + 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 + * Robb Matzke, 1998-08-25 + * The fields which are freed are set to NULL to prevent them from being + * freed again later. This fixes some allocation problems where + * changing the hyperslab selection of one dataspace causes a core dump + * when closing some other dataspace. +--------------------------------------------------------------------------*/ +static herr_t +H5S__hyper_release(H5S_t *space) +{ + herr_t ret_value = SUCCEED; - /* Free the previous spans */ - H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst); + FUNC_ENTER_STATIC - /* Point to the new merged spans */ - space->select.sel_info.hslab->span_lst = merged_spans; - } /* end else */ + /* Check args */ + HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space)); + + /* Reset the number of points selected */ + space->select.num_elem = 0; + + /* 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") - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_merge_spans() */ + /* 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_release() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_spans_nelem + H5S__hyper_recover_span PURPOSE - Count the number of elements in a span tree + Recover a generated span, if appropriate USAGE - hsize_t H5S__hyper_spans_nelem(spans) - const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of + 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 RETURNS - Number of elements in span tree on success; negative on failure + Non-negative on success, negative on failure DESCRIPTION - Counts the number of elements described by the spans in a span tree. + 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. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static hsize_t -H5S__hyper_spans_nelem(const H5S_hyper_span_info_t *spans) +static herr_t +H5S__hyper_recover_span(hbool_t *recover, H5S_hyper_span_t **curr_span, H5S_hyper_span_t *next_span) { - hsize_t ret_value = 0; /* Return value */ - FUNC_ENTER_STATIC_NOERR - /* Count the number of elements in the span tree */ - if(spans != NULL) { - const H5S_hyper_span_t *span; /* Hyperslab span */ + HDassert(recover); + HDassert(curr_span); - 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 if the span should be recovered */ + if(*recover) { + H5S__hyper_free_span(*curr_span); + *recover = FALSE; + } /* end if */ - /* Advance to next span */ - span = span->next; - } /* end while */ - } /* end else */ + /* Set the current span to next span */ + *curr_span = next_span; - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_spans_nelem() */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S__hyper_recover_span() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_make_spans + H5S__hyper_coord_to_span PURPOSE - Create a span tree + Create a span tree for a single element 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 + 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 - 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. + Create a span tree for a single element 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) +static H5S_hyper_span_t * +H5S__hyper_coord_to_span(unsigned rank, const hsize_t *coords) { - 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 */ + 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 */ 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 */ + HDassert(coords); + /* 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") - /* Keep the pointer to the next dimension down's completed list */ - down->head = head; - } /* end for */ + /* 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 */ - /* Indicate that there is a pointer to this tree */ - if(down) - down->count = 1; + /* 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") - /* Success! Return the head of the list in the slowest changing dimension */ - ret_value = down; + /* Set return value */ + ret_value = new_span; done: - /* cleanup if error (ret_value will be NULL) */ - if(!ret_value) { - if(head || down) { - if(head && down) - if(down->head != head) - down = NULL; - - do { - if(down) { - head = down->head; - down = H5FL_FREE(H5S_hyper_span_info_t, down); - } /* end if */ - down = head->down; - - 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 */ + if(ret_value == NULL && down != NULL) + H5S__hyper_free_span_info(down); FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_make_spans() */ +} /* end H5S__hyper_coord_to_span() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_rebuild_helper + H5S__hyper_add_span_element_helper PURPOSE - Helper routine to rebuild optimized hyperslab information if possible. - (It can be recovered with regular selection) + Add a single element to a span tree 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_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 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. + Add a single element to an existing span tree. 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. + Assumes that the element is not already covered by the span tree 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_add_span_element_helper(H5S_hyper_span_info_t *span_tree, + unsigned rank, const hsize_t *coords) { - hbool_t ret_value = TRUE; /* Return value */ + 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 */ + + 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 */ - FUNC_ENTER_STATIC_NOERR + /* 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); - 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 */ + /* Increase size of previous span */ + tmp2_span->high++; + tmp2_span->nelem++; - /* Initialization */ - curr_stride = 1; - curr_low = 0; - outcount = 0; + /* 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); - /* Get "canonical" down span information */ - if(span->down) { - HDassert(span->down->head); + /* Point at earlier span's "down tree" */ + tmp_span->down=tmp2_span->down; - /* 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) + /* Increment reference count on shared "down tree" */ + tmp_span->down->count++; + } /* end else */ - HDmemcpy(canon_down_span_slab_info, span_slab_info, sizeof(H5S_hyper_dim_t) * rank); - } /* end if */ + /* Found span to merge into, break out now */ + break; + } /* end if */ - /* Assign the initial starting point & block size */ - curr_start = span->low; - curr_block = (span->high - span->low) + 1; + /* Advance to next span to check */ + tmp2_span=tmp2_span->next; + } /* end while */ - /* 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 */ + /* 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") - /* 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 */ + /* Add new span tree as span */ + HDassert(tmp_span); + tmp_span->next=new_span; - HDassert(span->down->head); + /* Make scratch pointer point to last span in list */ + HDassert(tspan_info); + tspan_info->scratch=(H5S_hyper_span_info_t *)new_span; - /* 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) + /* Set the proper 'pstride' for new span */ + new_span->pstride=new_span->low-tmp_span->low; + } /* end if */ + else { + /* Does new node adjoin existing node? */ + if(tmp_span->high+1==coords[0]) { + tmp_span->high++; + tmp_span->nelem++; - /* 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]; + /* 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); - 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 */ + /* Increase size of previous span */ + tmp2_span->high++; + tmp2_span->nelem++; - /* Obtain values for stride and block */ - next_stride = span->low - curr_low; - next_block = (span->high - span->low) + 1; + /* 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); - /* 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) + /* Point at earlier span's "down tree" */ + tmp_span->down=tmp2_span->down; - /* Keep the isolated stride to be 1 */ - curr_stride = next_stride; + /* Increment reference count on shared "down tree" */ + tmp_span->down->count++; + } /* end else */ + + /* Found span to merge into, break out now */ + break; + } /* end if */ + + /* 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") - /* Keep current starting point */ - curr_low = span->low; + /* Add new span tree as span */ + HDassert(tmp_span); + tmp_span->next=new_span; - /* Advance to next span */ - prev_span = span; - span = span->next; - outcount++; - } /* end while */ + /* Make scratch pointer point to last span in list */ + tspan_info->scratch=(H5S_hyper_span_info_t *)new_span; - /* 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 */ + /* Set the proper 'pstride' for new span */ + new_span->pstride = new_span->low - tmp_span->low; + } /* end else */ + } /* end else */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_rebuild_helper() */ +} /* end H5S__hyper_add_span_element_helper() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_rebuild + H5S_hyper_add_span_element PURPOSE - Rebuild optimized hyperslab information if possible. - (It can be recovered with regular selection) + Add a single element to a span tree USAGE - hbool_t H5S__hyper_rebuild(space) - const H5S_t *space; IN: Dataspace to check + 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 - 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. + Add a single element to an existing span tree. 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. + Assumes that the element is not already in the dataspace's selection EXAMPLES REVISION LOG - This routine is the optimization of the old version. The previous version - can only detect a singluar selection. This version is general enough to - detect any regular selection. - KY, 2005/9/22 --------------------------------------------------------------------------*/ -static hbool_t -H5S__hyper_rebuild(H5S_t *space) +herr_t +H5S_hyper_add_span_element(H5S_t *space, unsigned rank, const hsize_t *coords) { - H5S_hyper_dim_t top_span_slab_info[H5S_MAX_RANK]; - unsigned rank, curr_dim; - hbool_t ret_value = TRUE; /* 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) + + 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; - FUNC_ENTER_STATIC_NOERR + /* Set selection type */ + space->select.type = H5S_sel_hyper; - /* Check args */ - HDassert(space); - HDassert(space->select.sel_info.hslab->span_lst); + /* Reset "regular" hyperslab flag */ + space->select.sel_info.hslab->diminfo_valid = FALSE; - /* Check the rank of space */ - rank = space->extent.rank; + /* Set unlim_dim */ + space->select.sel_info.hslab->unlim_dim = -1; - /* 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) + /* Set # of elements in selection */ + space->select.num_elem = 1; } /* end if */ else { - H5S_hyper_dim_t *diminfo; - H5S_hyper_dim_t *app_diminfo; - - diminfo = space->select.sel_info.hslab->opt_diminfo; - app_diminfo = space->select.sel_info.hslab->app_diminfo; - - for(curr_dim = 0; curr_dim < rank; curr_dim++) { - - 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; - - } /* end for */ + 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") - space->select.sel_info.hslab->diminfo_valid = TRUE; + /* 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_rebuild() */ +} /* end H5S_hyper_add_span_element() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_generate_spans + H5S_hyper_reset_scratch PURPOSE - Create span tree for a regular hyperslab selection + Reset the scratch information for span tree USAGE - herr_t H5S__hyper_generate_spans(space) - H5S_t *space; IN/OUT: Pointer to dataspace + herr_t H5S_hyper_reset_scratch(space) + H5S_t *space; IN/OUT: Pointer to dataspace to reset scratch pointers 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. + Resets the "scratch" pointers used for various tasks in computing hyperslab + spans. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -static herr_t -H5S__hyper_generate_spans(H5S_t *space) +herr_t +H5S_hyper_reset_scratch(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 */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_STATIC + FUNC_ENTER_NOAPI(FAIL) 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->opt_diminfo[u].count == H5S_UNLIMITED) - HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited count") - if(space->select.sel_info.hslab->opt_diminfo[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->opt_diminfo[u].start; - tmp_stride[u]=space->select.sel_info.hslab->opt_diminfo[u].stride; - tmp_count[u]=space->select.sel_info.hslab->opt_diminfo[u].count; - tmp_block[u]=space->select.sel_info.hslab->opt_diminfo[u].block; - } /* end for */ - /* 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") + /* 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); done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_generate_spans() */ +} /* end H5S_hyper_reset_scratch() */ -#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[]) +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_convert + PURPOSE + Convert a compatible selection to span tree form + USAGE + herr_t H5S_hyper_convert(space) + H5S_t *space; IN/OUT: Pointer to dataspace to convert + RETURNS + Non-negative on success, negative on failure + 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). + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5S_hyper_convert(H5S_t *space) { - 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 */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_STATIC + FUNC_ENTER_NOAPI(FAIL) - /* Check args */ HDassert(space); - HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); - 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") - - /* 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") - - /* Set the number of elements in current selection */ - space->select.num_elem = H5S__hyper_spans_nelem(new_spans); - - /* Indicate that the new_spans are owned */ - new_spans = NULL; - } /* end if */ - else { - hbool_t updated_spans = FALSE; /* Whether the spans in the selection were modified */ - - /* 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") - - 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") - - /* Update the number of elements in current selection */ - space->select.num_elem += H5S__hyper_spans_nelem(b_not_a); - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* 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 */ - 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; + /* 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; - /* Reset the number of items in selection */ - space->select.num_elem=0; + /* 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 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") + case H5S_SEL_HYPERSLABS: /* Hyperslab selection */ + break; - /* Update the number of elements in current selection */ - space->select.num_elem = H5S__hyper_spans_nelem(a_and_b); + 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 */ - /* Indicate that the a_and_b spans are owned */ - a_and_b=NULL; +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_convert() */ - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_intersect_block_helper + PURPOSE + Helper routine to detect intersections in span trees + USAGE + hbool_t H5S__hyper_intersect_block_helper(spans, start, end) + H5S_hyper_span_info_t *spans; IN: First span tree to operate with + hsize_t *start; IN: Starting coordinate for block + hsize_t *end; IN: Ending coordinate for block + RETURN + Non-negative (TRUE/FALSE) on success, can't fail + DESCRIPTION + Quickly detect intersections between span tree and block + 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) +{ + H5S_hyper_span_t *curr; /* Pointer to current span in 1st span tree */ + hbool_t ret_value = FALSE; /* Return value */ - 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; + FUNC_ENTER_STATIC_NOERR - /* Reset the number of items in selection */ - space->select.num_elem=0; + /* Sanity check */ + HDassert(spans); + HDassert(start); + HDassert(end); - /* 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") + /* Get the span list for spans in this tree */ + curr = spans->head; - /* Update the number of elements in current selection */ - space->select.num_elem = H5S__hyper_spans_nelem(a_not_b); + /* 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 */ - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* 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") + /* Recursively check spans in next dimension down */ + status = H5S__hyper_intersect_block_helper(curr->down, start + 1, end + 1); - /* Update the number of elements in current selection */ - space->select.num_elem += H5S__hyper_spans_nelem(b_not_a); + /* If there is a span intersection in the down dimensions, the span trees overlap */ + if(status == TRUE) + HGOTO_DONE(TRUE); - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* No intersection in down dimensions, advance to next span */ + curr = curr->next; + } /* end else */ + } /* end else */ + } /* end while */ - 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; + /* Fall through with 'FALSE' return value */ - /* Reset the number of items in selection */ - space->select.num_elem=0; +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_intersect_block_helper() */ - /* 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") + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_intersect_block + PURPOSE + Detect intersections in span trees + 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 + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Quickly detect intersections between span tree and block + 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) +{ + htri_t ret_value = FAIL; /* Return value */ - /* Update the number of elements in current selection */ - space->select.num_elem = H5S__hyper_spans_nelem(a_not_b); + FUNC_ENTER_NOAPI(FAIL) - /* Indicate that the a_not_b are owned */ - a_not_b=NULL; + /* Sanity check */ + HDassert(space); + HDassert(start); + HDassert(end); - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* 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); - 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; + /* 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") - /* Reset the number of items in selection */ - space->select.num_elem=0; + /* Perform the span-by-span intersection check */ + ret_value = H5S__hyper_intersect_block_helper(space->select.sel_info.hslab->span_lst, start, end); - /* 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") +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_intersect_block() */ - /* Update the number of elements in current selection */ - space->select.num_elem = H5S__hyper_spans_nelem(b_not_a); + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_adjust_u_helper + PURPOSE + Helper routine to adjust offsets in span trees + 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 + 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, + const hsize_t *offset) +{ + FUNC_ENTER_STATIC_NOERR - /* Indicate that the b_not_a are owned */ - b_not_a=NULL; + /* Sanity checks */ + HDassert(spans); + HDassert(spans->scratch == (H5S_hyper_span_info_t *)~((size_t)NULL) || + spans->scratch == NULL); + HDassert(offset); - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* 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 */ - 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 */ + /* Set the tree's scratch pointer */ + spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL); - /* 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 */ + /* 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 check */ - HDassert(space->select.num_elem == 0); + /* Recursively adjust spans in next dimension down */ + if(span->down != NULL) + H5S__hyper_adjust_u_helper(span->down, offset + 1); - /* 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") + /* Advance to next span in this dimension */ + span = span->next; + } /* end while */ + } /* end if */ - /* Set the reference count */ - spans->count=1; + FUNC_LEAVE_NOAPI_VOID +} /* end H5S__hyper_adjust_u_helper() */ - /* Reset the scratch pad space */ - spans->scratch=0; + +/*-------------------------------------------------------------------------- + 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) +{ + FUNC_ENTER_STATIC_NOERR - /* Set to empty tree */ - spans->head=NULL; + /* Sanity check */ + HDassert(space); + HDassert(offset); - /* 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); - } /* end if */ - } /* end else */ - } /* end else */ + /* Subtract the offset from the "regular" coordinates, if they exist */ + if(space->select.sel_info.hslab->diminfo_valid) { + unsigned u; /* Local index variable */ -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") + for(u = 0; u < space->extent.rank; u++) { + HDassert(space->select.sel_info.hslab->opt_diminfo[u].start >= offset[u]); + space->select.sel_info.hslab->opt_diminfo[u].start -= offset[u]; + } /* end for */ + } /* end if */ - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__generate_hyperslab() */ + /* 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 */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_adjust_u() */ /*------------------------------------------------------------------------- - * Function: H5S_select_hyperslab + * Function: H5S__hyper_project_scalar * - * Purpose: Internal version of H5Sselect_hyperslab(). + * Purpose: Projects a single element hyperslab selection into a scalar + * dataspace * - * Return: Non-negative on success/Negative on failure + * Return: Non-negative on success, negative on failure. * * Programmer: Quincey Koziol - * Wednesday, January 10, 2001 + * Sunday, July 18, 2010 * *------------------------------------------------------------------------- */ -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) +static herr_t +H5S__hyper_project_scalar(const H5S_t *space, hsize_t *offset) { - 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 */ + hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */ - FUNC_ENTER_NOAPI(FAIL) + FUNC_ENTER_STATIC_NOERR /* 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 */ + HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space)); + HDassert(offset); - /* 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 */ + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid) { + const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->opt_diminfo; /* Alias for dataspace's diminfo information */ + unsigned u; /* Counter */ - /* 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; + /* Build the table of the initial offset */ 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 */ + /* Keep the offset for later */ + block[u] = diminfo[u].start; } /* 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); - - /* 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 */ + else { + const H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */ + unsigned curr_dim; /* Current dimension being operated on */ - /* 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; - - 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; - - 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" */ - - 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; - - 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; - - case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ - HGOTO_DONE(SUCCEED); /* Selection stays "all" */ - - case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ - op = H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */ - break; - - 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 */ - - /* 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_CANTDELETE, FAIL, "can't convert selection") - } /* end case */ - break; - - 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_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; - - case H5S_SEL_HYPERSLABS: - /* Hyperslab operation on hyperslab selection, OK */ - break; - - 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 */ + /* 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); - case H5S_SEL_ERROR: - case H5S_SEL_N: - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ + /* Save the location of the selection in current dimension */ + block[curr_dim] = curr->low; - 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") + /* Advance down to next dimension */ + curr = curr->down->head; + curr_dim++; + } /* end while */ + } /* end else */ - /* 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") + /* Calculate offset of selection in projected buffer */ + *offset = H5VM_array_offset(space->extent.rank, space->extent.size, block); - /* Save the diminfo */ - space->select.num_elem = 1; - for(u = 0; u < space->extent.rank; u++) { - space->select.sel_info.hslab->app_diminfo[u].start = start[u]; - space->select.sel_info.hslab->app_diminfo[u].stride = stride[u]; - space->select.sel_info.hslab->app_diminfo[u].count = count[u]; - space->select.sel_info.hslab->app_diminfo[u].block = block[u]; + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_project_scalar() */ - space->select.sel_info.hslab->opt_diminfo[u].start = start[u]; - space->select.sel_info.hslab->opt_diminfo[u].stride = opt_stride[u]; - space->select.sel_info.hslab->opt_diminfo[u].count = opt_count[u]; - space->select.sel_info.hslab->opt_diminfo[u].block = opt_block[u]; + +/*------------------------------------------------------------------------- + * 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 */ - space->select.num_elem *= (opt_count[u] * opt_block[u]); - } /* end for */ + FUNC_ENTER_STATIC_NOERR - /* Save unlim_dim */ - space->select.sel_info.hslab->unlim_dim = unlim_dim; + /* 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); - /* Indicate that the dimension information is valid */ - space->select.sel_info.hslab->diminfo_valid = TRUE; + /* 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); - /* Indicate that there's no slab information */ - space->select.sel_info.hslab->span_lst = NULL; + /* Advance down to next dimension */ + down = down->head->down; + curr_dim++; + } /* end while */ + HDassert(down); - /* 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]); + /* Share the underlying hyperslab span information */ + new_space->select.sel_info.hslab->span_lst = down; + new_space->select.sel_info.hslab->span_lst->count++; - /* Set num_elem */ - if(space->select.num_elem != (hsize_t)0) - space->select.num_elem = H5S_UNLIMITED; - } /* end if */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_project_simple_lower() */ - /* 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); + +/*------------------------------------------------------------------------- + * 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 */ + herr_t ret_value = SUCCEED; /* Return value */ - /* 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]; + FUNC_ENTER_STATIC - /* 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") + /* 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); - /* 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") + /* 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 */ - /* 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 */ + /* 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") } /* end if */ - /* 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") + /* Check for linking into higher span */ + if(prev_span) + prev_span->down = new_span_info; - /* Indicate that the regular dimensions are no longer valid */ - space->select.sel_info.hslab->diminfo_valid = FALSE; + /* 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") + } /* end if */ - /* Set selection type */ - /* (Could be overridden by resetting selection to 'none', below) */ - space->select.type = H5S_sel_hyper; + /* Set the span_info information */ + new_span_info->count = 1; + new_span_info->head = new_span; - /* 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") + /* 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; -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_select_hyperslab() */ + /* Remember previous span info */ + prev_span = new_span; - -/*-------------------------------------------------------------------------- - 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 */ + /* Advance to next dimension */ + curr_dim++; + } /* end while */ + HDassert(new_space->select.sel_info.hslab->span_lst); + HDassert(prev_span); - FUNC_ENTER_API(FAIL) - H5TRACE6("e", "iSs*h*h*h*h", space_id, op, start, stride, count, block); + /* Share the underlying hyperslab span information */ + prev_span->down = base_space->select.sel_info.hslab->span_lst; + prev_span->down->count++; - /* 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 */ +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") - /* 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") + 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 */ - if(H5S_select_hyperslab(space, op, start, stride, count, block) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection") + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_project_simple_higher() */ -done: - FUNC_LEAVE_API(ret_value) -} /* end H5Sselect_hyperslab() */ -#else /* NEW_HYPERSLAB_API */ /* Works */ /*------------------------------------------------------------------------- - * Function: H5S_operate_hyperslab + * Function: H5S__hyper_project_simple * - * Purpose: Combines two hyperslabs with an operation, putting the - * result into a third hyperslab selection + * Purpose: Projects a hyperslab selection onto/into a simple dataspace + * of a different rank * - * Return: non-negative on success/NULL on failure + * Return: Non-negative on success, negative on failure. * * Programmer: Quincey Koziol - * Tuesday, October 30, 2001 - * - * Modifications: + * Sunday, July 18, 2010 * *------------------------------------------------------------------------- */ 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_project_simple(const H5S_t *base_space, H5S_t *new_space, + hsize_t *offset) { - 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 */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_STATIC /* Check args */ - HDassert(result); - HDassert(spans2); - HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space)); + HDassert(new_space); + HDassert(offset); - /* 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") + /* 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") - /* Update the number of elements in current selection */ - result->select.num_elem = H5S__hyper_spans_nelem(spans2); + /* 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") - /* Indicate that we took ownership of span2, if allowed */ - if(can_own_span2) - *span2_owned=TRUE; - } /* end if */ - else { - hbool_t updated_spans = FALSE; /* Whether the spans in the selection were modified */ + /* Set unlim_dim */ + new_space->select.sel_info.hslab->unlim_dim = -1; - HDassert(spans1); + /* Check for a "regular" hyperslab selection */ + if(base_space->select.sel_info.hslab->diminfo_valid) { + unsigned base_space_dim; /* Current dimension in the base dataspace */ + unsigned new_space_dim; /* Current dimension in the new dataspace */ - /* 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") + /* 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->opt_diminfo; /* Alias for dataspace's diminfo information */ + hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */ + unsigned u; /* Local index variable */ - /* 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") + /* 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); - /* Update the number of elements in current selection */ - result->select.num_elem = H5S__hyper_spans_nelem(spans1); - } /* end if */ + /* 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); - /* 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") + /* The offset is zero when projected into higher dimensions */ + *offset = 0; - /* Update the number of elements in current selection */ - result->select.num_elem += H5S__hyper_spans_nelem(b_not_a); + /* 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->app_diminfo[new_space_dim].start = 0; + new_space->select.sel_info.hslab->app_diminfo[new_space_dim].stride = 1; + new_space->select.sel_info.hslab->app_diminfo[new_space_dim].count = 1; + new_space->select.sel_info.hslab->app_diminfo[new_space_dim].block = 1; - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].start = 0; + new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].stride = 1; + new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].count = 1; + new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].block = 1; + } /* end for */ - 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") + /* Start at beginning of base space's dimension info */ + base_space_dim = 0; + } /* end else */ - /* Update the number of elements in current selection */ - result->select.num_elem = H5S__hyper_spans_nelem(a_and_b); + /* Copy the diminfo */ + while(base_space_dim < base_space->extent.rank) { + new_space->select.sel_info.hslab->app_diminfo[new_space_dim].start = + base_space->select.sel_info.hslab->app_diminfo[base_space_dim].start; + new_space->select.sel_info.hslab->app_diminfo[new_space_dim].stride = + base_space->select.sel_info.hslab->app_diminfo[base_space_dim].stride; + new_space->select.sel_info.hslab->app_diminfo[new_space_dim].count = + base_space->select.sel_info.hslab->app_diminfo[base_space_dim].count; + new_space->select.sel_info.hslab->app_diminfo[new_space_dim].block = + base_space->select.sel_info.hslab->app_diminfo[base_space_dim].block; - /* Indicate that the result owns the a_and_b spans */ - a_and_b=NULL; + new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].start = + base_space->select.sel_info.hslab->opt_diminfo[base_space_dim].start; + new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].stride = + base_space->select.sel_info.hslab->opt_diminfo[base_space_dim].stride; + new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].count = + base_space->select.sel_info.hslab->opt_diminfo[base_space_dim].count; + new_space->select.sel_info.hslab->opt_diminfo[new_space_dim].block = + base_space->select.sel_info.hslab->opt_diminfo[base_space_dim].block; - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* Advance to next dimensions */ + base_space_dim++; + new_space_dim++; + } /* end for */ - 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") + /* Indicate that the dimension information is valid */ + new_space->select.sel_info.hslab->diminfo_valid = TRUE; - /* Update the number of elements in current selection */ - result->select.num_elem = H5S__hyper_spans_nelem(a_not_b); + /* 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 */ - /* 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") + /* Clear the block buffer */ + HDmemset(block, 0, sizeof(block)); - /* Update the number of elements in current selection */ - result->select.num_elem += H5S__hyper_spans_nelem(b_not_a); + /* 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; - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* Advance down to next dimension */ + curr = curr->down->head; + curr_dim++; + } /* end while */ - 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") + /* Compute the offset for the down-projection */ + *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block); - /* Update the number of elements in current selection */ - result->select.num_elem = H5S__hyper_spans_nelem(a_not_b); + /* 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); - /* Indicate that the result owns the a_not_b spans */ - a_not_b=NULL; + /* The offset is zero when projected into higher dimensions */ + *offset = 0; - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* 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 */ - 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") + /* Indicate that the dimension information is not valid */ + new_space->select.sel_info.hslab->diminfo_valid = FALSE; + } /* end else */ + + /* Number of elements selected will be the same */ + new_space->select.num_elem = base_space->select.num_elem; + + /* Set selection type */ + new_space->select.type = H5S_sel_hyper; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_project_simple() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_adjust_s_helper + PURPOSE + Helper routine to adjust offsets in span trees + 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 + 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, + const hssize_t *offset) +{ + FUNC_ENTER_STATIC_NOERR + + /* Sanity checks */ + HDassert(spans); + HDassert(spans->scratch == (H5S_hyper_span_info_t *)~((size_t)NULL) || + spans->scratch == NULL); + HDassert(offset); + + /* 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 */ - /* Update the number of elements in current selection */ - result->select.num_elem = H5S__hyper_spans_nelem(b_not_a); + /* Set the tree's scratch pointer */ + spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL); - /* Indicate that the result owns the b_not_a spans */ - b_not_a=NULL; + /* 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); - /* Indicate that the spans were updated */ - updated_spans = TRUE; - } /* end if */ - break; + /* Recursively adjust spans in next dimension down */ + if(span->down != NULL) + H5S__hyper_adjust_s_helper(span->down, offset + 1); - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ + /* Advance to next span in this dimension */ + span = span->next; + } /* end while */ + } /* end if */ - /* 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); + FUNC_LEAVE_NOAPI_VOID +} /* end H5S__hyper_adjust_s_helper() */ - /* 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 */ + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_adjust_s + PURPOSE + Adjust a hyperslab selection by subtracting an offset + 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 + 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 +--------------------------------------------------------------------------*/ +herr_t +H5S_hyper_adjust_s(H5S_t *space, const hssize_t *offset) +{ + herr_t ret_value = SUCCEED; /* Return value */ - /* Sanity check */ - HDassert(result->select.num_elem == 0); + FUNC_ENTER_NOAPI(FAIL) - /* 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") + /* Sanity checks */ + HDassert(space); + HDassert(offset); - /* Set the reference count */ - spans->count=1; + /* Subtract the offset from the "regular" coordinates, if they exist */ + if(space->select.sel_info.hslab->diminfo_valid) { + unsigned u; /* Local index variable */ - /* Reset the scratch pad space */ - spans->scratch=0; + for(u = 0; u < space->extent.rank; u++) { + HDassert((hssize_t)space->select.sel_info.hslab->opt_diminfo[u].start >= offset[u]); + space->select.sel_info.hslab->opt_diminfo[u].start = (hsize_t)((hssize_t)space->select.sel_info.hslab->opt_diminfo[u].start - offset[u]); + } /* end for */ + } /* end if */ - /* Set to empty tree */ - spans->head=NULL; + /* 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); - /* 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 */ + /* Reset the scratch pointers for the next routine which needs them */ + H5S__hyper_span_scratch(space->select.sel_info.hslab->span_lst); + } /* end if */ done: FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_operate_hyperslab() */ +} /* end H5S_hyper_adjust_s() */ -/*------------------------------------------------------------------------- - * 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_normalize_offset + PURPOSE + "Normalize" a hyperslab selection by adjusting it's coordinates by the + amount of the selection offset. + USAGE + 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 + TRUE/FALSE for hyperslab selection, FAIL on error + 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) { - 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 */ + htri_t ret_value = FALSE; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT + FUNC_ENTER_NOAPI(FAIL) - /* Check args */ + /* Sanity checks */ HDassert(space); - HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); - HDassert(start); - HDassert(stride); - HDassert(count); - HDassert(block); + HDassert(old_offset); - /* 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") + /* Check for hyperslab selection & offset changed */ + if(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS && space->select.offset_changed) { + 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; + /* 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 */ - /* Reset the other dataspace selection information */ - if(H5S_SELECT_RELEASE(space)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") + /* 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") - /* 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") + /* Zero out the selection offset */ + HDmemset(space->select.offset, 0, sizeof(hssize_t) * space->extent.rank); - /* Set unlim_dim */ - space->select.sel_info.hslab->unlim_dim = -1; + /* Indicate that the offset was normalized */ + ret_value = TRUE; } /* end if */ - /* 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") - 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") - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__generate_hyperslab() */ +} /* end H5S_hyper_normalize_offset() */ -/*------------------------------------------------------------------------- - * 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: - * - *------------------------------------------------------------------------- - */ +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_denormalize_offset + PURPOSE + "Denormalize" a hyperslab selection by reverse adjusting it's coordinates + by the amount of the former selection offset. + 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 + 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. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ 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) +H5S_hyper_denormalize_offset(H5S_t *space, const hssize_t *old_offset) { - 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 */ + herr_t ret_value = SUCCEED; /* Return value */ FUNC_ENTER_NOAPI(FAIL) - /* Check args */ + /* Sanity checks */ HDassert(space); - HDassert(start); - HDassert(count); - HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS); + + /* Call the 'adjust' routine */ + if(H5S_hyper_adjust_s(space, old_offset) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection") + + /* Copy the selection offset over */ + HDmemcpy(space->select.offset, old_offset, sizeof(hssize_t) * space->extent.rank); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_denormalize_offset() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_append_span + PURPOSE + Create a new span and append to span list + 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 + DESCRIPTION + Create a new span node and append to a span list. Update the previous + span in the list also. + 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) +{ + H5S_hyper_span_t *new_span = NULL; + herr_t ret_value = SUCCEED; /* Return value */ - /* Point to the correct stride values */ - if(stride == NULL) - stride = H5S_hyper_ones_g; + FUNC_ENTER_STATIC - /* Point to the correct block values */ - if(block == NULL) - block = H5S_hyper_ones_g; + HDassert(prev_span); + HDassert(span_tree); - /* 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 */ - } /* end if */ + /* 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") - /* - * Check new selection. - */ - for(u=0; uextent.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") + /* Make first node in span list */ - /* 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); + /* Check that we haven't already allocated a span tree */ + HDassert(*span_tree == NULL); - 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 */ + /* 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") - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ - } /* end if */ - } /* end for */ + /* Set the span tree's basic information */ + (*span_tree)->count = 1; + (*span_tree)->head = new_span; - /* 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; + /* Update previous merged span */ + *prev_span = new_span; } /* end if */ + /* Merge or append to existing merged spans list */ 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 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 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); + /* 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); - /* 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") + /* Point the new node's down span at the previous node's down span */ + new_span->down = (*prev_span)->down; - /* 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 */ + /* Increment the reference count to the shared down span */ + new_span->down->count++; + } /* end if */ + } /* end if */ - /* 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; + /* Indicate elements from previous span */ + new_span->pstride = low - (*prev_span)->low; - 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; + /* Append to end of merged spans list */ + (*prev_span)->next = new_span; + *prev_span = new_span; + } /* end else */ + } /* end else */ - 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" */ +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") - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ - break; + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_append_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; + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_clip_spans + PURPOSE + Clip a new span tree against the current spans in the hyperslab selection + 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. + RETURNS + non-negative 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 ("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 + 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) +{ + 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 */ - case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ - HGOTO_DONE(SUCCEED); /* Selection stays "all" */ + FUNC_ENTER_STATIC - case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ - op=H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */ - break; + /* Check args */ + HDassert(a_spans); + HDassert(b_spans); + HDassert(a_not_b); + HDassert(a_and_b); + HDassert(b_not_a); - 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 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; - /* 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; + /* Reset the pointers to the previous spans */ + last_a_not_b = last_a_and_b = last_b_not_a = NULL; + + /* No spans to recover yet */ + recover_a = recover_b = FALSE; - 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); + /* 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 */ - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ - break; + /* 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") - case H5S_SEL_HYPERSLABS: - /* Hyperslab operation on hyperslab selection, OK */ - break; + /* 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' */ - 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 */ + /* 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") - default: - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") - } /* end switch */ + /* 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(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") + /* 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") + } /* 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; - /* 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") + /* 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") - /* Save the diminfo */ - space->select.num_elem=1; - for(u=0; uextent.rank; u++) { - space->select.sel_info.hslab->app_diminfo[u].start = start[u]; - space->select.sel_info.hslab->app_diminfo[u].stride = stride[u]; - space->select.sel_info.hslab->app_diminfo[u].count = count[u]; - space->select.sel_info.hslab->app_diminfo[u].block = block[u]; + /* 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") - space->select.sel_info.hslab->opt_diminfo[u].start = start[u]; - space->select.sel_info.hslab->opt_diminfo[u].stride = opt_stride[u]; - space->select.sel_info.hslab->opt_diminfo[u].count = opt_count[u]; - space->select.sel_info.hslab->opt_diminfo[u].block = opt_block[u]; + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_not_b); + } /* end if */ - space->select.num_elem*=(opt_count[u]*opt_block[u]); - } /* end for */ + /* 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") - /* Save unlim_dim */ - space->select.sel_info.hslab->unlim_dim = unlim_dim; + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_and_b); + } /* end if */ - /* Indicate that the dimension information is valid */ - space->select.sel_info.hslab->diminfo_valid = TRUE; + /* 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") - /* Indicate that there's no slab information */ - 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 */ - /* 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]); + /* Split off upper part of span 'b' at upper span of span 'a' */ - /* Set num_elem */ - if(space->select.num_elem != (hsize_t)0) - space->select.num_elem = H5S_UNLIMITED; - } /* 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); + /* 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") - /* 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]; + /* Advance span 'a' */ + H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - /* 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") + /* 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' */ - /* 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") + /* 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") - /* 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 */ + /* Check for overlaps between middle part of span 'a' and span 'b' */ - /* 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") + /* 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)); - /* Indicate that the regular dimensions are no longer valid */ - space->select.sel_info.hslab->diminfo_valid = FALSE; + /* 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; - /* 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 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") - /* Set selection type */ - space->select.type = H5S_sel_hyper; + /* 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") -done: - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_select_hyperslab() */ + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_not_b); + } /* end if */ - -/*-------------------------------------------------------------------------- - 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 = NULL; /* Dataspace to modify selection of */ - herr_t ret_value=SUCCEED; /* Return value */ + /* 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_ENTER_API(FAIL) - H5TRACE6("e", "iSs*h*h*h*h", space_id, op, start, stride, count, block); + /* 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_b->high,down_b_not_a,NULL)==FAIL) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") - /* 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 */ + /* Split off upper part of span 'a' at upper span of span 'b' */ - if (H5S_select_hyperslab(space, op, start, stride, count, block)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection") + /* 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") -done: - FUNC_LEAVE_API(ret_value) -} /* end H5Sselect_hyperslab() */ + /* Make upper part of span 'a' the new span 'a' */ + H5S__hyper_recover_span(&recover_a,&span_a,tmp_span); + recover_a = TRUE; - -/*-------------------------------------------------------------------------- - 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 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 - RETURNS - Dataspace ID on success/Negative 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 */ + /* 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' */ - FUNC_ENTER_API(FAIL) - H5TRACE6("i", "iSs*h*h*h*h", space_id, op, start, stride, count, block); + /* 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 */ - /* 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(start == NULL || count == NULL) - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified") - if(!(op >= H5S_SELECT_SET && op <= H5S_SELECT_NOTA)) - HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + /* Check for overlaps between span 'a' and midle of span 'b' */ - /* Copy the first dataspace */ - if (NULL == (new_space = H5S_copy (space, TRUE, TRUE))) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to copy dataspace") + /* 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)); - /* 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, FAIL, "unable to set hyperslab selection") + /* 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; - /* Atomize */ - if((ret_value = H5I_register(H5I_DATASPACE, new_space, TRUE)) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom") + /* 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") -done: - if(ret_value < 0 && new_space) - H5S_close(new_space); + /* 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") - FUNC_LEAVE_API(ret_value) -} /* end H5Scombine_hyperslab() */ + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_not_b); + } /* end if */ - -/*------------------------------------------------------------------------- - * 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; /* return value */ + /* 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") - FUNC_ENTER_STATIC + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_and_b); + } /* end if */ - /* Check args */ - HDassert(space1); - HDassert(space2); - HDassert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA); + /* 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") - /* 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") + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_b_not_a); + } /* end if */ + } /* 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") + /* 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' */ - /* 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") + /* 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") - /* 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") + /* And advance span 'a' */ + H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - /* Set unlim_dim */ - new_space->select.sel_info.hslab->unlim_dim = -1; + /* 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' */ - /* 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") + /* 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 */ - /* Set return value */ - ret_value = new_space; + /* Check for overlaps between lower part of span 'a' and upper part of span 'b' */ -done: - if(ret_value == NULL && new_space) - H5S_close(new_space); + /* 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(ret_value) -} /* end H5S__combine_select() */ + /* 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; - -/*-------------------------------------------------------------------------- - 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/Negative 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 */ + /* 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_API(FAIL) - H5TRACE3("i", "iSsi", space1_id, op, space2_id); + /* 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") - /* 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") + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_not_b); + } /* 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") + /* 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") - /* 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") + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_a_and_b); + } /* end if */ - /* 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") + /* 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") - /* Atomize */ - if((ret_value = H5I_register(H5I_DATASPACE, new_space, TRUE)) < 0) - HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom") + /* Release the down span tree generated */ + H5S__hyper_free_span_info(down_b_not_a); + } /* end if */ + } /* end else */ -done: - if(ret_value < 0 && new_space) - H5S_close(new_space); + /* Split off upper part of span 'a' at upper span of span 'b' */ - FUNC_LEAVE_API(ret_value) -} /* end H5Scombine_select() */ + /* 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") - -/*------------------------------------------------------------------------- - * Function: H5S_select_select - * - * Purpose: Internal version of H5Sselect_select(). - * - * Return: New dataspace on success/NULL on failure - * - * Programmer: Quincey Koziol - * Tuesday, October 30, 2001 - * - *------------------------------------------------------------------------- - */ -static herr_t -H5S_select_select (H5S_t *space1, H5S_seloper_t op, H5S_t *space2) -{ - 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 */ + /* Make upper part of span 'a' into new span 'a' */ + H5S__hyper_recover_span(&recover_a,&span_a,tmp_span); + recover_a=1; - FUNC_ENTER_NOAPI_NOINIT + /* 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 */ - /* Check args */ - HDassert(space1); - HDassert(space2); - HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + /* 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") - /* 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") + /* Advance span 'b', leave span 'a' */ + H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); + } /* end else */ + } /* end while */ - /* 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; + /* 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 */ - /* Reset the other dataspace selection information */ - if(H5S_SELECT_RELEASE(space1)<0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") + /* 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") - /* 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") + /* 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 */ - /* Set unlim_dim */ - space1->select.sel_info.hslab->unlim_dim = -1; + /* 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") - /* 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") + /* 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 */ done: - if(tmp_spans!=NULL) - H5S__hyper_free_span_info(tmp_spans); - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S_select_select() */ +} /* end H5S__hyper_clip_spans() */ /*-------------------------------------------------------------------------- NAME - H5Sselect_select + H5S__hyper_merge_spans_helper PURPOSE - Refine a hyperslab selection with an operation using a second hyperslab - to modify it. + Merge two hyperslab span tree together 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 + 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 - Non-negative on success/Negative on failure + Pointer to span tree containing the merged spans on success, NULL 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. + Merge two sets of hyperslab spans together and return the span tree from + the merged set. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES REVISION LOG --------------------------------------------------------------------------*/ -herr_t -H5Sselect_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id) +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) { - H5S_t *space1; /* First Dataspace */ - H5S_t *space2; /* Second Dataspace */ - herr_t ret_value = SUCCEED; /* Return value */ - - FUNC_ENTER_API(FAIL) - H5TRACE3("e", "iSsi", space1_id, op, space2_id); - - /* 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 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") + 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 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") + FUNC_ENTER_STATIC - /* Go refine the first selection */ - if(H5S_select_select(space1, op, space2) < 0) - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to modify hyperslab 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)); -done: - FUNC_LEAVE_API(ret_value) -} /* end H5Sselect_select() */ -#endif /* NEW_HYPERSLAB_API */ /* Works */ + /* 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 { + 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 */ - -/*-------------------------------------------------------------------------- - 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) -{ - 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 */ + /* Get the pointers to the 'a' and 'b' span lists */ + span_a = a_spans->head; + span_b = b_spans->head; - FUNC_ENTER_STATIC_NOERR + /* Set the pointer to the previous spans */ + prev_span_merge = NULL; - /* Check args */ - HDassert(space); - HDassert(iter); - HDassert(maxseq > 0); - HDassert(maxelem > 0); - HDassert(nseq); - HDassert(nelem); - HDassert(off); - HDassert(len); + /* No spans to recover yet */ + recover_a = recover_b = FALSE; - /* Set the rank of the fastest changing dimension */ - ndims = space->extent.rank; - fast_dim = (ndims - 1); + /* 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 */ - /* 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; + /* 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_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - /* 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; + /* 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_RESOURCE, 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_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - /* 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]; - } /* end for */ + /* Get merged span tree for overlapped section */ + tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down); - /* 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]; + /* 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_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - /* Range check against number of elements left in selection */ - HDassert(io_bytes_left <= (iter->elmt_left * elem_size)); + /* Release merged span tree for overlapped section */ + H5S__hyper_free_span_info(tmp_spans); + } /* end else */ - /* Take care of any partial spans leftover from previous I/Os */ - if(abs_arr[fast_dim]!=curr_span->low) { + /* 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' */ - /* Finish the span in the fastest changing dimension */ + /* 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_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span") - /* 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); + /* Advance span 'a' */ + H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - /* Check number of bytes against upper bounds allowed */ - if(span_size>io_bytes_left) - span_size=io_bytes_left; + /* 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_RESOURCE, 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_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - /* Add the partial span to the list of sequences */ - off[curr_seq]=loc_off; - len[curr_seq]=span_size; + /* Get merged span tree for overlapped section */ + tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down); - /* Increment sequence count */ - curr_seq++; + /* 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_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - /* Set the location of the last span's end */ - last_span_end=loc_off+span_size; + /* Release merged span tree for overlapped section */ + H5S__hyper_free_span_info(tmp_spans); + } /* end else */ - /* Decrement I/O left to perform */ - io_bytes_left-=span_size; + /* Copy upper part of span 'a' as new span 'a' (remember to free) */ - /* 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; + /* 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") - if(NULL != curr_span) { - /* Move location offset of destination */ - loc_off += (curr_span->low - abs_arr[fast_dim]) * elem_size; + /* Set new span 'a' to tmp_span */ + H5S__hyper_recover_span(&recover_a,&span_a,tmp_span); + recover_a = TRUE; - /* Move iterator for fastest changing dimension */ - abs_arr[fast_dim] = curr_span->low; + /* Advance span 'b' */ + H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); } /* end if */ - } /* end if */ - else { - abs_arr[fast_dim] += span_size / elem_size; + /* 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_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 */ - /* Check if we are still within the span */ - if(abs_arr[fast_dim] <= curr_span->high) { - iter->u.hyp.span[fast_dim] = curr_span; - } /* end if */ - /* If we walked off that span, advance to the next span */ - else { - /* Advance span in this dimension */ - curr_span = curr_span->next; + /* Get merged span tree for overlapped section */ + tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down); - /* 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 */ + /* 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_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") - /* Adjust iterator pointers */ + /* Release merged span tree for overlapped section */ + H5S__hyper_free_span_info(tmp_spans); + } /* end else */ - if(NULL == curr_span) { -/* Same as code in main loop */ - /* Start at the next fastest dim */ - curr_dim = (int)(fast_dim - 1); + /* 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) */ - /* Work back up through the dimensions */ - while(curr_dim >= 0) { - /* Reset the current span */ - curr_span = iter->u.hyp.span[curr_dim]; + /* 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") - /* Increment absolute position */ - abs_arr[curr_dim]++; + /* Advance span 'a' */ + H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); - /* Check if we are still within the span */ - if(abs_arr[curr_dim] <= curr_span->high) { - break; + /* Set new span 'b' to tmp_span */ + H5S__hyper_recover_span(&recover_b,&span_b,tmp_span); + recover_b = TRUE; } /* 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 the span in the current dimension */ - ispan[curr_dim] = curr_span; - - /* Reset absolute position */ - abs_arr[curr_dim] = curr_span->low; - - break; + /* 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 { - /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */ - curr_dim--; + /* No lower part of span 'b' , keep going... */ } /* end else */ - } /* end else */ - } /* end while */ - /* 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); + /* Get merged span tree for overlapped section */ + tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down); - /* Increment current dimension */ - curr_dim++; + /* 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") - /* Set the new span_info & span for this dimension */ - iter->u.hyp.span[curr_dim] = curr_span->down->head; + /* Release merged span tree for overlapped section */ + H5S__hyper_free_span_info(tmp_spans); + } /* end else */ - /* Advance span down the tree */ - curr_span = curr_span->down->head; + /* Copy upper part of span 'a' as new span 'a' */ - /* Reset the absolute offset for the dim */ - abs_arr[curr_dim] = curr_span->low; - } /* end while */ + /* 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") - /* Verify that the curr_span points to the fastest dim */ - HDassert(curr_span == iter->u.hyp.span[fast_dim]); + /* Set new span 'a' to tmp_span */ + H5S__hyper_recover_span(&recover_a,&span_a,tmp_span); + recover_a = TRUE; - /* 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]; + /* 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") + + /* Advance span 'b' */ + H5S__hyper_recover_span(&recover_b,&span_b,span_b->next); } /* end else */ - else - /* We had better be done with I/O or bad things are going to happen... */ - HDassert(io_bytes_left == 0); + } /* end while */ + + /* 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") + + /* Advance to next 'a' span, until all processed */ + H5S__hyper_recover_span(&recover_a,&span_a,span_a->next); + } /* end while */ } /* 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); + /* 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") - /* Adjust location offset of destination to compensate for initial increment below */ - loc_off -= curr_span->pstride; + /* 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 */ - /* Loop over all the spans in the fastest changing dimension */ - while(curr_span != NULL) { - /* Move location offset of destination */ - loc_off += curr_span->pstride; + /* Set return value */ + ret_value = merged_spans; - /* Compute the number of elements to attempt in this span */ - H5_CHECKED_ASSIGN(span_size, size_t, curr_span->nelem, hsize_t); +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") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_merge_spans_helper() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_merge_spans + PURPOSE + Merge new hyperslab spans to existing hyperslab selection + 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. + 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 to be non-overlapping with the existing spans in + the dataspace's current hyperslab selection. + 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) +{ + FUNC_ENTER_STATIC_NOERR - /* 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 args */ + HDassert(space); + HDassert(new_spans); -/* COMMON */ - /* Store the I/O information for the span */ + /* 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 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; + /* Get the merged spans */ + merged_spans = H5S__hyper_merge_spans_helper(space->select.sel_info.hslab->span_lst, new_spans); - /* Increment the number of sequences in arrays */ - curr_seq++; - } /* end else */ + /* Sanity checking since we started with some spans, we should still have some after the merge */ + HDassert(merged_spans); - /* Set the location of the last span's end */ - last_span_end = loc_off + span_size; -/* end COMMON */ + /* Free the previous spans */ + H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst); - /* Break out now, we are finished with I/O */ - break; - } /* end if */ - else { - /* Decrement I/O left to perform */ - io_bytes_left -= span_size; + /* Point to the new merged spans */ + space->select.sel_info.hslab->span_lst = merged_spans; + } /* end else */ -/* COMMON */ - /* Store the I/O information for the span */ + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S__hyper_merge_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; + +/*-------------------------------------------------------------------------- + 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(const H5S_hyper_span_info_t *spans) +{ + hsize_t ret_value = 0; /* Return value */ - /* Increment the number of sequences in arrays */ - curr_seq++; - } /* end else */ + FUNC_ENTER_STATIC_NOERR - /* Set the location of the last span's end */ - last_span_end = loc_off + span_size; -/* end COMMON */ + /* Count the number of elements in the span tree */ + if(spans != NULL) { + const H5S_hyper_span_t *span; /* Hyperslab span */ - /* 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 */ + 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; - /* Move to next span in fastest changing dimension */ - curr_span=curr_span->next; + /* Advance to next span */ + span = span->next; } /* end while */ + } /* end else */ - /* 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); - - /* 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 */ - else { - /* Advance span in this dimension */ - curr_span=curr_span->next; + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_spans_nelem() */ - /* 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 */ - } /* end else */ - } /* end if */ + +/*-------------------------------------------------------------------------- + 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 *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 */ - /* Adjust iterator pointers */ + FUNC_ENTER_STATIC - /* Start at the next fastest dim */ - curr_dim = (int)(fast_dim - 1); + /* Check args */ + HDassert(rank > 0); + HDassert(start); + HDassert(stride); + HDassert(count); + HDassert(block); - /* Work back up through the dimensions */ - while(curr_dim >= 0) { - /* Reset the current span */ - curr_span=iter->u.hyp.span[curr_dim]; + /* Start creating spans in fastest changing dimension */ + for(i = (int)(rank - 1); i >= 0; i--) { - /* Increment absolute position */ - abs_arr[curr_dim]++; + /* Sanity check */ + if(0 == count[i]) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, NULL, "count == 0 is invalid") - /* 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; + /* Start a new list in this dimension */ + head = NULL; + last_span = NULL; - /* 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; + /* 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 */ - /* Reset absolute position */ - abs_arr[curr_dim]=curr_span->low; + /* 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") - 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 */ + /* 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; - /* 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); + /* Append to the list of spans in this dimension */ + if(head == NULL) + head = span; + else + last_span->next = span; - /* Increment current dimension to the next dimension down */ - curr_dim++; + /* Move current pointer */ + last_span = span; - /* Set the new span for the next dimension down */ - iter->u.hyp.span[curr_dim] = curr_span->down->head; + /* 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 */ - /* Advance span down the tree */ - curr_span = curr_span->down->head; + /* 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") - /* Reset the absolute offset for the dim */ - abs_arr[curr_dim] = curr_span->low; - } /* end while */ + /* Keep the pointer to the next dimension down's completed list */ + down->head = head; - /* Verify that the curr_span points to the fastest dim */ - HDassert(curr_span == iter->u.hyp.span[fast_dim]); - } /* end else */ + } /* end for */ - /* 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 */ + /* Indicate that there is a pointer to this tree */ + if(down) + down->count = 1; - /* Decrement number of elements left in iterator */ - io_used = (io_left - (io_bytes_left / elem_size)); - iter->elmt_left -= io_used; + /* Success! Return the head of the list in the slowest changing dimension */ + ret_value = down; - /* Set the number of sequences generated */ - *nseq = curr_seq; +done: + /* cleanup if error (ret_value will be NULL) */ + if(!ret_value) { + if(head || down) { + if(head && down) + if(down->head != head) + down = NULL; - /* Set the number of elements used */ - *nelem = io_used; + do { + if(down) { + head = down->head; + down = H5FL_FREE(H5S_hyper_span_info_t, down); + } /* end if */ + down = head->down; - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_get_seq_list_gen() */ + 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 */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_make_spans() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_get_seq_list_opt + H5S__hyper_rebuild_helper PURPOSE - Create a list of offsets & lengths for a selection + Helper routine to rebuild optimized hyperslab information if possible. + (It can be recovered with regular 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 + 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 RETURNS - Non-negative on success/Negative on failure. + TRUE/FALSE for hyperslab selection rebuilt 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. + 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 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) +static hbool_t +H5S__hyper_rebuild_helper(const H5S_hyper_span_t *span, H5S_hyper_dim_t span_slab_info[], + unsigned rank) { - 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 */ + hbool_t ret_value = TRUE; /* Return value */ FUNC_ENTER_STATIC_NOERR - /* Check args */ - HDassert(space); - HDassert(iter); - HDassert(maxseq > 0); - HDassert(maxelem > 0); - HDassert(nseq); - HDassert(nelem); - HDassert(off); - HDassert(len); + 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 */ - /* Set the local copy of the diminfo pointer */ - tdiminfo = iter->u.hyp.diminfo; + /* Initialization */ + curr_stride = 1; + curr_low = 0; + outcount = 0; - /* 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; + /* Get "canonical" down span information */ + if(span->down) { + HDassert(span->down->head); - /* Set the local copy of the selection offset */ - sel_off = iter->u.hyp.sel_off; + /* 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) - /* 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; + HDmemcpy(canon_down_span_slab_info, span_slab_info, sizeof(H5S_hyper_dim_t) * rank); + } /* end if */ - /* Set the local copy of the selection offset */ - sel_off = space->select.offset; + /* Assign the initial starting point & block size */ + curr_start = span->low; + curr_block = (span->high - span->low) + 1; - /* Set up the pointer to the size of the memory space */ - mem_size = space->extent.size; - } /* end else */ + /* 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 */ - /* 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 */ + /* 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 */ - /* 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); + HDassert(span->down->head); - /* 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))); + /* 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) - /* 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. - */ + /* 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]; - /* Keep the number of elements we started with */ - start_io_left = io_left; + 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 */ + + /* Obtain values for stride and block */ + next_stride = span->low - curr_low; + next_block = (span->high - span->low) + 1; + + /* 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) + + /* Keep the isolated stride to be 1 */ + curr_stride = next_stride; + } /* end if */ + + /* Keep current starting point */ + curr_low = span->low; - /* Compute the arrays to perform I/O on */ + /* Advance to next span */ + prev_span = span; + span = span->next; + outcount++; + } /* end while */ - /* 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]); + /* 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 */ - /* 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 */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_rebuild_helper() */ - /* Compute the initial buffer offset */ - for(u = 0, loc = 0; u < ndims; u++) - loc += offset[u] * slab[u]; + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_rebuild + PURPOSE + Rebuild optimized hyperslab information if possible. + (It can be recovered with regular selection) + USAGE + hbool_t H5S__hyper_rebuild(space) + const H5S_t *space; IN: Dataspace to check + 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 + This routine is the optimization of the old version. The previous version + can only detect a singluar selection. This version is general enough to + detect any regular selection. + KY, 2005/9/22 +--------------------------------------------------------------------------*/ +static hbool_t +H5S__hyper_rebuild(H5S_t *space) +{ + H5S_hyper_dim_t top_span_slab_info[H5S_MAX_RANK]; + unsigned rank, curr_dim; + hbool_t ret_value = TRUE; /* Return value */ - /* Set the number of elements to write each time */ - H5_CHECKED_ASSIGN(actual_elem, size_t, tdiminfo[fast_dim].block, hsize_t); + FUNC_ENTER_STATIC_NOERR - /* Set the number of actual bytes */ - actual_bytes = actual_elem * elem_size; + /* Check args */ + HDassert(space); + HDassert(space->select.sel_info.hslab->span_lst); - /* 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]); + /* Check the rank of space */ + rank = space->extent.rank; - /* 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 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; - /* Don't go over the maximum number of sequences allowed */ - tot_blk_count = MIN(tot_blk_count, (maxseq - curr_seq)); + diminfo = space->select.sel_info.hslab->opt_diminfo; + app_diminfo = space->select.sel_info.hslab->app_diminfo; - /* 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]; + for(curr_dim = 0; curr_dim < rank; curr_dim++) { - /* Compute the amount to skip between blocks */ - for(u = 0; u < ndims; u++) - skip[u] = (tdiminfo[u].stride - tdiminfo[u].block) * slab[u]; + 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; - /* 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); + } /* end for */ - /* Make certain this entire row will fit into buffer */ - fast_dim_count = MIN(fast_dim_count, tot_blk_count); + space->select.sel_info.hslab->diminfo_valid = TRUE; + } /* end else */ - /* Number of blocks to sequence over */ - act_blk_count = fast_dim_count; +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_rebuild() */ - /* 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; + +/*-------------------------------------------------------------------------- + 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 */ - /* Increment sequence count */ - curr_seq++; + FUNC_ENTER_STATIC - /* Increment information to reflect block just processed */ - loc += fast_dim_buf_off; + HDassert(space); + HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS); - /* Decrement number of blocks */ - fast_dim_count--; - } /* end while */ + /* 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->opt_diminfo[u].count == H5S_UNLIMITED) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited count") + if(space->select.sel_info.hslab->opt_diminfo[u].block == H5S_UNLIMITED) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "can't generate spans with unlimited block") - /* Decrement number of elements left */ - io_left -= actual_elem * act_blk_count; + tmp_start[u]=space->select.sel_info.hslab->opt_diminfo[u].start; + tmp_stride[u]=space->select.sel_info.hslab->opt_diminfo[u].stride; + tmp_count[u]=space->select.sel_info.hslab->opt_diminfo[u].count; + tmp_block[u]=space->select.sel_info.hslab->opt_diminfo[u].block; + } /* end for */ - /* Decrement number of blocks left */ - tot_blk_count -= act_blk_count; + /* 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") - /* Increment information to reflect block just processed */ - tmp_count[fast_dim] += act_blk_count; +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_generate_spans() */ - /* 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]; + +/*------------------------------------------------------------------------- + * 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 */ - /* 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; + FUNC_ENTER_STATIC - /* 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]++; + /* Check args */ + HDassert(space); + HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + HDassert(start); + HDassert(stride); + HDassert(count); + HDassert(block); - /* 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]++; + /* 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") - /* 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 */ + /* 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") - /* 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 */ + /* Set the number of elements in current selection */ + space->select.num_elem = H5S__hyper_spans_nelem(new_spans); + + /* Indicate that the new_spans are owned */ + new_spans = NULL; } /* end if */ + else { + hbool_t updated_spans = FALSE; /* Whether the spans in the selection were modified */ - /* 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 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") - /* Reset copy of number of blocks in fastest dimension */ - H5_CHECKED_ASSIGN(fast_dim_count, size_t, tdiminfo[fast_dim].count, hsize_t); + 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") - /* Read in data until an entire sequence can't be written out any longer */ - while(curr_rows > 0) { + /* Update the number of elements in current selection */ + space->select.num_elem += H5S__hyper_spans_nelem(b_not_a); -#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; + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* end if */ + 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: + /* 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; - /* Decrement number of blocks */ - fast_dim_count--; - } /* end while */ -#else /* NO_DUFFS_DEVICE */ - { - size_t duffs_index; /* Counting index for Duff's device */ + /* Reset the number of items in selection */ + space->select.num_elem=0; - 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 - case 7: - DUFF_GUTS - case 6: - DUFF_GUTS - case 5: - DUFF_GUTS - case 4: - DUFF_GUTS - case 3: - DUFF_GUTS - case 2: - DUFF_GUTS - case 1: - DUFF_GUTS - } while (--duffs_index > 0); - } /* end switch */ - } -#endif /* NO_DUFFS_DEVICE */ -#undef DUFF_GUTS + /* 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") - /* Increment offset in destination buffer */ - loc += wrap[fast_dim]; + /* Update the number of elements in current selection */ + space->select.num_elem = H5S__hyper_spans_nelem(a_and_b); - /* 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]++; + /* Indicate that the a_and_b spans are owned */ + a_and_b=NULL; - /* 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) + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* end if */ 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 */ + 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; - /* Decrement dimension count */ - temp_dim--; - } /* end while */ + /* Reset the number of items in selection */ + space->select.num_elem=0; - /* Decrement the number of rows left */ - curr_rows--; - } /* end while */ + /* 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") - /* Adjust the number of blocks & elements left to transfer */ + /* Update the number of elements in current selection */ + space->select.num_elem = H5S__hyper_spans_nelem(a_not_b); - /* 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)); + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* 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") - /* 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); + /* Update the number of elements in current selection */ + space->select.num_elem += H5S__hyper_spans_nelem(b_not_a); - /* 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; + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* end if */ + break; - /* 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; + 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; - /* Increment sequence count */ - curr_seq++; + /* Reset the number of items in selection */ + space->select.num_elem=0; - /* Increment information to reflect block just processed */ - loc += fast_dim_buf_off; + /* 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") - /* Decrement number of blocks */ - fast_dim_count--; - } /* end while */ + /* Update the number of elements in current selection */ + space->select.num_elem = H5S__hyper_spans_nelem(a_not_b); - /* Decrement number of elements left */ - io_left -= actual_elem * tot_blk_count; + /* Indicate that the a_not_b are owned */ + a_not_b=NULL; - /* Increment information to reflect block just processed */ - offset[fast_dim] += (fast_dim_stride * tot_blk_count); /* move the offset in the fastest dimension */ + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* end if */ + break; - /* 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; + 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; - /* Store the sequence information */ - off[curr_seq] = loc; - len[curr_seq] = actual_bytes; + /* Reset the number of items in selection */ + space->select.num_elem=0; - /* Increment sequence count */ - curr_seq++; + /* 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") - /* Decrement the number of elements left */ - io_left -= actual_elem; + /* Update the number of elements in current selection */ + space->select.num_elem = H5S__hyper_spans_nelem(b_not_a); - /* Increment buffer correctly */ - offset[fast_dim] += actual_elem; - } /* end if */ + /* Indicate that the b_not_a are owned */ + b_not_a=NULL; + + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* end if */ + 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 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 */ + + /* Sanity check */ + HDassert(space->select.num_elem == 0); - /* don't bother checking slower dimensions */ - HDassert(io_left == 0 || curr_seq == maxseq); - } /* end if */ + /* 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") - /* Update the iterator */ + /* Set the reference count */ + spans->count=1; - /* 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]); + /* Reset the scratch pad space */ + spans->scratch=0; - /* Decrement the number of elements left in selection */ - iter->elmt_left -= (start_io_left - io_left); + /* Set to empty tree */ + spans->head=NULL; - /* Increment the number of sequences generated */ - *nseq += curr_seq; + /* 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); + } /* end if */ + } /* end else */ + } /* end else */ - /* Increment the number of elements used */ - *nelem += start_io_left - io_left; +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(SUCCEED) -} /* end H5S__hyper_get_seq_list_opt() */ + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__generate_hyperslab() */ -/*-------------------------------------------------------------------------- - NAME - H5S__hyper_get_seq_list_single - PURPOSE - Create a list of offsets & lengths for a 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 - 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_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) +/*------------------------------------------------------------------------- + * 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) { - 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 */ + 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_STATIC_NOERR + FUNC_ENTER_NOAPI(FAIL) /* Check args */ HDassert(space); - HDassert(iter); - HDassert(maxseq > 0); - HDassert(maxelem > 0); - HDassert(nseq); - HDassert(nelem); - HDassert(off); - HDassert(len); + HDassert(start); + HDassert(count); + HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); - /* Set a local copy of the diminfo pointer */ - tdiminfo = iter->u.hyp.diminfo; + /* Point to the correct stride values */ + if(stride == NULL) + stride = H5S_hyper_ones_g; - /* 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; + /* Point to the correct block values */ + if(block == NULL) + block = H5S_hyper_ones_g; - /* Set the local copy of the selection offset */ - sel_off = iter->u.hyp.sel_off; + /* 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") - /* 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; + /* 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); - /* Set the local copy of the selection offset */ - sel_off = space->select.offset; + 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 */ - /* Set up the pointer to the size of the memory space */ - mem_size = space->extent.size; - } /* end else */ - 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 */ + } /* end if */ - /* 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 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 */ - /* 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]); + /* 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 */ + + /* 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); - /* 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]); + /* 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") - /* Compute the initial buffer offset */ - for(u = 0, loc = 0; u < ndims; u++) - loc += offset[u] * slab[u]; + /* 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 */ - /* Set local copies of information for the fastest changing dimension */ - fast_dim_block = tdiminfo[fast_dim].block; + /* 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; - /* 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); + 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; - /* 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); + 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" */ - /* Don't go over the maximum number of sequences allowed */ - tot_blk_count = MIN(tot_blk_count, maxseq); + 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 number of elements to write each time */ - H5_CHECKED_ASSIGN(actual_elem, size_t, fast_dim_block, hsize_t); + 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; - /* Check for blocks to operate on */ - if(tot_blk_count > 0) { - size_t actual_bytes; /* The actual number of bytes to copy */ + case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */ + HGOTO_DONE(SUCCEED); /* Selection stays "all" */ - /* Set the number of actual bytes */ - actual_bytes = actual_elem * elem_size; + case H5S_SELECT_AND: /* Binary "and" operation for hyperslabs */ + op = H5S_SELECT_SET; /* Maps to "set" operation when applied to "none" selection */ + break; - /* Check for 1-dim selection */ - if(0 == fast_dim) { - /* Sanity checks */ - HDassert(1 == tot_blk_count); - HDassert(io_left == actual_elem); + 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 */ - /* 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 */ + /* 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; - /* 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; + /* 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; - } /* 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; + 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); - /* Decrement block count */ - blk_count--; - } /* end while */ + 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; - /* 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 */ + case H5S_SEL_HYPERSLABS: + /* Hyperslab operation on hyperslab selection, OK */ + break; - /* Set the starting block location */ - for(u = 0; u < ndims; u++) - tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start; + 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 */ - /* Compute the amount to skip between sequences */ - for(u = 0; u < ndims; u++) - skip[u] = (mem_size[u] - tdiminfo[u].block) * slab[u]; + case H5S_SEL_ERROR: + case H5S_SEL_N: + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ - /* 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; + 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") - /* Set temporary dimension for advancing offsets */ - temp_dim = (int)skip_dim; + /* 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") - /* Increment offset in destination buffer */ - loc += skip_slab; + /* Save the diminfo */ + space->select.num_elem = 1; + for(u = 0; u < space->extent.rank; u++) { + space->select.sel_info.hslab->app_diminfo[u].start = start[u]; + space->select.sel_info.hslab->app_diminfo[u].stride = stride[u]; + space->select.sel_info.hslab->app_diminfo[u].count = count[u]; + space->select.sel_info.hslab->app_diminfo[u].block = block[u]; - /* 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]++; + space->select.sel_info.hslab->opt_diminfo[u].start = start[u]; + space->select.sel_info.hslab->opt_diminfo[u].stride = opt_stride[u]; + space->select.sel_info.hslab->opt_diminfo[u].count = opt_count[u]; + space->select.sel_info.hslab->opt_diminfo[u].block = opt_block[u]; - /* 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 */ + space->select.num_elem *= (opt_count[u] * opt_block[u]); + } /* end for */ - /* Decrement dimension count */ - temp_dim--; - } /* end while */ + /* Save unlim_dim */ + space->select.sel_info.hslab->unlim_dim = unlim_dim; - /* Decrement block count */ - blk_count--; - } /* end while */ - } /* end else */ - } /* end else */ + /* Indicate that the dimension information is valid */ + space->select.sel_info.hslab->diminfo_valid = TRUE; - /* Update the iterator, if there were any blocks used */ + /* Indicate that there's no slab information */ + space->select.sel_info.hslab->span_lst = NULL; - /* Decrement the number of elements left in selection */ - iter->elmt_left -= tot_blk_count * actual_elem; + /* 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]); - /* 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]); + /* Set num_elem */ + if(space->select.num_elem != (hsize_t)0) + space->select.num_elem = H5S_UNLIMITED; } /* end if */ - /* Increment the number of sequences generated */ - *nseq += tot_blk_count; - - /* Increment the number of elements used */ - *nelem += tot_blk_count * actual_elem; + /* 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); - /* 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 */ + /* 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]; + + /* 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") - /* Compute elements left */ - elmt_remainder = io_left - (tot_blk_count * actual_elem); - HDassert(elmt_remainder < fast_dim_block); - HDassert(elmt_remainder > 0); + /* 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") - /* Store the sequence information */ - *off++ = loc; - *len++ = elmt_remainder * elem_size; + /* 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 */ - /* Update the iterator with the location we stopped */ - iter->u.hyp.off[fast_dim] += (hsize_t)elmt_remainder; + /* 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") - /* Decrement the number of elements left in selection */ - iter->elmt_left -= elmt_remainder; + /* Indicate that the regular dimensions are no longer valid */ + space->select.sel_info.hslab->diminfo_valid = FALSE; - /* Increment the number of sequences generated */ - (*nseq)++; + /* Set selection type */ + /* (Could be overridden by resetting selection to 'none', below) */ + space->select.type = H5S_sel_hyper; - /* Increment the number of elements used */ - *nelem += elmt_remainder; + /* 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") - /* Sanity check */ - HDassert(*nseq > 0); - HDassert(*nelem > 0); - - FUNC_LEAVE_NOAPI(SUCCEED) -} /* end H5S__hyper_get_seq_list_single() */ +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_select_hyperslab() */ /*-------------------------------------------------------------------------- NAME - H5S__hyper_get_seq_list + H5Sselect_hyperslab PURPOSE - Create a list of offsets & lengths for a selection + Specify a hyperslab to combine with the current hyperslab selection 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 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. + 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. + 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 --------------------------------------------------------------------------*/ -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 +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[]) { - herr_t ret_value = FAIL; /* return value */ + H5S_t *space; /* Dataspace to modify selection of */ + herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_STATIC_NOERR + FUNC_ENTER_API(FAIL) + H5TRACE6("e", "iSs*h*h*h*h", space_id, op, start, stride, count, block); /* 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); - - /* Check for the special case of just one H5Sselect_hyperslab call made */ - if(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 */ + 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 */ - /* 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; - - /* 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 */ - - - /* 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); - - /* 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 */ - - /* 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_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); + /* 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 */ - else - /* Call the general sequence generator routine */ - ret_value = H5S__hyper_get_seq_list_gen(space, iter, maxseq, maxelem, nseq, nelem, off, len); - FUNC_LEAVE_NOAPI(ret_value) -} /* end H5S__hyper_get_seq_list() */ + 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() */ /*-------------------------------------------------------------------------- diff --git a/src/H5Smpio.c b/src/H5Smpio.c index 2ebe987..01ec3e1 100644 --- a/src/H5Smpio.c +++ b/src/H5Smpio.c @@ -31,12 +31,7 @@ #include "H5private.h" /* Generic Functions */ #include "H5Dprivate.h" /* Datasets */ #include "H5Eprivate.h" /* Error handling */ -#include "H5Fprivate.h" /* File access */ -#include "H5FDprivate.h" /* File drivers */ -#include "H5Iprivate.h" /* IDs */ #include "H5MMprivate.h" /* Memory management */ -#include "H5Oprivate.h" /* Object headers */ -#include "H5Pprivate.h" /* Property lists */ #include "H5Spkg.h" /* Dataspaces */ #include "H5VMprivate.h" /* Vector and array functions */ @@ -97,6 +92,8 @@ static herr_t H5S__mpio_create_large_type(hsize_t, MPI_Aint, MPI_Datatype , MPI_ static hsize_t bigio_count = H5S_MAX_MPI_COUNT; + + /*------------------------------------------------------------------------- * Function: H5S_mpio_set_bigio_count * diff --git a/src/H5Snone.c b/src/H5Snone.c index c867e67..86994dd 100644 --- a/src/H5Snone.c +++ b/src/H5Snone.c @@ -334,6 +334,64 @@ H5S__none_iter_next_block(H5S_sel_iter_t H5_ATTR_UNUSED *iter) /*-------------------------------------------------------------------------- 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() */ + + +/*-------------------------------------------------------------------------- + NAME H5S__none_iter_release PURPOSE Release "none" selection iterator information for a dataspace @@ -941,61 +999,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 1fbfa35..0575f03 100644 --- a/src/H5Spkg.h +++ b/src/H5Spkg.h @@ -116,7 +116,7 @@ struct H5S_hyper_span_info_t { struct H5S_hyper_span_t *head; /* Pointer to list of spans in next dimension down */ }; -/* Information about new-style hyperslab selection */ +/* Information about 'diminfo' form of hyperslab selection */ typedef struct { hbool_t diminfo_valid; /* Whether the dataset has valid diminfo */ H5S_hyper_dim_t opt_diminfo[H5S_MAX_RANK]; /* per-dim selection info */ @@ -280,7 +280,7 @@ H5_DLL herr_t H5S__extent_release(H5S_extent_t *extent); H5_DLL herr_t H5S__extent_copy_real(H5S_extent_t *dst, const H5S_extent_t *src, hbool_t copy_max); -/* Operations on selections */ +/* Operations on hyperslab selections */ 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); diff --git a/src/H5Spoint.c b/src/H5Spoint.c index 11cf448..6411b94 100644 --- a/src/H5Spoint.c +++ b/src/H5Spoint.c @@ -371,6 +371,144 @@ H5S__point_iter_next_block(H5S_sel_iter_t *iter) /*-------------------------------------------------------------------------- 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 (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_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) && locelmt_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() */ + + +/*-------------------------------------------------------------------------- + NAME H5S__point_iter_release PURPOSE Release point selection iterator information for a dataspace @@ -525,7 +663,7 @@ H5S__point_release(H5S_t *space) { H5S_pnt_node_t *curr, *next; /* Point selection nodes */ - FUNC_ENTER_NOAPI_NOINIT_NOERR + FUNC_ENTER_STATIC_NOERR /* Check args */ HDassert(space); @@ -640,6 +778,7 @@ H5S__point_copy(H5S_t *dst, const H5S_t *src, hbool_t H5_ATTR_UNUSED share_selec FUNC_ENTER_STATIC + /* Sanity checks */ HDassert(src); HDassert(dst); @@ -1651,141 +1790,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) && locelmt_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 24db889..f4e0006 100644 --- a/src/H5Sprivate.h +++ b/src/H5Sprivate.h @@ -58,7 +58,7 @@ typedef struct H5S_hyper_dim_t { /* Point selection iteration container */ typedef struct { - H5S_pnt_node_t *curr; /* Pointer to next node to output */ + H5S_pnt_node_t *curr; /* Pointer to next node to output */ } H5S_point_iter_t; /* Hyperslab selection iteration container */ @@ -286,9 +286,6 @@ 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); -#ifdef LATER -H5_DLL htri_t H5S_hyper_intersect (H5S_t *space1, H5S_t *space2); -#endif /* LATER */ 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); @@ -304,7 +301,8 @@ H5_DLL hsize_t H5S_hyper_get_first_inc_block(const H5S_t *space, hsize_t clip_size, hbool_t *partial); /* 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); +H5_DLL herr_t H5S_select_iter_init(H5S_sel_iter_t *iter, const H5S_t *space, + size_t elmt_size); 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); diff --git a/src/H5Spublic.h b/src/H5Spublic.h index b7129ca..561875a 100644 --- a/src/H5Spublic.h +++ b/src/H5Spublic.h @@ -127,16 +127,6 @@ 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 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[]); diff --git a/src/H5Sselect.c b/src/H5Sselect.c index 4d7fc4f..24586de 100644 --- a/src/H5Sselect.c +++ b/src/H5Sselect.c @@ -295,43 +295,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 @@ -1425,6 +1388,44 @@ H5S_select_iter_next_block(H5S_sel_iter_t *iter) #endif /* LATER */ +/*------------------------------------------------------------------------- + * 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 + + /* Sanity check */ + 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() */ + + /*-------------------------------------------------------------------------- NAME H5S_select_iter_release @@ -1731,8 +1732,6 @@ H5S_get_select_type(const H5S_t *space) Assumes that there is only a single "block" for hyperslab selections. 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) @@ -1912,11 +1911,11 @@ H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) space_a_dim = (int)space_a_rank - 1; space_b_dim = (int)space_b_rank - 1; - /* The first block only compares the sizes and sets the - * relative offsets for later blocks + /* The first block only compares the sizes and sets the + * relative offsets for later blocks */ if(first_block) { - /* If the block sizes in the common dimensions from + /* If the block sizes in the common dimensions from * each selection don't match, get out */ while(space_b_dim >= 0) { @@ -1932,7 +1931,7 @@ H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) space_b_dim--; } /* end while */ - /* similarly, if the block size in any dimension that appears only + /* Similarly, if the block size in any dimension that appears only * in space_a is not equal to 1, get out. */ while(space_a_dim >= 0) { @@ -1950,7 +1949,7 @@ H5S_select_shape_same(const H5S_t *space1, const H5S_t *space2) } /* end if */ /* Check over the blocks for each selection */ else { - /* for dimensions that space_a and space_b have in common: */ + /* 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]) != diff --git a/test/tselect.c b/test/tselect.c index 9150b11..011be7c 100644 --- a/test/tselect.c +++ b/test/tselect.c @@ -4910,365 +4910,6 @@ 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) -** -****************************************************************/ -static void -test_select_hyper_union_stagger(void) -{ - hid_t file_id; /* File ID */ - hid_t dset_id; /* Dataset ID */ - hid_t dataspace; /* File dataspace ID */ - hid_t memspace; /* Memory dataspace ID */ - hid_t tmp_space; /* Temporary dataspace ID */ - hid_t tmp2_space; /* Another emporary dataspace ID */ - hsize_t dimsm[2]={7,7}; /* Memory array dimensions */ - hsize_t dimsf[2]={6,5}; /* File array dimensions */ - 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 count_out[2]={4,2}; /* Hyperslab size in memory */ - hssize_t offset_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}, - {1,0}, - {2,0}, - {2,1}, - {3,1}, - {4,1}, - {4,2}, - {5,2}}; - int output_loc[8][2]={{0,3}, - {0,4}, - {1,3}, - {1,4}, - {2,3}, - {2,4}, - {3,3}, - {3,4}}; - int dsetrank=2; /* File Dataset rank */ - int memrank=2; /* Memory Dataset rank */ - int i,j; /* Local counting variables */ - herr_t error; - hsize_t stride[2]={1,1}; - hsize_t block[2]={1,1}; - - /* Initialize data to write */ - for(i=0; i<6; i++) - for(j=0; j<5; j++) - data[i][j] = j*10 + i; - - /* Create file */ - file_id=H5Fcreate(FILENAME,H5F_ACC_TRUNC,H5P_DEFAULT,H5P_DEFAULT); - CHECK(file_id, FAIL, "H5Fcreate"); - - /* Create File Dataspace */ - dataspace=H5Screate_simple(dsetrank,dimsf,NULL); - CHECK(dataspace, FAIL, "H5Screate_simple"); - - /* Create File Dataset */ - dset_id=H5Dcreate2(file_id,"IntArray",H5T_NATIVE_INT,dataspace,H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); - CHECK(dset_id, FAIL, "H5Dcreate2"); - - /* Write File Dataset */ - error=H5Dwrite(dset_id,H5T_NATIVE_INT,dataspace,dataspace,H5P_DEFAULT,data); - CHECK(error, FAIL, "H5Dwrite"); - - /* Close things */ - error=H5Sclose(dataspace); - CHECK(error, FAIL, "H5Sclose"); - error = H5Dclose(dset_id); - CHECK(error, FAIL, "H5Dclose"); - error = H5Fclose(file_id); - CHECK(error, FAIL, "H5Fclose"); - - /* Initialize intput buffer */ - memset(data_out, 0, 7 * 7 * sizeof(int)); - - /* Open file */ - file_id = H5Fopen(FILENAME, H5F_ACC_RDONLY, H5P_DEFAULT); - CHECK(file_id, FAIL, "H5Fopen"); - - /* Open dataset */ - dset_id = H5Dopen2(file_id, "IntArray", H5P_DEFAULT); - CHECK(dset_id, FAIL, "H5Dopen2"); - - /* Get the dataspace */ - dataspace = H5Dget_space(dset_id); - CHECK(dataspace, FAIL, "H5Dget_space"); - - /* Select the hyperslabs */ - error = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, stride, count, block); - CHECK(error, FAIL, "H5Sselect_hyperslab"); - tmp_space = H5Scombine_hyperslab(dataspace, H5S_SELECT_OR, offset2, 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); - 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"); - - /* 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); - CHECK(error, FAIL, "H5Sselect_hyperslab"); - - /* Read File Dataset */ - error=H5Dread(dset_id,H5T_NATIVE_INT,memspace,tmp_space,H5P_DEFAULT,data_out); - CHECK(error, FAIL, "H5Dread"); - - /* Verify input data */ - for(i=0; i<8; i++) { - if(data[input_loc[i][0]][input_loc[i][1]]!=data_out[output_loc[i][0]][output_loc[i][1]]) { - printf("input data #%d is wrong!\n",i); - printf("input_loc=[%d][%d]\n",input_loc[i][0],input_loc[i][1]); - printf("output_loc=[%d][%d]\n",output_loc[i][0],output_loc[i][1]); - printf("data=%d\n",data[input_loc[i][0]][input_loc[i][1]]); - TestErrPrintf("data_out=%d\n",data_out[output_loc[i][0]][output_loc[i][1]]); - } /* end if */ - } /* end for */ - - /* Close things */ - error=H5Sclose(tmp2_space); - CHECK(error, FAIL, "H5Sclose"); - error=H5Sclose(tmp_space); - CHECK(error, FAIL, "H5Sclose"); - error=H5Sclose(dataspace); - CHECK(error, FAIL, "H5Sclose"); - error=H5Sclose(memspace); - CHECK(error, FAIL, "H5Sclose"); - error=H5Dclose(dset_id); - CHECK(error, FAIL, "H5Dclose"); - error=H5Fclose(file_id); - CHECK(error, FAIL, "H5Fclose"); -} - -/**************************************************************** -** -** test_select_hyper_union_3d(): Test basic H5S (dataspace) selection code. -** Tests unions of hyperslabs in 3-D (Uses H5Scombine_hyperslab -** and H5Scombine_select instead of H5Sselect_hyperslab) -** -****************************************************************/ -static void -test_select_hyper_union_3d(void) -{ - hid_t fid1; /* HDF5 File IDs */ - hid_t dataset; /* Dataset ID */ - hid_t sid1,sid2; /* Dataspace ID */ - hid_t tmp_space; /* Temporary Dataspace ID */ - hid_t tmp2_space; /* Another temporary Dataspace ID */ - hsize_t dims1[] = {SPACE1_DIM1, SPACE1_DIM2, SPACE1_DIM3}; - hsize_t dims2[] = {SPACE4_DIM1, SPACE4_DIM2, SPACE4_DIM3}; - hsize_t dims3[] = {SPACE3_DIM1, SPACE3_DIM2}; - hsize_t start[SPACE1_RANK]; /* Starting location of hyperslab */ - hsize_t stride[SPACE1_RANK]; /* Stride of hyperslab */ - hsize_t count[SPACE1_RANK]; /* Element count of hyperslab */ - hsize_t block[SPACE1_RANK]; /* Block size of hyperslab */ - struct row_list { - size_t z; - size_t y; - size_t x; - size_t l; - } rows[]= { /* Array of x,y,z coordinates & length for each row written from memory */ - {0,0,0,6}, /* 1st face of 3-D object */ - {0,1,0,6}, - {0,2,0,6}, - {0,3,0,6}, - {0,4,0,6}, - {1,0,0,6}, /* 2nd face of 3-D object */ - {1,1,0,6}, - {1,2,0,6}, - {1,3,0,6}, - {1,4,0,6}, - {2,0,0,6}, /* 3rd face of 3-D object */ - {2,1,0,10}, - {2,2,0,10}, - {2,3,0,10}, - {2,4,0,10}, - {2,5,2,8}, - {2,6,2,8}, - {3,0,0,6}, /* 4th face of 3-D object */ - {3,1,0,10}, - {3,2,0,10}, - {3,3,0,10}, - {3,4,0,10}, - {3,5,2,8}, - {3,6,2,8}, - {4,0,0,6}, /* 5th face of 3-D object */ - {4,1,0,10}, - {4,2,0,10}, - {4,3,0,10}, - {4,4,0,10}, - {4,5,2,8}, - {4,6,2,8}, - {5,1,2,8}, /* 6th face of 3-D object */ - {5,2,2,8}, - {5,3,2,8}, - {5,4,2,8}, - {5,5,2,8}, - {5,6,2,8}, - {6,1,2,8}, /* 7th face of 3-D object */ - {6,2,2,8}, - {6,3,2,8}, - {6,4,2,8}, - {6,5,2,8}, - {6,6,2,8}, - {7,1,2,8}, /* 8th face of 3-D object */ - {7,2,2,8}, - {7,3,2,8}, - {7,4,2,8}, - {7,5,2,8}, - {7,6,2,8}}; - uint8_t *wbuf, /* buffer to write to disk */ - *rbuf, /* buffer read from disk */ - *tbuf, /* temporary buffer pointer */ - *tbuf2; /* temporary buffer pointer */ - int i,j,k; /* Counters */ - herr_t ret; /* Generic return value */ - hsize_t npoints; /* Number of elements in selection */ - - /* Output message about test being performed */ - MESSAGE(5, ("Testing Hyperslab Selection Functions with unions of 3-D hyperslabs\n")); - - /* Allocate write & read buffers */ - wbuf = (uint8_t *)HDmalloc(sizeof(uint8_t) * SPACE4_DIM1 * SPACE4_DIM2 * SPACE4_DIM3); - CHECK(wbuf, NULL, "HDmalloc"); - rbuf = (uint8_t *)HDcalloc(sizeof(uint8_t), SPACE3_DIM1 * SPACE3_DIM2); - CHECK(rbuf, NULL, "HDcalloc"); - - /* Initialize write buffer */ - for(i=0, tbuf=wbuf; i