diff options
Diffstat (limited to 'src/H5Shyper.c')
-rw-r--r-- | src/H5Shyper.c | 10452 |
1 files changed, 10452 insertions, 0 deletions
diff --git a/src/H5Shyper.c b/src/H5Shyper.c new file mode 100644 index 0000000..e6e6cff --- /dev/null +++ b/src/H5Shyper.c @@ -0,0 +1,10452 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu> + * Thursday, June 18, 1998 + * + * Purpose: Hyperslab selection data space I/O functions. + */ + +#include "H5Smodule.h" /* This source code file is part of the H5S module */ + + +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5FLprivate.h" /* Free Lists */ +#include "H5Iprivate.h" /* ID Functions */ +#include "H5Spkg.h" /* Dataspace functions */ +#include "H5VMprivate.h" /* Vector functions */ + +/* Local datatypes */ + +/* Static function prototypes */ +static herr_t H5S_hyper_free_span_info(H5S_hyper_span_info_t *span_info); +static herr_t H5S_hyper_free_span(H5S_hyper_span_t *span); +static H5S_hyper_span_info_t *H5S_hyper_copy_span(H5S_hyper_span_info_t *spans); +static void H5S_hyper_span_scratch(H5S_hyper_span_info_t *spans, void *scr_value); +static herr_t H5S_hyper_span_precompute(H5S_hyper_span_info_t *spans, size_t elmt_size); +static herr_t H5S_generate_hyperslab(H5S_t *space, H5S_seloper_t op, + const hsize_t start[], const hsize_t stride[], const hsize_t count[], const hsize_t block[]); +static herr_t H5S_hyper_generate_spans(H5S_t *space); +/* Needed for use in hyperslab code (H5Shyper.c) */ +#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, + hsize_t num_slices, hbool_t incl_trail); + +/* Selection callbacks */ +static herr_t H5S_hyper_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection); +static herr_t H5S_hyper_get_seq_list(const H5S_t *space, unsigned flags, + H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes, + size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); +static herr_t H5S_hyper_release(H5S_t *space); +static htri_t H5S_hyper_is_valid(const H5S_t *space); +static hssize_t H5S_hyper_serial_size(const H5S_t *space); +static herr_t H5S_hyper_serialize(const H5S_t *space, uint8_t **p); +static herr_t H5S_hyper_deserialize(H5S_t *space, uint32_t version, uint8_t flags, + const uint8_t **p); +static herr_t H5S_hyper_bounds(const H5S_t *space, hsize_t *start, hsize_t *end); +static herr_t H5S_hyper_offset(const H5S_t *space, hsize_t *offset); +static int H5S__hyper_unlim_dim(const H5S_t *space); +static herr_t H5S_hyper_num_elem_non_unlim(const H5S_t *space, + hsize_t *num_elem_non_unlim); +static htri_t H5S_hyper_is_contiguous(const H5S_t *space); +static htri_t H5S_hyper_is_single(const H5S_t *space); +static htri_t H5S_hyper_is_regular(const H5S_t *space); +static herr_t H5S_hyper_adjust_u(H5S_t *space, const hsize_t *offset); +static herr_t H5S_hyper_project_scalar(const H5S_t *space, hsize_t *offset); +static herr_t H5S_hyper_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset); +static herr_t H5S_hyper_iter_init(H5S_sel_iter_t *iter, const H5S_t *space); + +/* Selection iteration callbacks */ +static herr_t H5S_hyper_iter_coords(const H5S_sel_iter_t *iter, hsize_t *coords); +static herr_t H5S_hyper_iter_block(const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end); +static hsize_t H5S_hyper_iter_nelmts(const H5S_sel_iter_t *iter); +static htri_t H5S_hyper_iter_has_next_block(const H5S_sel_iter_t *sel_iter); +static herr_t H5S_hyper_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem); +static herr_t H5S_hyper_iter_next_block(H5S_sel_iter_t *sel_iter); +static herr_t H5S_hyper_iter_release(H5S_sel_iter_t *sel_iter); + +/* Static function for optimizing hyperslab */ +static hbool_t H5S_hyper_rebuild_helper(const H5S_hyper_span_t *span, + H5S_hyper_dim_t span_slab_info[], unsigned rank); +static htri_t H5S_hyper_rebuild(H5S_t *space); + +/* Selection properties for hyperslab selections */ +const H5S_select_class_t H5S_sel_hyper[1] = {{ + H5S_SEL_HYPERSLABS, + + /* Methods on selection */ + H5S_hyper_copy, + H5S_hyper_get_seq_list, + H5S_hyper_release, + H5S_hyper_is_valid, + H5S_hyper_serial_size, + H5S_hyper_serialize, + H5S_hyper_deserialize, + H5S_hyper_bounds, + H5S_hyper_offset, + H5S__hyper_unlim_dim, + H5S_hyper_num_elem_non_unlim, + H5S_hyper_is_contiguous, + H5S_hyper_is_single, + H5S_hyper_is_regular, + H5S_hyper_adjust_u, + H5S_hyper_project_scalar, + H5S_hyper_project_simple, + H5S_hyper_iter_init, +}}; + +/* Iteration properties for hyperslab selections */ +static const H5S_sel_iter_class_t H5S_sel_iter_hyper[1] = {{ + H5S_SEL_HYPERSLABS, + + /* Methods on selection iterator */ + H5S_hyper_iter_coords, + H5S_hyper_iter_block, + H5S_hyper_iter_nelmts, + H5S_hyper_iter_has_next_block, + H5S_hyper_iter_next, + H5S_hyper_iter_next_block, + H5S_hyper_iter_release, +}}; + +/* Static variables */ + +/* Array for default stride, block, etc. */ +static const hsize_t _ones[H5O_LAYOUT_NDIMS]={ + 1,1,1,1, 1,1,1,1, + 1,1,1,1, 1,1,1,1, + 1,1,1,1, 1,1,1,1, + 1,1,1,1, 1,1,1,1,1}; + +/* Declare a free list to manage the H5S_hyper_sel_t struct */ +H5FL_DEFINE_STATIC(H5S_hyper_sel_t); + +/* Declare a free list to manage the H5S_hyper_span_t struct */ +H5FL_DEFINE_STATIC(H5S_hyper_span_t); + +/* Declare a free list to manage the H5S_hyper_span_info_t struct */ +H5FL_DEFINE_STATIC(H5S_hyper_span_info_t); + +/* Declare extern free list to manage the H5S_sel_iter_t struct */ +H5FL_EXTERN(H5S_sel_iter_t); + +/* #define H5S_HYPER_DEBUG */ +#ifdef H5S_HYPER_DEBUG +static herr_t +H5S_hyper_print_spans_helper(FILE *f, struct H5S_hyper_span_t *span,unsigned depth) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + while(span) { + HDfprintf(f,"%s: depth=%u, span=%p, (%d, %d), nelem=%u, pstride=%u\n",FUNC,depth,span,(int)span->low,(int)span->high,(unsigned)span->nelem,(unsigned)span->pstride); + if(span->down && span->down->head) { + HDfprintf(f,"%s: spans=%p, count=%u, scratch=%p, head=%p\n",FUNC,span->down,span->down->count,span->down->scratch,span->down->head); + H5S_hyper_print_spans_helper(f,span->down->head,depth+1); + } /* end if */ + span=span->next; + } /* end while */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} + +herr_t +H5S_hyper_print_spans(FILE *f, const struct H5S_hyper_span_info_t *span_lst) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + if(span_lst!=NULL) { + HDfprintf(f,"%s: spans=%p, count=%u, scratch=%p, head=%p\n",FUNC,span_lst,span_lst->count,span_lst->scratch,span_lst->head); + H5S_hyper_print_spans_helper(f,span_lst->head,0); + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} + +herr_t +H5S_space_print_spans(FILE *f, const H5S_t *space) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + H5S_hyper_print_spans(f,space->select.sel_info.hslab->span_lst); + + FUNC_LEAVE_NOAPI(SUCCEED) +} + +static herr_t +H5S_hyper_print_diminfo_helper(FILE *f, const char *field, unsigned ndims, const H5S_hyper_dim_t *dinfo) +{ + unsigned u; /* Local index variable */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + if(dinfo!=NULL) { + HDfprintf(f,"%s: %s: start=[",FUNC,field); + for(u=0; u<ndims; u++) + HDfprintf(f,"%Hd%s",dinfo[u].start, (u<(ndims-1) ? ", " : "]\n")); + HDfprintf(f,"%s: %s: stride=[",FUNC,field); + for(u=0; u<ndims; u++) + HDfprintf(f,"%Hu%s",dinfo[u].stride, (u<(ndims-1) ? ", " : "]\n")); + HDfprintf(f,"%s: %s: count=[",FUNC,field); + for(u=0; u<ndims; u++) + HDfprintf(f,"%Hu%s",dinfo[u].count, (u<(ndims-1) ? ", " : "]\n")); + HDfprintf(f,"%s: %s: block=[",FUNC,field); + for(u=0; u<ndims; u++) + HDfprintf(f,"%Hu%s",dinfo[u].block, (u<(ndims-1) ? ", " : "]\n")); + } /* end if */ + else + HDfprintf(f,"%s: %s==NULL\n",FUNC,field); + + FUNC_LEAVE_NOAPI(SUCCEED) +} + +herr_t +H5S_hyper_print_diminfo(FILE *f, const H5S_t *space) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + H5S_hyper_print_diminfo_helper(f,"opt_diminfo",space->extent.rank,space->select.sel_info.hslab->opt_diminfo); + H5S_hyper_print_diminfo_helper(f,"app_diminfo",space->extent.rank,space->select.sel_info.hslab->app_diminfo); + + FUNC_LEAVE_NOAPI(SUCCEED) +} +#endif /* H5S_HYPER_DEBUG */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_iter_init + * + * Purpose: Initializes iteration information for hyperslab span tree selection. + * + * Return: non-negative on success, negative on failure. + * + * Programmer: Quincey Koziol + * Saturday, February 24, 2001 + * + * Notes: If the 'elmt_size' parameter is set to zero, the regular + * hyperslab selection iterator will not be 'flattened'. This + * is used by the H5S_select_shape_same() code to avoid changing + * the rank and appearance of the selection. + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_hyper_iter_init(H5S_sel_iter_t *iter, const H5S_t *space) +{ + const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ + H5S_hyper_span_info_t *spans; /* Pointer to hyperslab span info node */ + unsigned rank; /* Dataspace's dimension rank */ + unsigned u; /* Index variable */ + int i; /* Index variable */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space)); + HDassert(iter); + HDassert(space->select.sel_info.hslab->unlim_dim < 0); + + /* Initialize the number of points to iterate over */ + iter->elmt_left = space->select.num_elem; + iter->u.hyp.iter_rank = 0; + + /* Get the rank of the dataspace */ + rank = space->extent.rank; + + /* Set the temporary pointer to the dimension information */ + tdiminfo = space->select.sel_info.hslab->opt_diminfo; + + /* Check for the special case of just one H5Sselect_hyperslab call made */ + if(space->select.sel_info.hslab->diminfo_valid) { +/* Initialize the information needed for regular hyperslab I/O */ + const hsize_t *mem_size; /* Temporary pointer to dataspace extent's dimension sizes */ + hsize_t acc; /* Accumulator for "flattened" dimension's sizes */ + unsigned cont_dim = 0; /* # of contiguous dimensions */ + + /* Set the temporary pointer to the dataspace extent's dimension sizes */ + mem_size = space->extent.size; + + /* + * For a regular hyperslab to be contiguous up to some dimension, it + * must have only one block (i.e. count==1 in all dimensions up to that + * dimension) and the block size must be the same as the dataspace's + * extent in that dimension and all dimensions up to that dimension. + */ + + /* Don't flatten adjacent elements into contiguous block if the + * element size is 0. This is for the H5S_select_shape_same() code. + */ + if(iter->elmt_size > 0) { + /* Check for any "contiguous" blocks that can be flattened */ + for(u = (rank - 1); u > 0; u--) { + if(tdiminfo[u].count == 1 && tdiminfo[u].block == mem_size[u]) { + cont_dim++; + iter->u.hyp.flattened[u] = TRUE; + } /* end if */ + else + iter->u.hyp.flattened[u] = FALSE; + } /* end for */ + iter->u.hyp.flattened[0] = FALSE; + } /* end if */ + + /* Check if the regular selection can be "flattened" */ + if(cont_dim > 0) { + unsigned last_dim_flattened = 1; /* Flag to indicate that the last dimension was flattened */ + unsigned flat_rank = rank-cont_dim; /* Number of dimensions after flattening */ + unsigned curr_dim; /* Current dimension */ + + /* Set the iterator's rank to the contiguous dimensions */ + iter->u.hyp.iter_rank = flat_rank; + + /* "Flatten" dataspace extent and selection information */ + curr_dim = flat_rank - 1; + for(i = (int)rank - 1, acc = 1; i >= 0; i--) { + if(tdiminfo[i].block == mem_size[i] && i > 0) { + /* "Flatten" this dimension */ + HDassert(tdiminfo[i].start == 0); + acc *= mem_size[i]; + + /* Indicate that the dimension was flattened */ + last_dim_flattened = 1; + } /* end if */ + else { + if(last_dim_flattened) { + /* First dimension after flattened dimensions */ + iter->u.hyp.diminfo[curr_dim].start = tdiminfo[i].start * acc; + + /* Special case for single block regular selections */ + if(tdiminfo[i].count == 1) + iter->u.hyp.diminfo[curr_dim].stride = 1; + else + iter->u.hyp.diminfo[curr_dim].stride = tdiminfo[i].stride * acc; + iter->u.hyp.diminfo[curr_dim].count = tdiminfo[i].count; + iter->u.hyp.diminfo[curr_dim].block = tdiminfo[i].block * acc; + iter->u.hyp.size[curr_dim] = mem_size[i] * acc; + iter->u.hyp.sel_off[curr_dim] = space->select.offset[i] * (hssize_t)acc; + + /* Reset the "last dim flattened" flag to avoid flattened any further dimensions */ + last_dim_flattened = 0; + + /* Reset the "accumulator" for possible further dimension flattening */ + acc = 1; + } /* end if */ + else { + /* All other dimensions */ + iter->u.hyp.diminfo[curr_dim].start = tdiminfo[i].start; + iter->u.hyp.diminfo[curr_dim].stride = tdiminfo[i].stride; + iter->u.hyp.diminfo[curr_dim].count = tdiminfo[i].count; + iter->u.hyp.diminfo[curr_dim].block = tdiminfo[i].block; + iter->u.hyp.size[curr_dim] = mem_size[i]; + iter->u.hyp.sel_off[curr_dim] = space->select.offset[i]; + } /* end else */ + + /* Decrement "current" flattened dimension */ + curr_dim--; + } /* end if */ + } /* end for */ + + /* Initialize "flattened" iterator offset to initial location and dataspace extent and selection information to correct values */ + for(u = 0; u < flat_rank; u++) + iter->u.hyp.off[u] = iter->u.hyp.diminfo[u].start; + } /* end if */ + else { + /* Initialize position to initial location */ + /* Also make local copy of the regular selection information */ + for(u = 0; u < rank; u++) { + /* Regular selection information */ + iter->u.hyp.diminfo[u].start = tdiminfo[u].start; + iter->u.hyp.diminfo[u].stride = tdiminfo[u].stride; + iter->u.hyp.diminfo[u].count = tdiminfo[u].count; + iter->u.hyp.diminfo[u].block = tdiminfo[u].block; + + /* Position information */ + iter->u.hyp.off[u] = tdiminfo[u].start; + } /* end if */ + } /* end else */ + + /* Flag the diminfo information as valid in the iterator */ + iter->u.hyp.diminfo_valid = TRUE; + + /* Initialize irregular region information also (for release) */ + iter->u.hyp.spans = NULL; + } /* end if */ + else { +/* Initialize the information needed for non-regular hyperslab I/O */ + HDassert(space->select.sel_info.hslab->span_lst); + /* Make a copy of the span tree to iterate over */ + iter->u.hyp.spans = H5S_hyper_copy_span(space->select.sel_info.hslab->span_lst); + + /* Set the nelem & pstride values according to the element size */ + H5S_hyper_span_precompute(iter->u.hyp.spans,iter->elmt_size); + + /* Initialize the starting span_info's and spans */ + spans = iter->u.hyp.spans; + for(u = 0; u < rank; u++) { + /* Set the pointers to the initial span in each dimension */ + HDassert(spans); + HDassert(spans->head); + + /* Set the pointer to the first span in the list for this node */ + iter->u.hyp.span[u] = spans->head; + + /* Set the initial offset to low bound of span */ + iter->u.hyp.off[u] = iter->u.hyp.span[u]->low; + + /* Get the pointer to the next level down */ + spans = spans->head->down; + } /* end for */ + + /* Flag the diminfo information as not valid in the iterator */ + iter->u.hyp.diminfo_valid = FALSE; + } /* end else */ + + /* Initialize type of selection iterator */ + iter->type = H5S_sel_iter_hyper; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_iter_init() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_iter_coords + * + * Purpose: Retrieve the current coordinates of iterator for current + * selection + * + * Return: non-negative on success, negative on failure + * + * Programmer: Quincey Koziol + * Tuesday, April 22, 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_hyper_iter_coords (const H5S_sel_iter_t *iter, hsize_t *coords) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(iter); + HDassert(coords); + + /* Copy the offset of the current point */ + + /* Check for a single "regular" hyperslab */ + if(iter->u.hyp.diminfo_valid) { + /* Check if this is a "flattened" regular hyperslab selection */ + if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank) { + int u, v; /* Dimension indices */ + + /* Set the starting rank of both the "natural" & "flattened" dimensions */ + u = (int)iter->rank - 1; + v = (int)iter->u.hyp.iter_rank - 1; + + /* Construct the "natural" dimensions from a set of flattened coordinates */ + while(u >= 0) { + if(iter->u.hyp.flattened[u]) { + int begin = u; /* The rank of the first flattened dimension */ + + /* Walk up through as many flattened dimensions as possible */ + do { + u--; + } while(u >= 0 && iter->u.hyp.flattened[u]); + + /* Compensate for possibly overshooting dim 0 */ + if(u < 0) + u = 0; + + /* Sanity check */ + HDassert(v >= 0); + + /* Compute the coords for the flattened dimensions */ + H5VM_array_calc(iter->u.hyp.off[v], (unsigned)((begin - u) + 1), &(iter->dims[u]), &(coords[u])); + + /* Continue to faster dimension in both indices */ + u--; + v--; + } /* end if */ + else { + /* Walk up through as many non-flattened dimensions as possible */ + while(u >= 0 && !iter->u.hyp.flattened[u]) { + /* Sanity check */ + HDassert(v >= 0); + + /* Copy the coordinate */ + coords[u] = iter->u.hyp.off[v]; + + /* Continue to faster dimension in both indices */ + u--; + v--; + } /* end while */ + } /* end else */ + } /* end while */ + HDassert(v < 0); + } /* end if */ + else + HDmemcpy(coords, iter->u.hyp.off, sizeof(hsize_t) * iter->rank); + } /* end if */ + else + HDmemcpy(coords, iter->u.hyp.off, sizeof(hsize_t) * iter->rank); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_iter_coords() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_iter_block + * + * Purpose: Retrieve the current block of iterator for current + * selection + * + * Return: non-negative on success, negative on failure + * + * Programmer: Quincey Koziol + * Monday, June 2, 2003 + * + * Notes: This routine assumes that the iterator is always located at + * the beginning of a block. + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_hyper_iter_block (const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end) +{ + unsigned u; /* Local index variable */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(iter); + HDassert(start); + HDassert(end); + + /* Copy the offset of the current point */ + + /* Check for a single "regular" hyperslab */ + if(iter->u.hyp.diminfo_valid) { + /* Compute the end of the block */ + for(u=0; u<iter->rank; u++) { + start[u]=iter->u.hyp.off[u]; + end[u]=(start[u]+iter->u.hyp.diminfo[u].block)-1; + } /* end for */ + } /* end if */ + else { + /* Copy the start of the block */ + for(u=0; u<iter->rank; u++) + start[u]=iter->u.hyp.span[u]->low; + + /* Copy the end of the block */ + for(u=0; u<iter->rank; u++) + end[u]=iter->u.hyp.span[u]->high; + } /* end else */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_iter_block() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_iter_nelmts + * + * Purpose: Return number of elements left to process in iterator + * + * Return: non-negative number of elements on success, zero on failure + * + * Programmer: Quincey Koziol + * Tuesday, June 16, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static hsize_t +H5S_hyper_iter_nelmts (const H5S_sel_iter_t *iter) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(iter); + + FUNC_LEAVE_NOAPI(iter->elmt_left) +} /* H5S_hyper_iter_nelmts() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_iter_has_next_block + PURPOSE + Check if there is another block left in the current iterator + USAGE + htri_t H5S_hyper_iter_has_next_block(iter) + const H5S_sel_iter_t *iter; IN: Pointer to selection iterator + RETURNS + Non-negative (TRUE/FALSE) on success/Negative on failure + DESCRIPTION + Check if there is another block available in the selection iterator. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static htri_t +H5S_hyper_iter_has_next_block(const H5S_sel_iter_t *iter) +{ + unsigned u; /* Local index variable */ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(iter); + + /* Check for a single "regular" hyperslab */ + if(iter->u.hyp.diminfo_valid) { + const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ + const hsize_t *toff; /* Temporary offset in selection */ + + /* Check if the offset of the iterator is at the last location in all dimensions */ + tdiminfo = iter->u.hyp.diminfo; + toff = iter->u.hyp.off; + for(u = 0; u < iter->rank; u++) { + /* If there is only one block, continue */ + if(tdiminfo[u].count == 1) + continue; + if(toff[u] != (tdiminfo[u].start + ((tdiminfo[u].count - 1) * tdiminfo[u].stride))) + HGOTO_DONE(TRUE); + } /* end for */ + } /* end if */ + else { + /* Check for any levels of the tree with more sequences in them */ + for(u = 0; u < iter->rank; u++) + if(iter->u.hyp.span[u]->next != NULL) + HGOTO_DONE(TRUE); + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_iter_has_next_block() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_iter_next + * + * Purpose: Moves a hyperslab iterator to the beginning of the next sequence + * of elements to read. Handles walking off the end in all dimensions. + * + * Return: Success: non-negative + * Failure: negative + * + * Programmer: Quincey Koziol + * Friday, September 8, 2000 + * + * Modifications: + * Modified for both general and optimized hyperslab I/O + * Quincey Koziol, April 17, 2003 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_hyper_iter_next(H5S_sel_iter_t *iter, size_t nelem) +{ + unsigned ndims; /* Number of dimensions of dataset */ + int fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + unsigned i; /* Counters */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check for the special case of just one H5Sselect_hyperslab call made */ + /* (i.e. a regular hyperslab selection */ + if(iter->u.hyp.diminfo_valid) { + const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ + hsize_t iter_offset[H5O_LAYOUT_NDIMS]; + hsize_t iter_count[H5O_LAYOUT_NDIMS]; + int temp_dim; /* Temporary rank holder */ + + /* Check if this is a "flattened" regular hyperslab selection */ + if(iter->u.hyp.iter_rank!=0 && iter->u.hyp.iter_rank<iter->rank) { + /* Set the aliases for the dimension rank */ + ndims=iter->u.hyp.iter_rank; + } /* end if */ + else { + /* Set the aliases for the dimension rank */ + ndims=iter->rank; + } /* end else */ + + /* Set the fastest dimension rank */ + fast_dim = (int)ndims - 1; + + /* Set the local copy of the diminfo pointer */ + tdiminfo=iter->u.hyp.diminfo; + + /* Calculate the offset and block count for each dimension */ + for(i=0; i<ndims; i++) { + if(tdiminfo[i].count==1) { + iter_offset[i]=iter->u.hyp.off[i]-tdiminfo[i].start; + iter_count[i]=0; + } /* end if */ + else { + iter_offset[i]=(iter->u.hyp.off[i]-tdiminfo[i].start)%tdiminfo[i].stride; + iter_count[i]=(iter->u.hyp.off[i]-tdiminfo[i].start)/tdiminfo[i].stride; + } /* end else */ + } /* end for */ + + /* Loop through, advancing the offset & counts, until all the nelements are accounted for */ + while(nelem>0) { + /* Start with the fastest changing dimension */ + temp_dim=fast_dim; + while(temp_dim>=0) { + if(temp_dim==fast_dim) { + size_t actual_elem; /* Actual # of elements advanced on each iteration through loop */ + hsize_t block_elem; /* Number of elements left in a block */ + + /* Compute the number of elements left in block */ + block_elem=tdiminfo[temp_dim].block-iter_offset[temp_dim]; + + /* Compute the number of actual elements to advance */ + actual_elem=(size_t)MIN(nelem,block_elem); + + /* Move the iterator over as many elements as possible */ + iter_offset[temp_dim]+=actual_elem; + + /* Decrement the number of elements advanced */ + nelem-=actual_elem; + } /* end if */ + else { + /* Move to the next row in the current dimension */ + iter_offset[temp_dim]++; + } /* end else */ + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(iter_offset[temp_dim]<tdiminfo[temp_dim].block) + break; + else { + /* Move to the next block in the current dimension */ + iter_offset[temp_dim]=0; + iter_count[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(iter_count[temp_dim]<tdiminfo[temp_dim].count) + break; + else + iter_count[temp_dim]=0; /* reset back to the beginning of the line */ + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + } /* end while */ + + /* Translate current iter_offset and iter_count into iterator position */ + for(i=0; i<ndims; i++) + iter->u.hyp.off[i]=tdiminfo[i].start+(tdiminfo[i].stride*iter_count[i])+iter_offset[i]; + } /* end if */ + /* Must be an irregular hyperslab selection */ + else { + H5S_hyper_span_t *curr_span; /* Current hyperslab span node */ + H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */ + hsize_t *abs_arr; /* Absolute hyperslab span position */ + int curr_dim; /* Temporary rank holder */ + + /* Set the rank of the fastest changing dimension */ + ndims=iter->rank; + fast_dim = (int)ndims - 1; + + /* Get the pointers to the current span info and span nodes */ + abs_arr=iter->u.hyp.off; + ispan=iter->u.hyp.span; + + /* Loop through, advancing the span information, until all the nelements are accounted for */ + while(nelem>0) { + /* Start at the fastest dim */ + curr_dim=fast_dim; + + /* Work back up through the dimensions */ + while(curr_dim>=0) { + /* Reset the current span */ + curr_span=ispan[curr_dim]; + + /* Increment absolute position */ + if(curr_dim==fast_dim) { + size_t actual_elem; /* Actual # of elements advanced on each iteration through loop */ + hsize_t span_elem; /* Number of elements left in a span */ + + /* Compute the number of elements left in block */ + span_elem=(curr_span->high-abs_arr[curr_dim])+1; + + /* Compute the number of actual elements to advance */ + actual_elem=(size_t)MIN(nelem,span_elem); + + /* Move the iterator over as many elements as possible */ + abs_arr[curr_dim]+=actual_elem; + + /* Decrement the number of elements advanced */ + nelem-=actual_elem; + } /* end if */ + else { + /* Move to the next row in the current dimension */ + abs_arr[curr_dim]++; + } /* end else */ + + /* 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; + + 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 */ + + /* Check if we are finished with the spans in the tree */ + if(curr_dim>=0) { + /* Walk back down the iterator positions, reseting them */ + while(curr_dim<fast_dim) { + HDassert(curr_span); + HDassert(curr_span->down); + HDassert(curr_span->down->head); + + /* Increment current dimension */ + curr_dim++; + + /* Set the new span_info & span for this dimension */ + ispan[curr_dim]=curr_span->down->head; + + /* Advance span down the tree */ + curr_span=curr_span->down->head; + + /* Reset the absolute offset for the dim */ + abs_arr[curr_dim]=curr_span->low; + } /* end while */ + + /* Verify that the curr_span points to the fastest dim */ + HDassert(curr_span==ispan[fast_dim]); + } /* end if */ + } /* end while */ + } /* end else */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_iter_next() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_iter_next_block + * + * Purpose: Moves a hyperslab iterator to the beginning of the next sequence + * of elements to read. Handles walking off the end in all dimensions. + * + * Return: Success: non-negative + * Failure: negative + * + * Programmer: Quincey Koziol + * Tuesday, June 3, 2003 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_hyper_iter_next_block(H5S_sel_iter_t *iter) +{ + unsigned ndims; /* Number of dimensions of dataset */ + int fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + unsigned u; /* Counters */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check for the special case of just one H5Sselect_hyperslab call made */ + /* (i.e. a regular hyperslab selection */ + if(iter->u.hyp.diminfo_valid) { + const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ + hsize_t iter_offset[H5O_LAYOUT_NDIMS]; + hsize_t iter_count[H5O_LAYOUT_NDIMS]; + int temp_dim; /* Temporary rank holder */ + + /* Check if this is a "flattened" regular hyperslab selection */ + if(iter->u.hyp.iter_rank!=0 && iter->u.hyp.iter_rank<iter->rank) { + /* Set the aliases for the dimension rank */ + ndims=iter->u.hyp.iter_rank; + } /* end if */ + else { + /* Set the aliases for the dimension rank */ + ndims=iter->rank; + } /* end else */ + + /* Set the fastest dimension rank */ + fast_dim = (int)ndims - 1; + + /* Set the local copy of the diminfo pointer */ + tdiminfo=iter->u.hyp.diminfo; + + /* Calculate the offset and block count for each dimension */ + for(u=0; u<ndims; u++) { + if(tdiminfo[u].count==1) { + iter_offset[u]=iter->u.hyp.off[u]-tdiminfo[u].start; + iter_count[u]=0; + } /* end if */ + else { + iter_offset[u]=(iter->u.hyp.off[u]-tdiminfo[u].start)%tdiminfo[u].stride; + iter_count[u]=(iter->u.hyp.off[u]-tdiminfo[u].start)/tdiminfo[u].stride; + } /* end else */ + } /* end for */ + + /* Advance one block */ + temp_dim=fast_dim; /* Start with the fastest changing dimension */ + while(temp_dim>=0) { + if(temp_dim==fast_dim) { + /* Move iterator over current block */ + iter_offset[temp_dim]+=tdiminfo[temp_dim].block; + } /* end if */ + else { + /* Move to the next row in the current dimension */ + iter_offset[temp_dim]++; + } /* end else */ + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(iter_offset[temp_dim]<tdiminfo[temp_dim].block) + break; + else { + /* Move to the next block in the current dimension */ + iter_offset[temp_dim]=0; + iter_count[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(iter_count[temp_dim]<tdiminfo[temp_dim].count) + break; + else + iter_count[temp_dim]=0; /* reset back to the beginning of the line */ + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + + /* Translate current iter_offset and iter_count into iterator position */ + for(u=0; u<ndims; u++) + iter->u.hyp.off[u]=tdiminfo[u].start+(tdiminfo[u].stride*iter_count[u])+iter_offset[u]; + } /* end if */ + /* Must be an irregular hyperslab selection */ + else { + H5S_hyper_span_t *curr_span; /* Current hyperslab span node */ + H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */ + hsize_t *abs_arr; /* Absolute hyperslab span position */ + int curr_dim; /* Temporary rank holder */ + + /* Set the rank of the fastest changing dimension */ + ndims = iter->rank; + fast_dim = (int)ndims - 1; + + /* Get the pointers to the current span info and span nodes */ + abs_arr=iter->u.hyp.off; + ispan=iter->u.hyp.span; + + /* Loop through, advancing the span information, until all the nelements are accounted for */ + curr_dim=fast_dim; /* Start at the fastest dim */ + + /* Work back up through the dimensions */ + while(curr_dim>=0) { + /* Reset the current span */ + curr_span=ispan[curr_dim]; + + /* Increment absolute position */ + if(curr_dim==fast_dim) { + /* Move the iterator over rest of element in span */ + abs_arr[curr_dim]=curr_span->high+1; + } /* end if */ + else { + /* Move to the next row in the current dimension */ + abs_arr[curr_dim]++; + } /* end else */ + + /* 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; + + 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 */ + + /* Check if we are finished with the spans in the tree */ + if(curr_dim>=0) { + /* Walk back down the iterator positions, reseting them */ + while(curr_dim<fast_dim) { + HDassert(curr_span); + HDassert(curr_span->down); + HDassert(curr_span->down->head); + + /* Increment current dimension */ + curr_dim++; + + /* Set the new span_info & span for this dimension */ + ispan[curr_dim]=curr_span->down->head; + + /* Advance span down the tree */ + curr_span=curr_span->down->head; + + /* Reset the absolute offset for the dim */ + abs_arr[curr_dim]=curr_span->low; + } /* end while */ + + /* Verify that the curr_span points to the fastest dim */ + HDassert(curr_span == ispan[fast_dim]); + } /* end if */ + } /* end else */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_iter_next() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_iter_release + PURPOSE + Release hyperslab selection iterator information for a dataspace + USAGE + herr_t H5S_hyper_iter_release(iter) + H5S_sel_iter_t *iter; IN: Pointer to selection iterator + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Releases all information for a dataspace hyperslab selection iterator + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_hyper_iter_release (H5S_sel_iter_t *iter) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(iter); + +/* Release the information needed for non-regular hyperslab I/O */ + /* Free the copy of the selections span tree */ + if(iter->u.hyp.spans != NULL) + H5S_hyper_free_span_info(iter->u.hyp.spans); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_iter_release() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_new_span + PURPOSE + Make a new hyperslab span node + USAGE + H5S_hyper_span_t *H5S_hyper_new_span(low, high, down, next) + hsize_t low, high; IN: Low and high bounds for new span node + H5S_hyper_span_info_t *down; IN: Down span tree for new node + H5S_hyper_span_t *next; IN: Next span for new node + RETURNS + 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 */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Allocate a new span node */ + if(NULL == (ret_value = H5FL_MALLOC(H5S_hyper_span_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") + + /* Copy the span's basic information */ + ret_value->low = low; + ret_value->high = high; + ret_value->nelem = (high - low) + 1; + ret_value->pstride = 0; + ret_value->down = down; + ret_value->next = next; + + /* Increment the reference count of the 'down span' if there is one */ + if(ret_value->down) + ret_value->down->count++; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_new_span() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_span_precompute_helper + PURPOSE + Helper routine to precompute the nelem and pstrides in bytes. + USAGE + herr_t 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 + 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_helper (H5S_hyper_span_info_t *spans, size_t elmt_size) +{ + H5S_hyper_span_t *span; /* Hyperslab span */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(spans); + + /* Check if we've already set this down span tree */ + if(spans->scratch!=(H5S_hyper_span_info_t *)~((size_t)NULL)) { + /* Set the tree's scratch pointer */ + spans->scratch=(H5S_hyper_span_info_t *)~((size_t)NULL); + + /* Set the scratch pointers in all the nodes */ + span=spans->head; + + /* Loop over all the spans for this down span tree */ + while(span!=NULL) { + /* If there are down spans, set their scratch value also */ + if(span->down!=NULL) { + if(H5S_hyper_span_precompute_helper(span->down,elmt_size)==FAIL) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't reset hyperslab scratch pointer") + } /* end if */ + + /* Change the nelem & pstride values into bytes */ + span->nelem *= elmt_size; + span->pstride *= elmt_size; + + /* Advance to next span */ + span=span->next; + } /* end while */ + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_span_precompute_helper() */ + + +/*-------------------------------------------------------------------------- + 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) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(spans); + + /* Call the helper routine to actually do the work */ + if(H5S_hyper_span_precompute_helper(spans, elmt_size) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't precompute span info") + + /* Reset the scratch pointers for the next routine which needs them */ + H5S_hyper_span_scratch(spans, NULL); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_span_precompute() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_span_scratch + PURPOSE + Set 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 + <none> + DESCRIPTION + Set the scratch pointers on a hyperslab span tree. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static void +H5S_hyper_span_scratch(H5S_hyper_span_info_t *spans, void *scr_value) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(spans); + + /* Check if we've already set this down span tree */ + if(spans->scratch != scr_value) { + H5S_hyper_span_t *span; /* Hyperslab span */ + + /* Set the tree's scratch pointer */ + spans->scratch = (H5S_hyper_span_info_t *)scr_value; + + /* 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, scr_value); + + /* Advance to next span */ + span = span->next; + } /* end while */ + } /* end if */ + + FUNC_LEAVE_NOAPI_VOID +} /* H5S_hyper_span_scratch() */ + + +/*-------------------------------------------------------------------------- + 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 */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(spans); + + /* Check if the span tree was already copied */ + if(spans->scratch != NULL && spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)) { + /* Just return the value of the already copied span tree */ + ret_value = spans->scratch; + + /* 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_MALLOC(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; + ret_value->scratch = NULL; + ret_value->head = NULL; + + /* Set the scratch pointer in the node being copied to the newly allocated node */ + spans->scratch = ret_value; + + /* 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 + 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) +} /* H5S_hyper_copy_span_helper() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_copy_span + PURPOSE + Copy a hyperslab span tree + USAGE + H5S_hyper_span_info_t * H5S_hyper_copy_span(span_info) + 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 */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(spans); + + /* 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") + + /* Reset the scratch pointers for the next routine which needs them */ + H5S_hyper_span_scratch(spans, NULL); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_copy_span() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_cmp_spans + PURPOSE + Check if two hyperslab slabs are the same + USAGE + htri_d H5S_hyper_cmp_spans(span1, span2) + H5S_hyper_span_t *span1; IN: First span tree to compare + H5S_hyper_span_t *span2; IN: Second span tree to compare + RETURNS + TRUE (1) or FALSE (0) on success, negative on failure + DESCRIPTION + Compare two hyperslab slabs 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 htri_t +H5S_hyper_cmp_spans (H5S_hyper_span_info_t *span_info1, H5S_hyper_span_info_t *span_info2) +{ + H5S_hyper_span_t *span1; + H5S_hyper_span_t *span2; + htri_t nest=FAIL; + htri_t ret_value=FAIL; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check for redundant comparison */ + if(span_info1==span_info2) + ret_value=TRUE; + else { + /* Check for both spans being NULL */ + if(span_info1==NULL && span_info2==NULL) + ret_value=TRUE; + else { + /* Check for one span being NULL */ + if(span_info1==NULL || span_info2==NULL) + ret_value=FALSE; + else { + /* Get the pointers to the actual lists of spans */ + span1=span_info1->head; + span2=span_info2->head; + + /* 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((nest=H5S_hyper_cmp_spans(span1->down,span2->down))==FAIL) { + ret_value=FAIL; + break; + } /* end if */ + else { + if(nest==FALSE) { + ret_value=FALSE; + break; + } /* end if */ + else { + /* Keep going... */ + } /* end else */ + } /* end else */ + } /* end if */ + else { + /* Keep going... */ + } /* end else */ + } /* end else */ + } /* end else */ + } /* end else */ + + /* Advance to the next nodes in the span list */ + span1=span1->next; + span2=span2->next; + } /* end while */ + } /* end else */ + } /* end else */ + } /* end else */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_cmp_spans() */ + + +/*-------------------------------------------------------------------------- + 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 */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(span_info); + + /* 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) +} /* H5S_hyper_free_span_info() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_free_span + PURPOSE + Free a hyperslab span node + USAGE + herr_t H5S_hyper_free_span(span) + H5S_hyper_span_t *span; IN: Span node to free + RETURNS + 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. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_hyper_free_span (H5S_hyper_span_t *span) +{ + herr_t ret_value=SUCCEED; + + FUNC_ENTER_NOAPI_NOINIT + + 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") + } /* end if */ + + /* Free this span */ + span = H5FL_FREE(H5S_hyper_span_t, span); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* 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) + H5S_t *dst; OUT: Pointer to the destination dataspace + H5S_t *src; IN: Pointer to the source dataspace + 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_NOAPI(FAIL) + + HDassert(src); + HDassert(dst); + + /* Allocate space for the hyperslab selection information */ + if(NULL == (dst->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info") + + /* Set temporary pointers */ + dst_hslab=dst->select.sel_info.hslab; + src_hslab=src->select.sel_info.hslab; + + /* Copy the hyperslab information */ + dst_hslab->diminfo_valid=src_hslab->diminfo_valid; + if(src_hslab->diminfo_valid) { + size_t u; /* Local index variable */ + + for(u=0; u<src->extent.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_hslab->unlim_dim = src_hslab->unlim_dim; + dst_hslab->num_elem_non_unlim = src_hslab->num_elem_non_unlim; + dst->select.sel_info.hslab->span_lst=src->select.sel_info.hslab->span_lst; + + /* 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->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 */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_copy() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_is_valid_helper + PURPOSE + Check whether the selection fits within the extent, with the current + offset defined. + USAGE + htri_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 and + Negative on an error. + DESCRIPTION + Determines if the current selection at the current offet fits within the + extent for the dataspace. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static htri_t +H5S_hyper_is_valid_helper (const H5S_hyper_span_info_t *spans, const hssize_t *offset, const hsize_t *size, hsize_t rank) +{ + H5S_hyper_span_t *curr; /* Hyperslab information nodes */ + htri_t tmp; /* temporary return value */ + htri_t ret_value=TRUE; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(spans); + HDassert(offset); + HDassert(size); + HDassert(rank < H5O_LAYOUT_NDIMS); + + /* Check each point to determine whether selection+offset is within extent */ + curr=spans->head; + while(curr!=NULL && ret_value==TRUE) { + /* Check if an offset has been defined */ + /* Bounds check the selected point + offset against the extent */ + if((((hssize_t)curr->low+offset[rank])>=(hssize_t)size[rank]) + || (((hssize_t)curr->low+offset[rank])<0) + || (((hssize_t)curr->high+offset[rank])>=(hssize_t)size[rank]) + || (((hssize_t)curr->high+offset[rank])<0)) { + ret_value=FALSE; + break; + } /* end if */ + + /* Recurse if this node has down spans */ + if(curr->down!=NULL) { + if((tmp=H5S_hyper_is_valid_helper(curr->down,offset,size,rank+1))!=TRUE) { + ret_value=tmp; + break; + } /* end if */ + } /* end if */ + + /* Advance to next node */ + curr=curr->next; + } /* end while */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_is_valid_helper() */ + + +/*-------------------------------------------------------------------------- + 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 offet 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) +{ + unsigned u; /* Counter */ + htri_t ret_value = TRUE; /* return value */ + + FUNC_ENTER_NOAPI(FAIL) + + HDassert(space); + + /* 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 */ + + /* 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 { + /* 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,(hsize_t)0); + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_is_valid() */ + + +/*-------------------------------------------------------------------------- + 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(H5S_hyper_span_info_t *spans) +{ + H5S_hyper_span_t *span; /* Hyperslab span */ + hsize_t ret_value = 0; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Count the number of elements in the span tree */ + if(spans != NULL) { + 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++; + + /* Advance to next span */ + span = span->next; + } /* end while */ + } /* end else */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_span_nblocks() */ + + +/*-------------------------------------------------------------------------- + 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(H5S_t *space) +{ + hsize_t ret_value = 0; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(space); + HDassert(space->select.sel_info.hslab->unlim_dim < 0); + + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid) { + unsigned u; /* Local index variable */ + + /* 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(ret_value) +} /* H5S_get_select_hyper_nblocks() */ + + +/*-------------------------------------------------------------------------- + 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 */ + + FUNC_ENTER_API(FAIL) + H5TRACE1("Hs", "i", spaceid); + + /* Check args */ + if(NULL == (space = (H5S_t *)H5I_object_verify(spaceid, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") + 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") + + ret_value = (hssize_t)H5S_get_select_hyper_nblocks(space); + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Sget_select_hyper_nblocks() */ + + +/*-------------------------------------------------------------------------- + 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 */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(space); + + /* 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: + * <type (4 bytes)> + <version (4 bytes)> + <flags (1 byte)> + + * <length (4 bytes)> + <rank (4 bytes)> + + * (4 (start/stride/count/block) * <rank> * <value (8 bytes)>) = + * 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: + * <type (4 bytes)> + <version (4 bytes)> + <padding (4 bytes)> + + * <length (4 bytes)> + <rank (4 bytes)> + <# of blocks (4 bytes)> + * = 24 bytes + */ + ret_value = 24; + + /* 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); + + 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 */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_serial_size() */ + + +/*-------------------------------------------------------------------------- + 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 */ + hsize_t u; /* Index variable */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity checks */ + HDassert(spans); + HDassert(start); + HDassert(end); + HDassert(rank < H5O_LAYOUT_NDIMS); + HDassert(p && pp); + + /* Walk through the list of spans, recursing or outputing 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; + + /* Recurse down to the next dimension */ + H5S_hyper_serialize_helper(curr->down, start, end, rank + 1, &pp); + } /* end if */ + else { + /* Encode all the previous dimensions starting & ending points */ + + /* Encode previous starting points */ + for(u=0; u<rank; u++) + UINT32ENCODE(pp, (uint32_t)start[u]); + + /* Encode starting point for this span */ + UINT32ENCODE(pp, (uint32_t)curr->low); + + /* Encode previous ending points */ + for(u=0; u<rank; u++) + UINT32ENCODE(pp, (uint32_t)end[u]); + + /* Encode starting point for this span */ + UINT32ENCODE(pp, (uint32_t)curr->high); + } /* end else */ + + /* Advance to next node */ + curr=curr->next; + } /* end while */ + + /* Update encoding pointer */ + *p = pp; + + FUNC_LEAVE_NOAPI_VOID +} /* H5S_hyper_serialize_helper() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_serialize + PURPOSE + Serialize the current selection into a user-provided buffer. + 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. + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Serializes the current element selection into a buffer. (Primarily for + storing on disk). + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_hyper_serialize(const H5S_t *space, uint8_t **p) +{ + const H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */ + uint8_t *pp = (*p); /* Local pointer for decoding */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary hyperslab counts */ + hsize_t offset[H5O_LAYOUT_NDIMS]; /* Offset of element in dataspace */ + hsize_t start[H5O_LAYOUT_NDIMS]; /* Location of start of hyperslab */ + hsize_t end[H5O_LAYOUT_NDIMS]; /* Location of end of hyperslab */ + hsize_t temp_off; /* Offset in a given dimension */ + 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 */ + unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + unsigned ndims; /* Rank of the dataspace */ + int done; /* Whether we are done with the iteration */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(space); + HDassert(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 */ + + /* Encode number of dimensions */ + UINT32ENCODE(pp, (uint32_t)space->extent.rank); + len += 4; + + /* If there is an unlimited dimension, only encode opt_unlim_diminfo */ + if(flags & H5S_SELECT_FLAG_UNLIM) { + unsigned i; + + HDassert(H5S_UNLIMITED == HSIZE_UNDEF); + + /* 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) { + unsigned u; /* Local counting variable */ + + /* Set some convienence values */ + 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; + + /* Encode number of hyperslabs */ + H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t); + UINT32ENCODE(pp, (uint32_t)block_count); + len+=4; + + /* Now serialize the information for the regular hyperslab */ + + /* Build the tables of count sizes as well as the initial offset */ + for(u = 0; u < ndims; u++) { + tmp_count[u] = diminfo[u].count; + offset[u] = diminfo[u].start; + } /* end for */ + + /* We're not done with the iteration */ + done=0; + + /* Go iterate over the hyperslabs */ + while(done==0) { + /* Iterate over the blocks in the fastest dimension */ + while(tmp_count[fast_dim]>0) { + /* Add 8 bytes times the rank for each hyperslab selected */ + len+=8*ndims; + + /* Encode hyperslab starting location */ + for(u = 0; u < ndims; u++) + UINT32ENCODE(pp, (uint32_t)offset[u]); + + /* Encode hyperslab ending location */ + for(u = 0; u < ndims; u++) + UINT32ENCODE(pp, (uint32_t)(offset[u] + (diminfo[u].block - 1))); + + /* Move the offset to the next sequence to start */ + offset[fast_dim]+=diminfo[fast_dim].stride; + + /* Decrement the block count */ + tmp_count[fast_dim]--; + } /* end while */ + + /* Work on other dimensions if necessary */ + if(fast_dim > 0) { + int temp_dim; /* Temporary rank holder */ + + /* Reset the block counts */ + tmp_count[fast_dim]=diminfo[fast_dim].count; + + /* Bubble up the decrement to the slower changing dimensions */ + temp_dim = (int)fast_dim - 1; + while(temp_dim >= 0 && done == 0) { + /* Decrement the block count */ + tmp_count[temp_dim]--; + + /* Check if we have more blocks left */ + if(tmp_count[temp_dim] > 0) + break; + + /* Check for getting out of iterator */ + if(temp_dim == 0) + done = 1; + + /* Reset the block count in this dimension */ + tmp_count[temp_dim] = diminfo[temp_dim].count; + + /* Wrapped a dimension, go up to next dimension */ + temp_dim--; + } /* end while */ + } /* end if */ + else + break; /* Break out now, for 1-D selections */ + + /* Re-compute offset array */ + for(u = 0; u < ndims; u++) { + 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 { + /* 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; + + /* 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); + + /* Encode each hyperslab in selection */ + H5S_hyper_serialize_helper(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, &pp); + } /* end else */ + + /* Encode length */ + UINT32ENCODE(lenp, (uint32_t)len); /* Store the length of the extra information */ + + /* Update encoding pointer */ + *p = pp; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_serialize() */ + + +/*-------------------------------------------------------------------------- + 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 = (*p); /* Local pointer for decoding */ + size_t num_elem=0; /* number of elements in selection */ + hsize_t start[H5O_LAYOUT_NDIMS]; /* hyperslab start information */ + hsize_t end[H5O_LAYOUT_NDIMS]; /* hyperslab end information */ + hsize_t stride[H5O_LAYOUT_NDIMS]; /* hyperslab stride information */ + hsize_t count[H5O_LAYOUT_NDIMS]; /* hyperslab count information */ + hsize_t block[H5O_LAYOUT_NDIMS]; /* hyperslab block information */ + hsize_t *tstart=NULL; /* temporary hyperslab pointers */ + hsize_t *tend=NULL; /* temporary hyperslab pointers */ + hsize_t *tstride=NULL; /* temporary hyperslab pointers */ + hsize_t *tcount=NULL; /* temporary hyperslab pointers */ + hsize_t *tblock=NULL; /* temporary hyperslab pointers */ + unsigned i,j; /* local counting variables */ + herr_t ret_value=FAIL; /* return value */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Check args */ + HDassert(space); + HDassert(p); + HDassert(pp); + + /* Deserialize slabs to select */ + /* (The header and rank have already beed decoded) */ + rank = space->extent.rank; /* Retrieve rank from space */ + + /* If there is an unlimited dimension, only encode opt_unlim_diminfo */ + if(flags & H5S_SELECT_FLAG_UNLIM) { + HDassert(H5S_UNLIMITED == HSIZE_UNDEF); + HDassert(version >= 2); + + /* Iterate over dimensions */ + for(i = 0; i < space->extent.rank; i++) { + /* Decode start/stride/block/count */ + UINT64DECODE(pp, start[i]); + UINT64DECODE(pp, stride[i]); + UINT64DECODE(pp, count[i]); + UINT64DECODE(pp, block[i]); + } /* 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_CANTDELETE, FAIL, "can't change selection") + } /* end if */ + else { + /* decode the number of points */ + UINT32DECODE(pp,num_elem); + + /* Set the count & stride for all blocks */ + for(tcount = count, tstride = stride, j = 0; j < rank; j++, tstride++, tcount++) { + *tcount=1; + *tstride=1; + } /* end for */ + + /* Retrieve the coordinates from the buffer */ + for(i = 0; i < num_elem; i++) { + /* Decode the starting points */ + for(tstart=start,j=0; j<rank; j++,tstart++) + UINT32DECODE(pp, *tstart); + + /* Decode the ending points */ + for(tend = end, j = 0; j < rank; j++, tend++) + UINT32DECODE(pp, *tend); + + /* Change the ending points into blocks */ + for(tblock=block,tstart=start,tend=end,j=0; j<rank; j++,tstart++,tend++,tblock++) + *tblock=(*tend-*tstart)+1; + + /* Select or add the hyperslab to the current selection */ + if((ret_value=H5S_select_hyperslab(space,(i==0 ? H5S_SELECT_SET : H5S_SELECT_OR),start,stride,count,block))<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection") + } /* end for */ + } /* end else */ + + /* Update decoding pointer */ + *p = pp; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_deserialize() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_span_blocklist + PURPOSE + Get a list of hyperslab blocks currently selected + 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 + 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 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_span_blocklist(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_span_t *curr; /* Pointer to current hyperslab span */ + hsize_t u; /* Index variable */ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Sanity checks */ + HDassert(spans); + HDassert(rank < H5O_LAYOUT_NDIMS); + HDassert(start); + HDassert(end); + HDassert(startblock); + HDassert(numblocks && *numblocks > 0); + HDassert(buf && *buf); + + /* Walk through the list of spans, recursing or outputing them */ + curr = spans->head; + while(curr != NULL && *numblocks > 0) { + /* Recurse if this node has down spans */ + if(curr->down != NULL) { + /* Add the starting and ending points for this span to the list */ + start[rank] = curr->low; + end[rank] = curr->high; + + /* Recurse down to the next dimension */ + if(H5S_hyper_span_blocklist(curr->down, start, end, (rank + 1), startblock, numblocks, buf) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans") + } /* end if */ + else { + /* Skip this block if we haven't skipped all the startblocks yet */ + if(*startblock > 0) { + /* Decrement the starting block */ + (*startblock)--; + } /* end if */ + /* Process this block */ + else { + /* Encode all the previous dimensions starting & ending points */ + + /* Copy previous starting points */ + for(u = 0; u < rank; u++, (*buf)++) + HDmemcpy(*buf, &start[u], sizeof(hsize_t)); + + /* Copy starting point for this span */ + HDmemcpy(*buf, &curr->low, sizeof(hsize_t)); + (*buf)++; + + /* 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) +} /* H5S_hyper_span_blocklist() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_get_select_hyper_blocklist + PURPOSE + Get the list of hyperslab blocks currently selected + 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 + 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 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_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_NOAPI_NOINIT_NOERR + + HDassert(space); + HDassert(buf); + HDassert(space->select.sel_info.hslab->unlim_dim < 0); + + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid) { + const H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary hyperslab counts */ + hsize_t offset[H5O_LAYOUT_NDIMS]; /* Offset of element in dataspace */ + unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + unsigned ndims; /* Rank of the dataspace */ + hbool_t done; /* Whether we are done with the iteration */ + unsigned u; /* Counter */ + + /* Set some convienence values */ + ndims = space->extent.rank; + fast_dim = ndims - 1; + + /* Check which set of dimension information to use */ + if(internal) + /* + * Use the "optimized dimension information" to pass back information + * on the blocks set, not the "application information". + */ + diminfo = space->select.sel_info.hslab->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; + + /* Build the tables of count sizes as well as the initial offset */ + for(u = 0; u < ndims; u++) { + tmp_count[u] = diminfo[u].count; + offset[u] = diminfo[u].start; + } /* end for */ + + /* We're not done with the iteration */ + done = FALSE; + + /* Go iterate over the hyperslabs */ + while(!done && 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; + + /* Decrement the number of blocks to retrieve */ + numblocks--; + } /* end if */ + else + startblock--; + + /* Move the offset to the next sequence to start */ + offset[fast_dim] += diminfo[fast_dim].stride; + + /* Decrement the block count */ + tmp_count[fast_dim]--; + } /* end while */ + + /* Work on other dimensions if necessary */ + if(fast_dim > 0 && numblocks > 0) { + int temp_dim; /* Temporary rank holder */ + + /* Reset the block counts */ + tmp_count[fast_dim] = diminfo[fast_dim].count; + + /* Bubble up the decrement to the slower changing dimensions */ + temp_dim = (int)(fast_dim - 1); + while(temp_dim >= 0 && !done) { + /* Decrement the block count */ + tmp_count[temp_dim]--; + + /* Check if we have more blocks left */ + if(tmp_count[temp_dim] > 0) + break; + + /* Check for getting out of iterator */ + if(temp_dim == 0) + done = TRUE; + + /* Reset the block count in this dimension */ + tmp_count[temp_dim] = diminfo[temp_dim].count; + + /* Wrapped a dimension, go up to next dimension */ + temp_dim--; + } /* end while */ + } /* end if */ + + /* 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[H5O_LAYOUT_NDIMS]; /* Location of start of hyperslab */ + hsize_t end[H5O_LAYOUT_NDIMS]; /* 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) +} /* H5S_get_select_hyper_blocklist() */ + + +/*-------------------------------------------------------------------------- + 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_t *space; /* Dataspace to modify selection of */ + herr_t ret_value; /* return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE4("e", "ihh*[a2]h", spaceid, startblock, numblocks, buf); + + /* 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 data space") + 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") + + /* 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: + FUNC_LEAVE_API(ret_value) +} /* H5Sget_select_hyper_blocklist() */ + + +/*-------------------------------------------------------------------------- + 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_bounds_helper(const H5S_hyper_span_info_t *spans, const hssize_t *offset, hsize_t rank, hsize_t *start, hsize_t *end) +{ + H5S_hyper_span_t *curr; /* Hyperslab information nodes */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(spans); + HDassert(offset); + HDassert(rank < H5O_LAYOUT_NDIMS); + 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]; + + /* 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 */ + + /* Advance to next node */ + curr = curr->next; + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_bounds_helper() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_bounds + PURPOSE + Gets the bounding box containing the selection. + 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 + 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_bounds(const H5S_t *space, hsize_t *start, hsize_t *end) +{ + unsigned rank; /* Dataspace rank */ + unsigned i; /* index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + HDassert(space); + HDassert(start); + HDassert(end); + + /* 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 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 */ + + /* 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") + + /* 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 */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_bounds() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_offset + PURPOSE + Gets the linear offset of the first element for the selection. + USAGE + herr_t H5S_hyper_offset(space, offset) + const H5S_t *space; IN: Dataspace pointer of selection to query + hsize_t *offset; OUT: Linear offset of first element in selection + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Retrieves the linear offset (in "units" of elements) of the first element + selected within the dataspace. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Calling this function on a "none" selection returns fail. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_hyper_offset(const H5S_t *space, hsize_t *offset) +{ + const hssize_t *sel_offset; /* Pointer to the selection's offset */ + const hsize_t *dim_size; /* Pointer to a dataspace's extent */ + hsize_t accum; /* Accumulator for dimension sizes */ + unsigned rank; /* Dataspace rank */ + int i; /* index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + 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") + + /* 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) +} /* H5S_hyper_offset() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_unlim_dim + PURPOSE + Return unlimited dimension of selection, or -1 if none + USAGE + int H5S__hyper_unlim_dim(space) + H5S_t *space; IN: Dataspace pointer to check + RETURNS + Unlimited dimension of selection, or -1 if none (never fails). + DESCRIPTION + Returns the index of the unlimited dimension of the selection, or -1 + if the selection has no unlimited dimension. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static int +H5S__hyper_unlim_dim(const H5S_t *space) +{ + FUNC_ENTER_STATIC_NOERR + + FUNC_LEAVE_NOAPI(space->select.sel_info.hslab->unlim_dim); +} /* end H5S__hyper_unlim_dim() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_num_elem_non_unlim + PURPOSE + Return number of elements in the non-unlimited dimensions + 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 + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Returns the number of elements in a slice through the non-unlimited + dimensions of the selection. Fails if the selection has no unlimited + dimension. + 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) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(FAIL) + + /* Sanity check */ + HDassert(space); + HDassert(num_elem_non_unlim); + + /* 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_num_elem_non_unlim() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_is_contiguous + PURPOSE + Check if a hyperslab selection is contiguous within the dataspace extent. + USAGE + htri_t H5S_hyper_is_contiguous(space) + H5S_t *space; IN: Dataspace pointer to check + RETURNS + TRUE/FALSE/FAIL + DESCRIPTION + Checks to see if the current selection in the dataspace is contiguous. + This is primarily used for reading the entire selection in one swoop. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static htri_t +H5S_hyper_is_contiguous(const H5S_t *space) +{ + unsigned small_contiguous, /* Flag for small contiguous block */ + large_contiguous; /* Flag for large contiguous block */ + unsigned u; /* index variable */ + htri_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + HDassert(space); + + /* 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 */ + + /* + * 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) + */ + + /* Initialize flags */ + large_contiguous=TRUE; /* assume true and reset if the dimensions don't match */ + small_contiguous=FALSE; /* assume false initially */ + + /* Check for a "large contigous" block */ + for(u=0; u<space->extent.rank; u++) { + if(diminfo[u].count>1) { + large_contiguous=FALSE; + break; + } /* end if */ + if(u>0 && diminfo[u].block!=space->extent.size[u]) { + large_contiguous=FALSE; + break; + } /* end if */ + } /* end for */ + + /* If we didn't find a large contiguous block, check for a small one */ + if(large_contiguous==FALSE) { + small_contiguous=TRUE; + for(u=0; u<space->extent.rank; u++) { + if(diminfo[u].count>1) { + small_contiguous=FALSE; + break; + } /* end if */ + if(u<(space->extent.rank-1) && diminfo[u].block!=1) { + small_contiguous=FALSE; + break; + } /* end if */ + } /* end for */ + } /* end if */ + + /* Indicate true if it's either a large or small contiguous block */ + if(large_contiguous || small_contiguous) + ret_value=TRUE; + } /* end if */ + else { + H5S_hyper_span_info_t *spans; /* Hyperslab span info node */ + H5S_hyper_span_t *span; /* Hyperslab span node */ + + /* + * For a hyperslab to be contiguous, it must have only one block and + * (either it's size must be the same as the dataspace extent's in all + * but the slowest changing dimension + * OR + * block size must be 1 in all but the fastest changing dimension). + */ + /* Initialize flags */ + large_contiguous=TRUE; /* assume true and reset if the dimensions don't match */ + small_contiguous=FALSE; /* assume false initially */ + + /* Get information for slowest changing information */ + spans=space->select.sel_info.hslab->span_lst; + span=spans->head; + + /* If there are multiple spans in the slowest changing dimension, the selection isn't contiguous */ + if(span->next!=NULL) + large_contiguous=FALSE; + else { + /* Now check the rest of the dimensions */ + if(span->down!=NULL) { + u=1; /* Current dimension working on */ + + /* Get the span information for the next fastest dimension */ + spans=span->down; + + /* Cycle down the spans until we run out of down spans or find a non-contiguous span */ + while(spans!=NULL) { + span=spans->head; + + /* Check that this is the only span and it spans the entire dimension */ + if(span->next!=NULL) { + large_contiguous=FALSE; + break; + } /* end if */ + else { + /* If this span doesn't cover the entire dimension, then this selection isn't contiguous */ + if(((span->high-span->low)+1)!=space->extent.size[u]) { + large_contiguous=FALSE; + break; + } /* end if */ + else { + /* Walk down to the next span */ + spans=span->down; + + /* Increment dimension */ + u++; + } /* end else */ + } /* end else */ + } /* end while */ + } /* end if */ + } /* end else */ + + /* If we didn't find a large contiguous block, check for a small one */ + if(large_contiguous==FALSE) { + small_contiguous=TRUE; + + /* Get information for slowest changing information */ + spans=space->select.sel_info.hslab->span_lst; + span=spans->head; + + /* Current dimension working on */ + u=0; + + /* Cycle down the spans until we run out of down spans or find a non-contiguous span */ + while(spans!=NULL) { + span=spans->head; + + /* Check that this is the only span and it spans the entire dimension */ + if(span->next!=NULL) { + small_contiguous=FALSE; + break; + } /* end if */ + else { + /* If this span doesn't cover the entire dimension, then this selection isn't contiguous */ + if(u<(space->extent.rank-1) && ((span->high-span->low)+1)!=1) { + small_contiguous=FALSE; + break; + } /* end if */ + else { + /* Walk down to the next span */ + spans=span->down; + + /* Increment dimension */ + u++; + } /* end else */ + } /* end else */ + } /* end while */ + } /* end if */ + + /* Indicate true if it's either a large or small contiguous block */ + if(large_contiguous || small_contiguous) + ret_value=TRUE; + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_is_contiguous() */ + + +/*-------------------------------------------------------------------------- + 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 htri_t +H5S_hyper_is_single(const H5S_t *space) +{ + H5S_hyper_span_info_t *spans; /* Hyperslab span info node */ + H5S_hyper_span_t *span; /* Hyperslab span node */ + unsigned u; /* index variable */ + htri_t ret_value=TRUE; /* return value */ + + FUNC_ENTER_NOAPI(FAIL) + + HDassert(space); + + /* Check for a "single" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid) { + /* + * For a regular hyperslab to be single, it must have only one + * block (i.e. count==1 in all dimensions) + */ + + /* 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 for */ + } /* end if */ + else { + /* + * 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) { + span=spans->head; + + /* Check that this is the only span and it spans the entire dimension */ + if(span->next!=NULL) + HGOTO_DONE(FALSE) + else + /* Walk down to the next span */ + spans=span->down; + } /* end while */ + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_is_single() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_is_regular + PURPOSE + Check if a hyperslab selection is "regular" + USAGE + htri_t H5S_hyper_is_regular(space) + const H5S_t *space; IN: Dataspace pointer to check + RETURNS + TRUE/FALSE/FAIL + 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. + 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) +{ + htri_t ret_value = FAIL; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(space); + + /* Only simple check for regular hyperslabs for now... */ + if(space->select.sel_info.hslab->diminfo_valid) + ret_value=TRUE; + else + ret_value=FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_is_regular() */ + + +/*-------------------------------------------------------------------------- + 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 data space causes a core dump + * when closing some other data space. +--------------------------------------------------------------------------*/ +static herr_t +H5S_hyper_release(H5S_t *space) +{ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(FAIL) + + /* 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") + } /* end if */ + + /* 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) +} /* H5S_hyper_release() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_recover_span + PURPOSE + Recover a generated span, if appropriate + 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 + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Check if the current span needs to be recovered and free it if so. + Set the current span to the next span in any case. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_hyper_recover_span (unsigned *recover, H5S_hyper_span_t **curr_span, H5S_hyper_span_t *next_span) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(recover); + HDassert(curr_span); + + /* Check if the span should be recovered */ + if(*recover) { + H5S_hyper_free_span(*curr_span); + *recover=0; + } /* end if */ + + /* Set the current span to next span */ + *curr_span=next_span; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_recover_span() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_coord_to_span + PURPOSE + Create a span tree for a single element + 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 + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Create a span tree for a single element + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static H5S_hyper_span_t * +H5S_hyper_coord_to_span(unsigned rank, hsize_t *coords) +{ + 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_NOAPI_NOINIT + + HDassert(rank > 0); + HDassert(coords); + + /* Search for location to insert new element in tree */ + if(rank>1) { + /* Allocate a span info node */ + if((down = H5FL_MALLOC(H5S_hyper_span_info_t))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span") + + /* Set the reference count */ + down->count=0; + + /* Reset the scratch pad space */ + down->scratch=0; + + /* Build span tree for coordinates below this one */ + if((down->head=H5S_hyper_coord_to_span(rank-1,&coords[1]))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span") + } /* end if */ + + /* Build span for this coordinate */ + if((new_span = H5S_hyper_new_span(coords[0],coords[0],down,NULL))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span") + + /* Set return value */ + ret_value=new_span; + +done: + if(ret_value==NULL) { + if(down!=NULL) + H5S_hyper_free_span_info(down); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_coord_to_span() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_add_span_element_helper + PURPOSE + Add a single elment to a span tree + 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 + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Add a single element to an existing span tree. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Assumes that the element is not already covered by the span tree + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_hyper_add_span_element_helper(H5S_hyper_span_info_t *span_tree, unsigned rank, hsize_t *coords) +{ + 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_NOAPI_NOINIT + + HDassert(span_tree); + HDassert(rank > 0); + HDassert(coords); + + /* Get pointer to last span in span tree */ + tspan_info=span_tree; + if(span_tree->scratch) + tmp_span=(H5S_hyper_span_t *)span_tree->scratch; + else { + tmp_span=span_tree->head; + HDassert(tmp_span); + span_tree->scratch=(H5S_hyper_span_info_t *)tmp_span; + } /* end else */ + + /* Find last span tree which includes a portion of the coordinate */ + prev_span_info=NULL; + while(coords[0]>=tmp_span->low && coords[0]<=tmp_span->high) { + /* Move rank & coordinate offset down a dimension */ + rank--; + coords++; + + /* Remember the span tree we are descending into */ + prev_span_info=tspan_info; + tspan_info=tmp_span->down; + + /* Get the last span in this span's 'down' tree */ + if(tspan_info->scratch) + tmp_span=(H5S_hyper_span_t *)tspan_info->scratch; + else { + tmp_span=tspan_info->head; + HDassert(tmp_span); + tspan_info->scratch=(H5S_hyper_span_info_t *)tmp_span; + } /* end else */ + } /* end while */ + + /* Check if we made it all the way to the bottom span in the tree */ + if(rank>1) { + /* Before we create another span at this level in the tree, check if + * the last span's "down tree" was equal to any other spans in this + * list of spans in the span tree. + * + * If so, release last span information and make last span merge into + * previous span (if possible), or at least share their "down tree" + * information. + */ + tmp2_span=tspan_info->head; + while(tmp2_span!=tmp_span) { + if(H5S_hyper_cmp_spans(tmp2_span->down,tmp_span->down)==TRUE) { + /* Check for merging into previous span */ + if(tmp2_span->high+1==tmp_span->low) { + /* Release last span created */ + H5S_hyper_free_span(tmp_span); + + /* Increase size of previous span */ + tmp2_span->high++; + tmp2_span->nelem++; + + /* Reset the 'tmp_span' for the rest of this block's algorithm */ + tmp_span=tmp2_span; + } /* end if */ + /* Span is disjoint, but has the same "down tree" selection */ + else { + /* Release "down tree" information */ + H5S_hyper_free_span_info(tmp_span->down); + + /* Point at earlier span's "down tree" */ + tmp_span->down=tmp2_span->down; + + /* 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((new_span=H5S_hyper_coord_to_span(rank,coords))==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 */ + 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((new_span = H5S_hyper_new_span(coords[0],coords[0],NULL,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) +} /* H5S_hyper_add_span_element_helper() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_add_span_element + PURPOSE + Add a single elment to a span tree + 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 + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Add a single element to an existing span tree. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Assumes that the element is not already in the dataspace's selection + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5S_hyper_add_span_element(H5S_t *space, unsigned rank, hsize_t *coords) +{ + H5S_hyper_span_info_t *head = NULL; /* Pointer to new head of span tree */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(space); + HDassert(rank > 0); + HDassert(coords); + + /* 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_MALLOC(H5S_hyper_span_info_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + + /* Set the reference count */ + head->count = 1; + + /* Reset the scratch pad space */ + head->scratch = 0; + + /* Build span tree for this coordinate */ + if(NULL == (head->head = H5S_hyper_coord_to_span(rank, coords))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + + /* Allocate selection info */ + 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") + + /* Set the selection to the new span tree */ + space->select.sel_info.hslab->span_lst = head; + + /* Set selection type */ + space->select.type = H5S_sel_hyper; + + /* Reset "regular" hyperslab flag */ + space->select.sel_info.hslab->diminfo_valid = FALSE; + + /* Set unlim_dim */ + space->select.sel_info.hslab->unlim_dim = -1; + + /* Set # of elements in selection */ + space->select.num_elem = 1; + } /* end if */ + else { + if(H5S_hyper_add_span_element_helper(space->select.sel_info.hslab->span_lst, rank, coords) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + + /* 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) +} /* H5S_hyper_add_span_element() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_reset_scratch + PURPOSE + Reset the scratch information for span tree + USAGE + 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 + Resets the "scratch" pointers used for various tasks in computing hyperslab + spans. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5S_hyper_reset_scratch(H5S_t *space) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(space); + + /* 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, NULL); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_reset_scratch() */ + + +/*-------------------------------------------------------------------------- + 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 */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(space); + + /* Check the type of selection */ + switch(H5S_GET_SELECT_TYPE(space)) { + case H5S_SEL_ALL: /* All elements selected in dataspace */ + /* Convert current "all" selection to "real" hyperslab selection */ + { + hsize_t tmp_start[H5O_LAYOUT_NDIMS]; /* Temporary start information */ + hsize_t tmp_stride[H5O_LAYOUT_NDIMS]; /* Temporary stride information */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary count information */ + hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block information */ + unsigned u; /* Local index variable */ + + /* Fill in temporary information for the dimensions */ + for(u=0; u<space->extent.rank; u++) { + tmp_start[u]=0; + tmp_stride[u]=1; + tmp_count[u]=1; + tmp_block[u]=space->extent.size[u]; + } /* end for */ + + /* 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_SEL_HYPERSLABS: /* Hyperslab selection */ + break; + + 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 */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_convert() */ + +#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 */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Sanity check */ + HDassert((spans1 && spans2) || (spans1 == NULL && spans2 == NULL)); + + /* "NULL" span trees compare as overlapping */ + if(spans1==NULL && spans2==NULL) + HGOTO_DONE(TRUE); + + /* 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->high<curr2->low) + curr1=curr1->next; + /* Check for 2nd span entirely before 1st span */ + else if(curr2->high<curr1->low) + 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") + + /* If there is a span intersection in the down dimensions, the span trees overlap */ + if(status==TRUE) + HGOTO_DONE(TRUE); + + /* No intersection in down dimensions, advance to next span */ + if(curr1->high<curr2->high) + curr1=curr1->next; + else + curr2=curr2->next; + } /* end else */ + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_intersect_helper() */ + + +/*-------------------------------------------------------------------------- + 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 */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Sanity check */ + HDassert(space1); + HDassert(space2); + + /* 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") + + /* 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") + + /* 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") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_intersect() */ +#endif /* LATER */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_intersect_block_helper + PURPOSE + Helper routine to detect intersections in span trees + USAGE + htri_t H5S_hyper_intersect_block_helper(spans, start, end) + H5S_hyper_span_info_t *spans; IN: First span tree to operate with + hssize_t *offset; IN: Selection offset coordinate + hsize_t *start; IN: Starting coordinate for block + hsize_t *end; IN: Ending coordinate for block + RETURN + Non-negative on success, negative on failure + DESCRIPTION + Quickly detect intersections between span tree and block + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static htri_t +H5S_hyper_intersect_block_helper (const H5S_hyper_span_info_t *spans, hsize_t *start, hsize_t *end) +{ + H5S_hyper_span_t *curr; /* Pointer to current span in 1st span tree */ + htri_t status; /* Status from recursive call */ + htri_t ret_value=FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* 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 { + /* Recursively check spans in next dimension down */ + if((status=H5S_hyper_intersect_block_helper(curr->down,start+1,end+1))<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab intersection check") + + /* If there is a span intersection in the down dimensions, the span trees overlap */ + if(status==TRUE) + HGOTO_DONE(TRUE); + + /* No intersection in down dimensions, advance to next span */ + curr=curr->next; + } /* end else */ + } /* end else */ + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_intersect_block_helper() */ + + +/*-------------------------------------------------------------------------- + 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, hsize_t *start, hsize_t *end) +{ + htri_t ret_value=FAIL; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Sanity check */ + HDassert(space); + HDassert(start); + HDassert(end); + + /* Check for 'all' selection, instead of a hyperslab selection */ + /* (Technically, this shouldn't be in the "hyperslab" routines...) */ + if(H5S_GET_SELECT_TYPE(space)==H5S_SEL_ALL) + HGOTO_DONE(TRUE); + + /* Check that the space selection has a span tree */ + if(space->select.sel_info.hslab->span_lst==NULL) + if(H5S_hyper_generate_spans(space)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") + + /* Perform the span-by-span intersection check */ + if((ret_value=H5S_hyper_intersect_block_helper(space->select.sel_info.hslab->span_lst,start,end))<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab intersection check") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_intersect_block() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_adjust_helper_u + PURPOSE + Helper routine to adjust offsets in span trees + USAGE + herr_t H5S_hyper_adjust_helper_u(spans, offset) + H5S_hyper_span_info_t *spans; IN: Span tree to operate with + const hsize_t *offset; IN: Offset to subtract + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Adjust the location of the spans in a span tree by subtracting an offset + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_hyper_adjust_helper_u (H5S_hyper_span_info_t *spans, const hsize_t *offset) +{ + H5S_hyper_span_t *span; /* Pointer to current span in span tree */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity check */ + HDassert(spans); + HDassert(offset); + + /* Check if we've already set this down span tree */ + if(spans->scratch!=(H5S_hyper_span_info_t *)~((size_t)NULL)) { + /* Set the tree's scratch pointer */ + spans->scratch=(H5S_hyper_span_info_t *)~((size_t)NULL); + + /* Get the span lists for each span in this tree */ + span=spans->head; + + /* Iterate over the spans in tree */ + while(span!=NULL) { + /* Adjust span offset */ + HDassert(span->low>=*offset); + span->low-=*offset; + span->high-=*offset; + + /* Recursively adjust spans in next dimension down */ + if(span->down!=NULL) + H5S_hyper_adjust_helper_u(span->down,offset+1); + + /* Advance to next span in this dimension */ + span=span->next; + } /* end while */ + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_adjust_helper_u() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_adjust_u + PURPOSE + Adjust a hyperslab selection by subtracting an offset + USAGE + herr_t 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) +{ + unsigned u; /* Local index variable */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(space); + HDassert(offset); + + /* Subtract the offset from the "regular" coordinates, if they exist */ + if(space->select.sel_info.hslab->diminfo_valid) { + 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 */ + + /* Subtract the offset from the span tree coordinates, if they exist */ + if(space->select.sel_info.hslab->span_lst) { + if(H5S_hyper_adjust_helper_u(space->select.sel_info.hslab->span_lst,offset)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab offset adjustment") + + /* Reset the scratch pointers for the next routine which needs them */ + H5S_hyper_span_scratch(space->select.sel_info.hslab->span_lst, NULL); + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_adjust_u() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_project_scalar + * + * Purpose: Projects a single element hyperslab selection into a scalar + * dataspace + * + * Return: non-negative on success, negative on failure. + * + * Programmer: Quincey Koziol + * Sunday, July 18, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_hyper_project_scalar(const H5S_t *space, hsize_t *offset) +{ + hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Check args */ + HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space)); + HDassert(offset); + + /* Check for a "regular" hyperslab selection */ + if(space->select.sel_info.hslab->diminfo_valid) { + const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->opt_diminfo; /* Alias for dataspace's diminfo information */ + unsigned u; /* Counter */ + + /* Build the table of the initial offset */ + for(u = 0; u < space->extent.rank; u++) { + block[u] = diminfo[u].start; + + /* Check for more than one hyperslab */ + if(diminfo[u].count > 1 || diminfo[u].block > 1) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "hyperslab selection of one element has more than one node!") + } /* end for */ + } /* end if */ + else { + const H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */ + unsigned curr_dim; /* Current dimension being operated on */ + + /* Advance down selected spans */ + curr = space->select.sel_info.hslab->span_lst->head; + curr_dim = 0; + while(curr) { + /* Check for more than one span */ + if(curr->next || curr->low != curr->high) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "hyperslab selection of one element has more than one node!") + + /* Save the location of the selection in current dimension */ + block[curr_dim] = curr->low; + + /* Advance down to next dimension */ + curr = curr->down->head; + curr_dim++; + } /* end while */ + } /* end else */ + + /* Calculate offset of selection in projected buffer */ + *offset = H5VM_array_offset(space->extent.rank, space->extent.size, block); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_project_scalar() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_project_simple_lower + * + * Purpose: Projects a hyperslab selection onto/into a simple dataspace + * of a lower rank + * + * Return: non-negative on success, negative on failure. + * + * Programmer: Quincey Koziol + * Sunday, July 18, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_hyper_project_simple_lower(const H5S_t *base_space, H5S_t *new_space) +{ + H5S_hyper_span_info_t *down; /* Pointer to list of spans */ + unsigned curr_dim; /* Current dimension being operated on */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space)); + HDassert(new_space); + HDassert(new_space->extent.rank < base_space->extent.rank); + + /* Walk down the span tree until we reach the selection to project */ + down = base_space->select.sel_info.hslab->span_lst; + curr_dim = 0; + while(down && curr_dim < (base_space->extent.rank - new_space->extent.rank)) { + /* Sanity check */ + HDassert(NULL == down->head->next); + + /* Advance down to next dimension */ + down = down->head->down; + curr_dim++; + } /* end while */ + HDassert(down); + + /* Share the underlying hyperslab span information */ + new_space->select.sel_info.hslab->span_lst = down; + new_space->select.sel_info.hslab->span_lst->count++; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_project_simple_lower() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_project_simple_higher + * + * Purpose: Projects a hyperslab selection onto/into a simple dataspace + * of a higher rank + * + * Return: non-negative on success, negative on failure. + * + * Programmer: Quincey Koziol + * Sunday, July 18, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_hyper_project_simple_higher(const H5S_t *base_space, H5S_t *new_space) +{ + H5S_hyper_span_t *prev_span = NULL; /* Pointer to previous list of spans */ + unsigned curr_dim; /* Current dimension being operated on */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* 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; + while(curr_dim < (new_space->extent.rank - base_space->extent.rank)) { + H5S_hyper_span_info_t *new_span_info; /* Pointer to list of spans */ + H5S_hyper_span_t *new_span; /* Temporary hyperslab span */ + + /* Allocate a new span_info node */ + if(NULL == (new_span_info = H5FL_MALLOC(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(0, 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->scratch = NULL; + 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); + + /* Share the underlying hyperslab span information */ + prev_span->down = base_space->select.sel_info.hslab->span_lst; + prev_span->down->count++; + +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) +} /* H5S_hyper_project_simple_higher() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_project_simple + * + * Purpose: Projects a hyperslab selection onto/into a simple dataspace + * of a different rank + * + * Return: non-negative on success, negative on failure. + * + * Programmer: Quincey Koziol + * Sunday, July 18, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_hyper_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *offset) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Check args */ + HDassert(base_space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(base_space)); + HDassert(new_space); + HDassert(offset); + + /* We are setting a new selection, remove any current selection in new dataspace */ + if(H5S_SELECT_RELEASE(new_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") + + /* Allocate space for the hyperslab selection information */ + if(NULL == (new_space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info") + + /* Set unlim_dim */ + new_space->select.sel_info.hslab->unlim_dim = -1; + + /* Check for a "regular" hyperslab selection */ + if(base_space->select.sel_info.hslab->diminfo_valid) { + 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 less 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; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_project_simple() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_adjust_helper_s + PURPOSE + Helper routine to adjust offsets in span trees + USAGE + herr_t H5S_hyper_adjust_helper_s(spans, offset) + H5S_hyper_span_info_t *spans; IN: Span tree to operate with + const hssize_t *offset; IN: Offset to subtract + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Adjust the location of the spans in a span tree by subtracting an offset + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_hyper_adjust_helper_s(H5S_hyper_span_info_t *spans, const hssize_t *offset) +{ + H5S_hyper_span_t *span; /* Pointer to current span in span tree */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Sanity check */ + HDassert(spans); + HDassert(offset); + + /* Check if we've already set this down span tree */ + if(spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)) { + /* Set the tree's scratch pointer */ + spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL); + + /* Get the span lists for each span in this tree */ + span = spans->head; + + /* Iterate over the spans in tree */ + 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); + + /* Recursively adjust spans in next dimension down */ + if(span->down != NULL) + H5S_hyper_adjust_helper_s(span->down, offset + 1); + + /* Advance to next span in this dimension */ + span = span->next; + } /* end while */ + } /* end if */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_adjust_helper_s() */ + + +/*-------------------------------------------------------------------------- + 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) +{ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(space); + HDassert(offset); + + /* Subtract the offset from the "regular" coordinates, if they exist */ + if(space->select.sel_info.hslab->diminfo_valid) { + 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 */ + + /* Subtract the offset from the span tree coordinates, if they exist */ + if(space->select.sel_info.hslab->span_lst) { + if(H5S_hyper_adjust_helper_s(space->select.sel_info.hslab->span_lst, offset) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab offset adjustment") + + /* Reset the scratch pointers for the next routine which needs them */ + H5S_hyper_span_scratch(space->select.sel_info.hslab->span_lst, NULL); + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_adjust_s() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_normalize_offset + PURPOSE + "Normalize" a hyperslab selection by adjusting it's coordinates by the + amount of the selection offset. + USAGE + herr_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 + Non-negative on success, negative on failure + 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) +{ + unsigned u; /* Local index variable */ + herr_t ret_value = FALSE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(space); + + /* Check for hyperslab selection & offset changed */ + if(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS && space->select.offset_changed) { + /* 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 existing 'adjust' routine */ + if(H5S_hyper_adjust_s(space, space->select.offset) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab normalization") + + /* Zero out the selection offset */ + HDmemset(space->select.offset, 0, sizeof(hssize_t) * space->extent.rank); + + /* Indicate that the offset was normalized */ + ret_value = TRUE; + } /* end if */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_normalize_offset() */ + + +/*-------------------------------------------------------------------------- + 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_normalize_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_hyper_denormalize_offset(H5S_t *space, const hssize_t *old_offset) +{ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(space); + HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS); + + /* Call the existing 'adjust' routine */ + if(H5S_hyper_adjust_s(space, old_offset) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADSELECT, FAIL, "can't perform hyperslab normalization") + + /* Copy the selection offset over */ + HDmemcpy(space->select.offset, old_offset, sizeof(hssize_t) * space->extent.rank); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* 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 */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(prev_span); + HDassert(span_tree); + + /* Check for adding first node to merged spans */ + if(*prev_span==NULL) { + /* Allocate new span node to append to list */ + if((new_span = H5S_hyper_new_span(low,high,down,next))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + + /* Make first node in span list */ + + /* Check that we haven't already allocated a span tree */ + HDassert(*span_tree==NULL); + + /* Allocate a new span_info node */ + if((*span_tree = H5FL_MALLOC(H5S_hyper_span_info_t))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span") + + /* Set the span tree's basic information */ + (*span_tree)->count=1; + (*span_tree)->scratch=NULL; + (*span_tree)->head=new_span; + + /* 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((new_span = H5S_hyper_new_span(low,high,down,next))==NULL) + 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)==TRUE) { + /* 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) + if(H5S_hyper_free_span(new_span) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "failed to release new hyperslab span") + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* 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, the area defined by the overlap of the 'a' hyperslab span + tree and the 'b' span tree, and the area defined by the 'b' hyperslab span + tree which does not overlap the 'a' span tree. + 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 */ + unsigned recover_a, recover_b; /* Flags to indicate when to recover temporary spans */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* 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((*b_not_a=H5S_hyper_copy_span(b_spans))==NULL) + 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((*a_not_b=H5S_hyper_copy_span(a_spans))==NULL) + 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)==TRUE) { + *a_not_b=NULL; + if((*a_and_b=H5S_hyper_copy_span(a_spans))==NULL) + 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; + + /* Set the pointer to the previous spans */ + last_a_not_b=NULL; + last_a_and_b=NULL; + last_b_not_a=NULL; + + /* No spans to recover yet */ + recover_a=recover_b=0; + + /* 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 */ + + /* 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 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' */ + + /* 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 upper part of span 'a' and lower part of span 'b' */ + + /* Make certain both spans either have a down span or both don't have one */ + HDassert((span_a->down != NULL && span_b->down != NULL) || (span_a->down == NULL && span_b->down == NULL)); + + /* If there are no down spans, just add the overlapping area to the a_and_b list */ + if(span_a->down==NULL) { + /* Merge/add overlapped part with/to a_and_b list */ + if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_b->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!=NULL) { + /* 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!=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,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_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); + } /* end if */ + } /* end else */ + + /* Split off upper part of span 'b' at upper span of span 'a' */ + + /* Check if there is actually an upper part of span 'b' to split off */ + if(span_a->high<span_b->high) { + /* Allocate new span node for upper part of span 'b' */ + if((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, 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=1; + } /* 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!=NULL) { + /* 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!=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,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_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((tmp_span = H5S_hyper_new_span(span_b->high+1,span_a->high,span_a->down,span_a->next))==NULL) + HGOTO_ERROR(H5E_RESOURCE, 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=1; + + /* 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!=NULL) { + /* 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((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, 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!=NULL) { + /* 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!=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_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((tmp_span = H5S_hyper_new_span(span_b->high+1,span_a->high,span_a->down,span_a->next))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 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) +} /* 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 *tmp_spans; /* Pointer to temporary new span tree */ + H5S_hyper_span_t *tmp_span; /* Pointer to temporary new span */ + H5S_hyper_span_t *span_a; /* Pointer to current span 'a' working on */ + H5S_hyper_span_t *span_b; /* Pointer to current span 'b' working on */ + H5S_hyper_span_t *prev_span_merge; /* Pointer to previous merged span */ + unsigned recover_a, recover_b; /* Flags to indicate when to recover temporary spans */ + H5S_hyper_span_info_t *ret_value = NULL; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* 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)==TRUE) { + if(a_spans==NULL) + merged_spans=NULL; + else { + /* Copy one of the span trees to return */ + if((merged_spans=H5S_hyper_copy_span(a_spans))==NULL) + HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree") + } /* end else */ + } /* end if */ + else { + /* Get the pointers to the 'a' and 'b' span lists */ + span_a=a_spans->head; + span_b=b_spans->head; + + /* Set the pointer to the previous spans */ + prev_span_merge=NULL; + + /* No spans to recover yet */ + recover_a=recover_b=0; + + /* Work through the list of spans in the new list */ + while(span_a!=NULL && span_b!=NULL) { + /* Check if the 'a' span is completely before 'b' span */ + /* AAAAAAA */ + /* <-----------------------------------> */ + /* BBBBBBBBBB */ + if(span_a->high<span_b->low) { + /* Merge/add span 'a' with/to the merged spans */ + if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,span_a->down,NULL)==FAIL) + HGOTO_ERROR(H5E_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)==TRUE) { + /* 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=1; + } /* 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)==TRUE) { + /* 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((tmp_span = H5S_hyper_new_span(span_b->high+1,span_a->high,span_a->down,span_a->next))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 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=1; + + /* 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)==TRUE) { + /* 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((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=1; + } /* 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)==TRUE) { + /* Merge/add copy of span 'b' to merged spans if so */ + if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,span_b->down,NULL)==FAIL) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + } /* end if */ + else { + /* Check if there is a lower part of span 'b' */ + if(span_a->low>span_b->low) { + /* Merge/add lower part of span 'b' to merged spans */ + if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->low-1,span_b->down,NULL)==FAIL) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span") + } /* end if */ + else { + /* No lower part of span 'b' , keep going... */ + } /* end else */ + + /* 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_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' */ + + /* Allocate new span node to append to list */ + if((tmp_span = H5S_hyper_new_span(span_b->high+1,span_a->high,span_a->down,span_a->next))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 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=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 { + /* 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 */ + } /* 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 */ + + /* 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") + + /* 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 */ + + /* Set return value */ + ret_value = merged_spans; + +done: + if(ret_value == NULL) { + if(merged_spans) + if(H5S_hyper_free_span_info(merged_spans) < 0) + HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, NULL, "failed to release merged hyperslab spans") + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* 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_NOAPI_NOINIT_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; + + /* Get the merged spans */ + merged_spans=H5S_hyper_merge_spans_helper(space->select.sel_info.hslab->span_lst, new_spans); + + /* Sanity checking since we started with some spans, we should still have some after the merge */ + HDassert(merged_spans); + + /* Free the previous spans */ + H5S_hyper_free_span_info(space->select.sel_info.hslab->span_lst); + + /* Point to the new merged spans */ + space->select.sel_info.hslab->span_lst=merged_spans; + } /* end else */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_hyper_merge_spans() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_spans_nelem + PURPOSE + Count the number of elements in a span tree + USAGE + hsize_t H5S_hyper_spans_nelem(spans) + const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of + RETURNS + Number of elements in span tree on success; negative on failure + DESCRIPTION + Counts the number of elements described by the spans in a span tree. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static hsize_t +H5S_hyper_spans_nelem (H5S_hyper_span_info_t *spans) +{ + H5S_hyper_span_t *span; /* Hyperslab span */ + hsize_t ret_value = 0; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Count the number of elements in the span tree */ + if(spans==NULL) + ret_value=0; + else { + span=spans->head; + ret_value=0; + 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; + + /* Advance to next span */ + span=span->next; + } /* end while */ + } /* end else */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_spans_nelem() */ + + +/*-------------------------------------------------------------------------- + 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 */ + + FUNC_ENTER_NOAPI_NOINIT + + /* 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 else */ + } /* end for */ + + /* Allocate a span info node */ + if(NULL == (down = H5FL_MALLOC(H5S_hyper_span_info_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span") + + /* Set the reference count */ + down->count = 0; + + /* Reset the scratch pad space */ + down->scratch = 0; + + /* Keep the pointer to the next dimension down's completed list */ + down->head = head; + } /* end for */ + + /* Indicate that there is a pointer to this tree */ + down->count = 1; + + /* Success! Return the head of the list in the slowest changing dimension */ + ret_value = down; + +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 */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_make_spans() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_rebuild_helper + PURPOSE + Helper routine to rebuild optimized hyperslab information if possible. + (It can be recovered with regular selection) + USAGE + herr_t H5S_hyper_rebuild_helper(space) + const H5S_hyper_span_t *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 + >=0 on success, <0 on failure + DESCRIPTION + Examine the span tree for a hyperslab selection and rebuild + the start/stride/count/block information for the selection, if possible. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + To be able to recover the optimized information, the span tree must conform + to span tree able to be generated from a single H5S_SELECT_SET operation. + + EXAMPLES + REVISION LOG + KY, 2005/9/22 +--------------------------------------------------------------------------*/ +static hbool_t +H5S_hyper_rebuild_helper(const H5S_hyper_span_t *span, H5S_hyper_dim_t span_slab_info[], + unsigned rank) +{ + hsize_t curr_stride, next_stride; + hsize_t curr_block, next_block; + hsize_t curr_start; + hsize_t curr_low; + size_t outcount; + unsigned u; + H5S_hyper_dim_t canon_down_span_slab_info[H5S_MAX_RANK]; + hbool_t ret_value = TRUE; + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + if(span) { + /* Initialization */ + curr_stride = 1; + curr_block = 0; + outcount = 0; + curr_low = 0; + + /* Get "canonical" down span information */ + if(span->down) { + HDassert(span->down->head); + + /* 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) + + HDmemcpy(canon_down_span_slab_info, span_slab_info, sizeof(H5S_hyper_dim_t) * rank); + } /* end if */ + + /* Assign the initial starting point & block size */ + curr_start = span->low; + curr_block = (span->high - span->low) + 1; + + /* Loop the span */ + while(span) { + if(outcount > 0) { + if(span->down) { + H5S_hyper_dim_t *curr_down_span_slab_info; + + HDassert(span->down->head); + + /* 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) + + /* Compare the slab information of the adjacent spans in the down span tree. + We have to compare all the sub-tree slab information with the canon_down_span_slab_info.*/ + + for( u = 0; u < rank - 1; u++) { + curr_down_span_slab_info = &span_slab_info[u]; + + if(curr_down_span_slab_info->count > 0 && canon_down_span_slab_info[u].count > 0) { + if(curr_down_span_slab_info->start != canon_down_span_slab_info[u].start + || curr_down_span_slab_info->stride != canon_down_span_slab_info[u].stride + || curr_down_span_slab_info->block != canon_down_span_slab_info[u].block + || curr_down_span_slab_info->count != canon_down_span_slab_info[u].count) + HGOTO_DONE(FALSE) + } /* end if */ + else if (!((curr_down_span_slab_info->count == 0) && (canon_down_span_slab_info[u].count == 0))) + HGOTO_DONE(FALSE) + } + } /* end if */ + } /* 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. Ignore the first two spans. + */ + if(outcount > 1 && curr_stride != next_stride) + HGOTO_DONE(FALSE) + if(outcount != 0 && next_block != curr_block) + HGOTO_DONE(FALSE) + + /* Keep the isolated stride to be 1 */ + if(outcount != 0) + curr_stride = next_stride; + + /* Keep current starting point */ + curr_low = span->low; + + /* Advance to next span */ + span = span->next; + outcount++; + } /* end while */ + + /* 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 */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_rebuild_helper() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_rebuild + PURPOSE + Rebuild optimized hyperslab information if possible. + (It can be recovered with regular selection) + USAGE + herr_t H5S_hyper_rebuild(space) + const H5S_t *space; IN: Dataspace to check + RETURNS + >=0 on success, <0 on failure + DESCRIPTION + Examine the span tree for a hyperslab selection and rebuild + the start/stride/count/block information for the selection, if possible. + + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + 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 htri_t +H5S_hyper_rebuild(H5S_t *space) +{ + H5S_hyper_dim_t top_span_slab_info[H5O_LAYOUT_NDIMS]; + H5S_hyper_dim_t *diminfo; + H5S_hyper_dim_t *app_diminfo; + unsigned rank, curr_dim; + htri_t ret_value = TRUE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(space); + HDassert(space->select.sel_info.hslab->span_lst); + + /* Check the rank of space */ + rank = space->extent.rank; + + /* 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 { + 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 */ + + space->select.sel_info.hslab->diminfo_valid = TRUE; + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_rebuild() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_generate_spans + PURPOSE + Create span tree for a regular hyperslab selection + USAGE + herr_t H5S_hyper_generate_spans(space) + H5S_t *space; IN/OUT: Pointer to dataspace + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Create a span tree representation of a regular hyperslab selection and + add it to the information for the hyperslab selection. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_hyper_generate_spans(H5S_t *space) +{ + hsize_t tmp_start[H5O_LAYOUT_NDIMS]; /* Temporary start information */ + hsize_t tmp_stride[H5O_LAYOUT_NDIMS]; /* Temporary stride information */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary count information */ + hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block information */ + unsigned u; /* Counter */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + 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") + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_hyper_generate_spans() */ + +#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 (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[]) +{ + 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 */ + + FUNC_ENTER_NOAPI_NOINIT + + /* 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((new_spans=H5S_hyper_make_spans(space->extent.rank,start,stride,count,block))==NULL) + 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; + + 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; + + /* Reset the number of items in selection */ + space->select.num_elem=0; + + /* 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") + + /* Update the number of elements in current selection */ + space->select.num_elem=H5S_hyper_spans_nelem(a_and_b); + + /* Indicate that the a_and_b spans are owned */ + a_and_b=NULL; + + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* end if */ + break; + + 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; + + /* Reset the number of items in selection */ + space->select.num_elem=0; + + /* 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") + + /* Update the number of elements in current selection */ + space->select.num_elem=H5S_hyper_spans_nelem(a_not_b); + + /* 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") + + /* 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; + + 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; + + /* Reset the number of items in selection */ + space->select.num_elem=0; + + /* 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") + + /* Update the number of elements in current selection */ + space->select.num_elem=H5S_hyper_spans_nelem(a_not_b); + + /* Indicate that the a_not_b are owned */ + a_not_b=NULL; + + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* end if */ + break; + + 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; + + /* Reset the number of items in selection */ + space->select.num_elem=0; + + /* 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") + + /* Update the number of elements in current selection */ + space->select.num_elem=H5S_hyper_spans_nelem(b_not_a); + + /* 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); + + /* 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") + + /* Set the reference count */ + spans->count=1; + + /* Reset the scratch pad space */ + spans->scratch=0; + + /* Set to empty tree */ + spans->head=NULL; + + /* 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 + */ + if(H5S_hyper_rebuild(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't rebuild hyperslab info") + } /* end if */ + } /* end else */ + } /* end else */ + +done: + /* Free resources */ + if(a_not_b) + if(H5S_hyper_free_span_info(a_not_b) < 0) + HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans") + if(a_and_b) + if(H5S_hyper_free_span_info(a_and_b) < 0) + HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans") + if(b_not_a) + if(H5S_hyper_free_span_info(b_not_a) < 0) + HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans") + if(new_spans) + if(H5S_hyper_free_span_info(new_spans) < 0) + HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_generate_hyperslab() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_select_hyperslab + * + * Purpose: Internal version of H5Sselect_hyperslab(). + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, January 10, 2001 + * + *------------------------------------------------------------------------- + */ +herr_t +H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, + const hsize_t start[], + const hsize_t *stride, + const hsize_t count[], + const hsize_t *block) +{ + hsize_t int_stride[H5O_LAYOUT_NDIMS]; /* Internal storage for stride information */ + hsize_t int_count[H5O_LAYOUT_NDIMS]; /* Internal storage for count information */ + hsize_t int_block[H5O_LAYOUT_NDIMS]; /* 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 */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Check args */ + HDassert(space); + HDassert(start); + HDassert(count); + HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + + /* Point to the correct stride values */ + if(stride==NULL) + stride = _ones; + + /* Point to the correct block values */ + if(block==NULL) + block = _ones; + + /* Check for unlimited dimension */ + for(u = 0; u<space->extent.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 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_CANTDELETE, 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 */ + } /* end for */ + + /* Optimize hyperslab parameters to merge contiguous blocks, etc. */ + if(stride == _ones && block == _ones) { + /* Point to existing arrays */ + opt_stride = _ones; + opt_count = _ones; + 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); + + /* 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 */ + + /* 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 */ + { + hsize_t tmp_start[H5O_LAYOUT_NDIMS]; /* Temporary start information */ + hsize_t tmp_stride[H5O_LAYOUT_NDIMS]; /* Temporary stride information */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary count information */ + hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block information */ + + /* Fill in temporary information for the dimensions */ + for(u=0; u<space->extent.rank; u++) { + tmp_start[u]=0; + tmp_stride[u]=1; + tmp_count[u]=1; + tmp_block[u]=space->extent.size[u]; + } /* end for */ + + /* 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_CANTDELETE, 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 */ + + case H5S_SEL_ERROR: + case H5S_SEL_N: + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ + + 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") + + /* Allocate space for the hyperslab selection information */ + if(NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info") + + /* Save the diminfo */ + space->select.num_elem = 1; + for(u = 0; 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]; + + 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]; + + space->select.num_elem *= (opt_count[u] * opt_block[u]); + } /* end for */ + + /* Save unlim_dim */ + space->select.sel_info.hslab->unlim_dim = unlim_dim; + + /* Indicate that the dimension information is valid */ + space->select.sel_info.hslab->diminfo_valid = TRUE; + + /* Indicate that there's no slab information */ + space->select.sel_info.hslab->span_lst = NULL; + + /* 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]); + + /* 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); + + /* 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") + + /* 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") + + /* 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 != _ones)); + HDassert((tmp_block == 1) || (opt_block != _ones)); + if(opt_count != _ones) { + HDassert(opt_count == int_count); + int_count[unlim_dim] = tmp_count; + } /* end if */ + if(opt_block != _ones) { + HDassert(opt_block == int_block); + int_block[unlim_dim] = tmp_block; + } /* end if */ + } /* 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") + + /* Indicate that the regular dimensions are no longer valid */ + space->select.sel_info.hslab->diminfo_valid = FALSE; + + /* Add in the new hyperslab information */ + if(H5S_generate_hyperslab(space, op, start, opt_stride, opt_count, opt_block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs") + } /* end if */ + else + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + + /* Set selection type */ + space->select.type = H5S_sel_hyper; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_select_hyperslab() */ + + +/*-------------------------------------------------------------------------- + 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 */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE6("e", "iSs*h*h*h*h", space_id, op, start, stride, count, block); + + /* Check args */ + if(NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") + 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) { + /* 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 for */ + } /* end if */ + + if (H5S_select_hyperslab(space, op, start, stride, count, block)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Sselect_hyperslab() */ +#else /* NEW_HYPERSLAB_API */ /* Works */ + +/*------------------------------------------------------------------------- + * Function: H5S_operate_hyperslab + * + * Purpose: Combines two hyperslabs with an operation, putting the + * result into a third hyperslab selection + * + * Return: non-negative on success/NULL on failure + * + * Programmer: Quincey Koziol + * Tuesday, October 30, 2001 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_operate_hyperslab (H5S_t *result, H5S_hyper_span_info_t *spans1, H5S_seloper_t op, H5S_hyper_span_info_t *spans2, + hbool_t can_own_span2, hbool_t *span2_owned) +{ + H5S_hyper_span_info_t *a_not_b=NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */ + H5S_hyper_span_info_t *a_and_b=NULL; /* Span tree for hyperslab spans in both old and new span trees */ + H5S_hyper_span_info_t *b_not_a=NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Check args */ + HDassert(result); + HDassert(spans2); + HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + + /* 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") + + /* Update the number of elements in current selection */ + result->select.num_elem=H5S_hyper_spans_nelem(spans2); + + /* 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 */ + + HDassert(spans1); + + /* Generate lists of spans which overlap and don't overlap */ + if(H5S_hyper_clip_spans(spans1,spans2,&a_not_b,&a_and_b,&b_not_a)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") + + /* Switch on the operation */ + switch(op) { + case H5S_SELECT_OR: + /* Copy spans from spans1 to current selection */ + if(spans1!=NULL) { + if(H5S_hyper_merge_spans(result,spans1,FALSE)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + + /* Update the number of elements in current selection */ + result->select.num_elem=H5S_hyper_spans_nelem(spans1); + } /* end if */ + + /* Add any new spans from spans2 to current selection */ + if(b_not_a!=NULL) { + if(H5S_hyper_merge_spans(result,b_not_a,FALSE)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs") + + /* Update the number of elements in current selection */ + result->select.num_elem+=H5S_hyper_spans_nelem(b_not_a); + + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* end if */ + break; + + 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") + + /* Update the number of elements in current selection */ + result->select.num_elem=H5S_hyper_spans_nelem(a_and_b); + + /* Indicate that the result owns the a_and_b spans */ + a_and_b=NULL; + + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* end if */ + break; + + 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") + + /* Update the number of elements in current selection */ + result->select.num_elem=H5S_hyper_spans_nelem(a_not_b); + + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* 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") + + /* Update the number of elements in current selection */ + result->select.num_elem+=H5S_hyper_spans_nelem(b_not_a); + + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* end if */ + break; + + 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") + + /* Update the number of elements in current selection */ + result->select.num_elem=H5S_hyper_spans_nelem(a_not_b); + + /* Indicate that the result owns the a_not_b spans */ + a_not_b=NULL; + + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* end if */ + break; + + 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") + + /* Update the number of elements in current selection */ + result->select.num_elem=H5S_hyper_spans_nelem(b_not_a); + + /* Indicate that the result owns the b_not_a spans */ + b_not_a=NULL; + + /* Indicate that the spans were updated */ + updated_spans = TRUE; + } /* end if */ + break; + + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ + + /* 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); + + /* 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 */ + + /* Sanity check */ + HDassert(result->select.num_elem == 0); + + /* Allocate a span info node */ + if((spans = H5FL_MALLOC(H5S_hyper_span_info_t))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span") + + /* Set the reference count */ + spans->count=1; + + /* Reset the scratch pad space */ + spans->scratch=0; + + /* Set to empty tree */ + spans->head=NULL; + + /* 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 + */ + if(H5S_hyper_rebuild(result) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't rebuild hyperslab info") + } /* end if */ + } /* end else */ + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_operate_hyperslab() */ + + +/*------------------------------------------------------------------------- + * 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[]) +{ + 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 */ + + FUNC_ENTER_NOAPI_NOINIT + + /* 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((new_spans=H5S_hyper_make_spans(space->extent.rank,start,stride,count,block))==NULL) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information") + + /* 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; + + /* Reset the other dataspace selection information */ + if(H5S_SELECT_RELEASE(space)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") + + /* Allocate space for the hyperslab selection information */ + if((space->select.sel_info.hslab=H5FL_MALLOC(H5S_hyper_sel_t))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info") + + /* Set unlim_dim */ + space->select.sel_info.hslab->unlim_dim = -1; + } /* 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() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_select_hyperslab + * + * Purpose: Internal version of H5Sselect_hyperslab(). + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol + * Wednesday, January 10, 2001 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t +H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, + const hsize_t start[], + const hsize_t *stride, + const hsize_t count[], + const hsize_t *block) +{ + hsize_t int_stride[H5O_LAYOUT_NDIMS]; /* Internal storage for stride information */ + hsize_t int_count[H5O_LAYOUT_NDIMS]; /* Internal storage for count information */ + hsize_t int_block[H5O_LAYOUT_NDIMS]; /* 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 */ + + FUNC_ENTER_NOAPI(FAIL) + + /* Check args */ + HDassert(space); + HDassert(start); + HDassert(count); + HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + + /* Point to the correct stride values */ + if(stride==NULL) + stride = _ones; + + /* Point to the correct block values */ + if(block==NULL) + block = _ones; + + /* Check for unlimited dimension */ + for(u = 0; u<space->extent.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 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_CANTDELETE, 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 */ + + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ + } /* end if */ + } /* end for */ + + /* Optimize hyperslab parameters to merge contiguous blocks, etc. */ + if(stride == _ones && block == _ones) { + /* Point to existing arrays */ + opt_stride = _ones; + opt_count = _ones; + 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); + + /* 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 */ + + /* 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" */ + + 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 */ + { + hsize_t tmp_start[H5O_LAYOUT_NDIMS]; /* Temporary start information */ + hsize_t tmp_stride[H5O_LAYOUT_NDIMS]; /* Temporary stride information */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary count information */ + hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block information */ + + /* Fill in temporary information for the dimensions */ + for(u=0; u<space->extent.rank; u++) { + tmp_start[u]=0; + tmp_stride[u]=1; + tmp_count[u]=1; + tmp_block[u]=space->extent.size[u]; + } /* end for */ + + /* 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_CANTDELETE, FAIL, "can't convert selection") + HGOTO_DONE(SUCCEED); + + 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 */ + + default: + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + } /* end switch */ + + + 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") + + /* Allocate space for the hyperslab selection information */ + if(NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info") + + /* Save the diminfo */ + space->select.num_elem=1; + for(u=0; 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]; + + 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]; + + space->select.num_elem*=(opt_count[u]*opt_block[u]); + } /* end for */ + + /* Save unlim_dim */ + space->select.sel_info.hslab->unlim_dim = unlim_dim; + + /* Indicate that the dimension information is valid */ + space->select.sel_info.hslab->diminfo_valid = TRUE; + + /* Indicate that there's no slab information */ + space->select.sel_info.hslab->span_lst = NULL; + + /* 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]); + + /* 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); + + /* 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") + + /* 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") + + /* 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 != _ones)); + HDassert((tmp_block == 1) || (opt_block != _ones)); + if(opt_count != _ones) { + HDassert(opt_count == int_count); + int_count[unlim_dim] = tmp_count; + } /* end if */ + if(opt_block != _ones) { + HDassert(opt_block == int_block); + int_block[unlim_dim] = tmp_block; + } /* end if */ + } /* 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") + + /* Indicate that the regular dimensions are no longer valid */ + space->select.sel_info.hslab->diminfo_valid = FALSE; + + /* Add in the new hyperslab information */ + if(H5S_generate_hyperslab (space, op, start, opt_stride, opt_count, opt_block)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs") + } /* end if */ + else + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + + /* Set selection type */ + space->select.type = H5S_sel_hyper; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_select_hyperslab() */ + + +/*-------------------------------------------------------------------------- + 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 */ + + FUNC_ENTER_API(FAIL) + H5TRACE6("e", "iSs*h*h*h*h", space_id, op, start, stride, count, block); + + /* Check args */ + if (NULL == (space=H5I_object_verify(space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") + if (H5S_SCALAR==H5S_GET_EXTENT_TYPE(space)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_SCALAR space") + if (H5S_NULL==H5S_GET_EXTENT_TYPE(space)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_NULL space") + if(start==NULL || count==NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified") + if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID)) + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation") + if(stride!=NULL) { + unsigned u; /* Local index variable */ + + /* Check for 0-sized strides */ + for(u=0; u<space->extent.rank; u++) { + if(stride[u]==0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "invalid stride==0 value") + } /* end for */ + } /* end if */ + + if (H5S_select_hyperslab(space, op, start, stride, count, block)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Sselect_hyperslab() */ + + +/*-------------------------------------------------------------------------- + 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 = NULL; /* Dataspace to modify selection of */ + H5S_t *new_space = NULL; /* New dataspace created */ + hid_t ret_value; + + FUNC_ENTER_API(FAIL) + H5TRACE6("i", "iSs*h*h*h*h", space_id, op, start, stride, count, block); + + /* Check args */ + if (NULL == (space=H5I_object_verify(space_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data 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") + + /* Copy the first dataspace */ + if (NULL == (new_space = H5S_copy (space, TRUE, TRUE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to copy data space") + + /* 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") + + /* Atomize */ + if ((ret_value=H5I_register (H5I_DATASPACE, new_space, TRUE))<0) + HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom") + +done: + if (ret_value<0 && new_space) + H5S_close(new_space); + + FUNC_LEAVE_API(ret_value) +} /* end H5Scombine_hyperslab() */ + + +/*------------------------------------------------------------------------- + * 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 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +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 */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Check args */ + HDassert(space1); + HDassert(space2); + HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + + /* Check that the space selections both have span trees */ + if(space1->select.sel_info.hslab->span_lst==NULL) + if(H5S_hyper_generate_spans(space1)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, NULL, "dataspace does not have span tree") + if(space2->select.sel_info.hslab->span_lst==NULL) + if(H5S_hyper_generate_spans(space2)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, NULL, "dataspace does not have span tree") + + /* Copy the first dataspace */ + if (NULL == (new_space = H5S_copy (space1, TRUE, TRUE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to copy data space") + + /* 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 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") + + /* Set unlim_dim */ + new_space->select.sel_info.hslab->unlim_dim = -1; + + /* 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") + + /* Set return value */ + ret_value=new_space; + +done: + if(ret_value==NULL && new_space!=NULL) + H5S_close(new_space); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_combine_select() */ + + +/*-------------------------------------------------------------------------- + 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; + + FUNC_ENTER_API(FAIL) + H5TRACE3("i", "iSsi", space1_id, op, space2_id); + + /* Check args */ + if (NULL == (space1=H5I_object_verify(space1_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") + if (NULL == (space2=H5I_object_verify(space2_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") + if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID)) + 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") + + /* 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") + + /* Go combine the dataspaces */ + if ((new_space=H5S_combine_select(space1, op, space2))==NULL) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to create hyperslab selection") + + /* Atomize */ + if ((ret_value=H5I_register (H5I_DATASPACE, new_space, TRUE))<0) + HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom") + +done: + if (ret_value<0 && new_space) + H5S_close(new_space); + + FUNC_LEAVE_API(ret_value) +} /* end H5Scombine_select() */ + + +/*------------------------------------------------------------------------- + * 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 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +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 */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Check args */ + HDassert(space1); + HDassert(space2); + HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID); + + /* Check that the space selections both have span trees */ + if(space1->select.sel_info.hslab->span_lst==NULL) + if(H5S_hyper_generate_spans(space1)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") + if(space2->select.sel_info.hslab->span_lst==NULL) + if(H5S_hyper_generate_spans(space2)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") + + /* Take ownership of the dataspace's hyperslab spans */ + /* (These are freed later) */ + tmp_spans=space1->select.sel_info.hslab->span_lst; + space1->select.sel_info.hslab->span_lst=NULL; + + /* Reset the other dataspace selection information */ + if(H5S_SELECT_RELEASE(space1)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") + + /* Allocate space for the hyperslab selection information */ + if((space1->select.sel_info.hslab=H5FL_CALLOC(H5S_hyper_sel_t))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info") + + /* Set unlim_dim */ + space1->select.sel_info.hslab->unlim_dim = -1; + + /* 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") + +done: + if(tmp_spans!=NULL) + H5S_hyper_free_span_info(tmp_spans); + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_select_select() */ + + +/*-------------------------------------------------------------------------- + NAME + H5Sselect_select + PURPOSE + Refine a hyperslab selection with an operation using a second hyperslab + to modify it. + USAGE + herr_t H5Sselect_select(space1, op, space2) + hid_t space1; IN/OUT: First Dataspace ID + H5S_seloper_t op; IN: Selection operation + hid_t space2; IN: Second Dataspace ID + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Refine an existing hyperslab selection with an operation, using a second + hyperslab. The first selection is modified to contain the result of + space1 operated on by space2. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5Sselect_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id) +{ + H5S_t *space1; /* First Dataspace */ + H5S_t *space2; /* Second Dataspace */ + herr_t ret_value=SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE3("e", "iSsi", space1_id, op, space2_id); + + /* Check args */ + if (NULL == (space1=H5I_object_verify(space1_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") + if (NULL == (space2=H5I_object_verify(space2_id, H5I_DATASPACE))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space") + if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID)) + 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") + + /* 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") + + /* 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") + +done: + FUNC_LEAVE_API(ret_value) +} /* end H5Sselect_select() */ +#endif /* NEW_HYPERSLAB_API */ /* Works */ + + +/*-------------------------------------------------------------------------- + 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[H5O_LAYOUT_NDIMS]; /* 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_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(space); + HDassert(iter); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); + + /* Set the rank of the fastest changing dimension */ + ndims = space->extent.rank; + fast_dim = (ndims - 1); + + /* Get the pointers to the current span info and span nodes */ + curr_span = iter->u.hyp.span[fast_dim]; + abs_arr = iter->u.hyp.off; + off_arr = space->select.offset; + ispan = iter->u.hyp.span; + elem_size = iter->elmt_size; + + /* 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; + + /* 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 */ + + /* Set the offset of the first element iterated on */ + for(u = 0, loc_off = 0; u < ndims; u++) + /* Compute the sequential element offset */ + loc_off += ((hsize_t)((hssize_t)abs_arr[u] + off_arr[u])) * slab[u]; + + /* Range check against number of elements left in selection */ + HDassert(io_bytes_left <= (iter->elmt_left * elem_size)); + + /* Take care of any partial spans leftover from previous I/Os */ + if(abs_arr[fast_dim]!=curr_span->low) { + + /* Finish the span in the fastest changing dimension */ + + /* 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); + + /* Check number of bytes against upper bounds allowed */ + if(span_size>io_bytes_left) + span_size=io_bytes_left; + + /* Add the partial span to the list of sequences */ + off[curr_seq]=loc_off; + len[curr_seq]=span_size; + + /* Increment sequence count */ + curr_seq++; + + /* Set the location of the last span's end */ + last_span_end=loc_off+span_size; + + /* Decrement I/O left to perform */ + io_bytes_left-=span_size; + + /* 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; + + if(NULL != curr_span) { + /* Move location offset of destination */ + loc_off += (curr_span->low - abs_arr[fast_dim]) * elem_size; + + /* Move iterator for fastest changing dimension */ + abs_arr[fast_dim] = curr_span->low; + } /* end if */ + } /* end if */ + else { + abs_arr[fast_dim] += span_size / elem_size; + + /* Check if we are still within the span */ + if(abs_arr[fast_dim] <= curr_span->high) { + iter->u.hyp.span[fast_dim] = curr_span; + } /* end if */ + /* If we walked off that span, advance to the next span */ + else { + /* Advance span in this dimension */ + curr_span = curr_span->next; + + /* Check if we have a valid span in this dimension still */ + if(NULL != curr_span) { + /* Reset absolute position */ + abs_arr[fast_dim] = curr_span->low; + iter->u.hyp.span[fast_dim] = curr_span; + } /* end if */ + } /* end else */ + } /* end else */ + + /* Adjust iterator pointers */ + + if(NULL == curr_span) { +/* Same as code in main loop */ + /* 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(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; + } /* 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 */ + + /* Check if we have more spans in the tree */ + if(curr_dim >= 0) { + /* Walk back down the iterator positions, reseting them */ + while((unsigned)curr_dim < fast_dim) { + HDassert(curr_span); + HDassert(curr_span->down); + HDassert(curr_span->down->head); + + /* Increment current dimension */ + curr_dim++; + + /* Set the new span_info & span for this dimension */ + iter->u.hyp.span[curr_dim] = curr_span->down->head; + + /* Advance span down the tree */ + curr_span = curr_span->down->head; + + /* Reset the absolute offset for the dim */ + abs_arr[curr_dim] = curr_span->low; + } /* end while */ + + /* Verify that the curr_span points to the fastest dim */ + HDassert(curr_span == iter->u.hyp.span[fast_dim]); + + /* 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 */ + + /* 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); + + /* Adjust location offset of destination to compensate for initial increment below */ + loc_off -= curr_span->pstride; + + /* Loop over all the spans in the fastest changing dimension */ + while(curr_span != NULL) { + /* Move location offset of destination */ + loc_off += curr_span->pstride; + + /* Compute the number of elements to attempt in this span */ + H5_CHECKED_ASSIGN(span_size, size_t, curr_span->nelem, hsize_t); + + /* 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; + +/* COMMON */ + /* Store the I/O information for the 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; + + /* Increment the number of sequences in arrays */ + curr_seq++; + } /* end else */ + + /* Set the location of the last span's end */ + last_span_end = loc_off + span_size; +/* end COMMON */ + + /* Break out now, we are finished with I/O */ + break; + } /* end if */ + else { + /* Decrement I/O left to perform */ + io_bytes_left -= span_size; + +/* COMMON */ + /* Store the I/O information for the 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; + + /* Increment the number of sequences in arrays */ + curr_seq++; + } /* end else */ + + /* Set the location of the last span's end */ + last_span_end = loc_off + span_size; +/* end COMMON */ + + /* 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 */ + + /* Move to next span in fastest changing dimension */ + curr_span=curr_span->next; + } /* end while */ + + /* 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; + + /* 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 */ + + /* 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; + + 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 */ + + /* 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, reseting them */ + while((unsigned)curr_dim < fast_dim) { + HDassert(curr_span); + HDassert(curr_span->down); + HDassert(curr_span->down->head); + + /* Increment current dimension to the next dimension down */ + curr_dim++; + + /* Set the new span for the next dimension down */ + iter->u.hyp.span[curr_dim] = curr_span->down->head; + + /* Advance span down the tree */ + curr_span = curr_span->down->head; + + /* Reset the absolute offset for the dim */ + abs_arr[curr_dim] = curr_span->low; + } /* end while */ + + /* Verify that the curr_span points to the fastest dim */ + HDassert(curr_span == iter->u.hyp.span[fast_dim]); + } /* end else */ + + /* Reset the buffer offset */ + for(u = 0, loc_off = 0; u < ndims; u++) + loc_off += ((hsize_t)((hssize_t)abs_arr[u] + off_arr[u])) * slab[u]; + } /* end while */ + + /* Decrement number of elements left in iterator */ + io_used = (io_left - (io_bytes_left / elem_size)); + iter->elmt_left -= io_used; + + /* Set the number of sequences generated */ + *nseq = curr_seq; + + /* Set the number of elements used */ + *nelem = io_used; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S_hyper_get_seq_list_gen() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_get_seq_list_opt + PURPOSE + Create a list of offsets & lengths for a selection + USAGE + herr_t H5S_select_hyper_get_file_list_opt(space,iter,maxseq,maxelem,nseq,nelem,off,len) + H5S_t *space; IN: Dataspace containing selection to use. + H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last + position of interest in selection. + size_t maxseq; IN: Maximum number of sequences to generate + size_t maxelem; IN: Maximum number of elements to include in the + generated sequences + size_t *nseq; OUT: Actual number of sequences generated + size_t *nelem; OUT: Actual number of elements in sequences generated + hsize_t *off; OUT: Array of offsets + size_t *len; OUT: Array of lengths + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + Use the selection in the dataspace to generate a list of byte offsets and + lengths for the region(s) selected. Start/Restart from the position in the + ITER parameter. The number of sequences generated is limited by the MAXSEQ + parameter and the number of sequences actually generated is stored in the + NSEQ parameter. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_hyper_get_seq_list_opt(const H5S_t *space, H5S_sel_iter_t *iter, + size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem, + hsize_t *off, size_t *len) +{ + hsize_t *mem_size; /* Size of the source buffer */ + hsize_t slab[H5O_LAYOUT_NDIMS]; /* Hyperslab size */ + const hssize_t *sel_off; /* Selection offset in dataspace */ + hsize_t offset[H5O_LAYOUT_NDIMS]; /* Coordinate offset in dataspace */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS];/* Temporary block count */ + hsize_t tmp_block[H5O_LAYOUT_NDIMS];/* Temporary block offset */ + hsize_t wrap[H5O_LAYOUT_NDIMS]; /* Bytes to wrap around at the end of a row */ + hsize_t skip[H5O_LAYOUT_NDIMS]; /* 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 */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(space); + HDassert(iter); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); + + /* Set the 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; + fast_dim = ndims - 1; + + /* 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; + fast_dim = ndims - 1; + + /* 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 */ + + /* 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 */ + + /* 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); + + /* 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))); + + /* 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. + */ + + /* Keep the number of elements we started with */ + start_io_left = io_left; + + /* Compute the arrays to perform I/O on */ + + /* Copy the location of the point to get */ + /* (Add in the selection offset) */ + for(u = 0; u < ndims; u++) + offset[u] = (hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u]); + + /* Compute the current "counts" for this location */ + for(u = 0; u < ndims; u++) { + if(tdiminfo[u].count == 1) { + tmp_count[u] = 0; + tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start; + } /* end if */ + else { + 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 */ + + /* Compute the initial buffer offset */ + for(u = 0, loc = 0; u < ndims; u++) + loc += offset[u] * slab[u]; + + /* Set the number of elements to write each time */ + H5_CHECKED_ASSIGN(actual_elem, size_t, tdiminfo[fast_dim].block, hsize_t); + + /* Set the number of actual bytes */ + actual_bytes = actual_elem * elem_size; + + /* 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]); + + /* Compute the number of blocks which would fit into the buffer */ + H5_CHECK_OVERFLOW(io_left / fast_dim_block, hsize_t, size_t); + tot_blk_count = (size_t)(io_left / fast_dim_block); + + /* Don't go over the maximum number of sequences allowed */ + tot_blk_count = MIN(tot_blk_count, (maxseq - curr_seq)); + + /* 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]; + + /* Compute the amount to skip between blocks */ + for(u = 0; u < ndims; u++) + skip[u] = (tdiminfo[u].stride - tdiminfo[u].block) * slab[u]; + + /* 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); + + /* Make certain this entire row will fit into buffer */ + fast_dim_count = MIN(fast_dim_count, tot_blk_count); + + /* Number of blocks to sequence over */ + act_blk_count = fast_dim_count; + + /* Loop over all the blocks in the fastest changing dimension */ + while(fast_dim_count > 0) { + /* Store the sequence information */ + off[curr_seq] = loc; + len[curr_seq] = actual_bytes; + + /* Increment sequence count */ + curr_seq++; + + /* Increment information to reflect block just processed */ + loc += fast_dim_buf_off; + + /* Decrement number of blocks */ + fast_dim_count--; + } /* end while */ + + /* Decrement number of elements left */ + io_left -= actual_elem * act_blk_count; + + /* Decrement number of blocks left */ + tot_blk_count -= act_blk_count; + + /* Increment information to reflect block just processed */ + tmp_count[fast_dim] += act_blk_count; + + /* Check if we finished the entire row of blocks */ + if(tmp_count[fast_dim] >= tdiminfo[fast_dim].count) { + /* Increment offset in destination buffer */ + loc += wrap[fast_dim]; + + /* Increment information to reflect block just processed */ + offset[fast_dim] = fast_dim_offset; /* reset the offset in the fastest dimension */ + tmp_count[fast_dim] = 0; + + /* Increment the offset and count for the other dimensions */ + temp_dim = (int)fast_dim - 1; + while(temp_dim >= 0) { + /* Move to the next row in the curent dimension */ + offset[temp_dim]++; + tmp_block[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_block[temp_dim] < tdiminfo[temp_dim].block) + break; + else { + /* Move to the next block in the current dimension */ + offset[temp_dim] += (tdiminfo[temp_dim].stride - tdiminfo[temp_dim].block); + loc += skip[temp_dim]; + tmp_block[temp_dim] = 0; + tmp_count[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_count[temp_dim] < tdiminfo[temp_dim].count) + break; + else { + offset[temp_dim] = (hsize_t)((hssize_t)tdiminfo[temp_dim].start + sel_off[temp_dim]); + loc += wrap[temp_dim]; + tmp_count[temp_dim] = 0; /* reset back to the beginning of the line */ + tmp_block[temp_dim] = 0; + } /* end else */ + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + } /* end if */ + else { + /* Update the offset in the fastest dimension */ + offset[fast_dim] += (fast_dim_stride * act_blk_count); + } /* end else */ + } /* end if */ + + /* Compute the number of entire rows to read in */ + H5_CHECK_OVERFLOW(tot_blk_count / tdiminfo[fast_dim].count, hsize_t, size_t); + curr_rows = total_rows = (size_t)(tot_blk_count / tdiminfo[fast_dim].count); + + /* Reset copy of number of blocks in fastest dimension */ + H5_CHECKED_ASSIGN(fast_dim_count, size_t, tdiminfo[fast_dim].count, hsize_t); + + /* Read in data until an entire sequence can't be written out any longer */ + while(curr_rows > 0) { + +#define DUFF_GUTS \ +/* Store the sequence information */ \ +off[curr_seq] = loc; \ +len[curr_seq] = actual_bytes; \ + \ +/* Increment sequence count */ \ +curr_seq++; \ + \ +/* Increment information to reflect block just processed */ \ +loc += fast_dim_buf_off; + +#ifdef NO_DUFFS_DEVICE + /* Loop over all the blocks in the fastest changing dimension */ + while(fast_dim_count > 0) { + DUFF_GUTS + + /* Decrement number of blocks */ + fast_dim_count--; + } /* end while */ +#else /* NO_DUFFS_DEVICE */ + { + size_t duffs_index; /* Counting index for Duff's device */ + + duffs_index = (fast_dim_count + 7) / 8; + switch (fast_dim_count % 8) { + default: + HDassert(0 && "This Should never be executed!"); + break; + case 0: + do + { + DUFF_GUTS + 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 + + /* Increment offset in destination buffer */ + loc += wrap[fast_dim]; + + /* Increment the offset and count for the other dimensions */ + temp_dim = (int)fast_dim - 1; + while(temp_dim >= 0) { + /* Move to the next row in the curent dimension */ + offset[temp_dim]++; + tmp_block[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_block[temp_dim] < tdiminfo[temp_dim].block) + break; + else { + /* Move to the next block in the current dimension */ + offset[temp_dim] += (tdiminfo[temp_dim].stride - tdiminfo[temp_dim].block); + loc += skip[temp_dim]; + tmp_block[temp_dim] = 0; + tmp_count[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_count[temp_dim] < tdiminfo[temp_dim].count) + break; + else { + offset[temp_dim] = (hsize_t)((hssize_t)tdiminfo[temp_dim].start + sel_off[temp_dim]); + loc += wrap[temp_dim]; + tmp_count[temp_dim] = 0; /* reset back to the beginning of the line */ + tmp_block[temp_dim] = 0; + } /* end else */ + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + + /* Decrement the number of rows left */ + curr_rows--; + } /* end while */ + + /* Adjust the number of blocks & elements left to transfer */ + + /* Decrement number of elements left */ + H5_CHECK_OVERFLOW(actual_elem * (total_rows * tdiminfo[fast_dim].count), hsize_t, size_t); + io_left -= (size_t)(actual_elem * (total_rows * tdiminfo[fast_dim].count)); + + /* Decrement number of blocks left */ + H5_CHECK_OVERFLOW((total_rows * tdiminfo[fast_dim].count), hsize_t, size_t); + tot_blk_count -= (size_t)(total_rows * tdiminfo[fast_dim].count); + + /* Read in partial row of blocks */ + if(io_left > 0 && curr_seq < maxseq) { + /* Get remaining number of blocks left to output */ + fast_dim_count = tot_blk_count; + + /* Loop over all the blocks in the fastest changing dimension */ + while(fast_dim_count > 0) { + /* Store the sequence information */ + off[curr_seq] = loc; + len[curr_seq] = actual_bytes; + + /* Increment sequence count */ + curr_seq++; + + /* Increment information to reflect block just processed */ + loc += fast_dim_buf_off; + + /* Decrement number of blocks */ + fast_dim_count--; + } /* end while */ + + /* Decrement number of elements left */ + io_left -= actual_elem * tot_blk_count; + + /* Increment information to reflect block just processed */ + offset[fast_dim] += (fast_dim_stride * tot_blk_count); /* move the offset in the fastest dimension */ + + /* Handle any leftover, partial blocks in this row */ + if(io_left > 0 && curr_seq < maxseq) { + actual_elem = io_left; + actual_bytes = actual_elem * elem_size; + + /* Store the sequence information */ + off[curr_seq] = loc; + len[curr_seq] = actual_bytes; + + /* Increment sequence count */ + curr_seq++; + + /* Decrement the number of elements left */ + io_left -= actual_elem; + + /* Increment buffer correctly */ + offset[fast_dim] += actual_elem; + } /* end if */ + + /* don't bother checking slower dimensions */ + HDassert(io_left == 0 || curr_seq == maxseq); + } /* end if */ + + /* Update the iterator */ + + /* Update the iterator with the location we stopped */ + /* (Subtract out the selection offset) */ + for(u = 0; u < ndims; u++) + iter->u.hyp.off[u] = (hsize_t)((hssize_t)offset[u] - sel_off[u]); + + /* Decrement the number of elements left in selection */ + iter->elmt_left -= (start_io_left - io_left); + + /* Increment the number of sequences generated */ + *nseq += curr_seq; + + /* Increment the number of elements used */ + *nelem += start_io_left - io_left; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S_hyper_get_seq_list_opt() */ + + +/*-------------------------------------------------------------------------- + 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) +{ + 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[H5O_LAYOUT_NDIMS]; /* Base coordinate offset in dataspace */ + hsize_t offset[H5O_LAYOUT_NDIMS]; /* Coordinate offset in dataspace */ + hsize_t slab[H5O_LAYOUT_NDIMS]; /* 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_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(space); + HDassert(iter); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); + + /* Set a local copy of the diminfo pointer */ + tdiminfo = iter->u.hyp.diminfo; + + /* Check if this is a "flattened" regular hyperslab selection */ + if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < space->extent.rank) { + /* Set the aliases for a few important dimension ranks */ + ndims = iter->u.hyp.iter_rank; + + /* Set the local copy of the selection offset */ + sel_off = iter->u.hyp.sel_off; + + /* Set up the pointer to the size of the memory space */ + mem_size = iter->u.hyp.size; + } /* end if */ + else { + /* Set the aliases for a few important dimension ranks */ + ndims = space->extent.rank; + + /* Set the local copy of the selection offset */ + sel_off = space->select.offset; + + /* Set up the pointer to the size of the memory space */ + mem_size = space->extent.size; + } /* end else */ + fast_dim = ndims - 1; + + /* 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 the base location of the block */ + /* (Add in the selection offset) */ + for(u = 0; u < ndims; u++) + base_offset[u] = (hsize_t)((hssize_t)tdiminfo[u].start + sel_off[u]); + + /* Copy the location of the point to get */ + /* (Add in the selection offset) */ + for(u = 0; u < ndims; u++) + offset[u] = (hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u]); + + /* Compute the initial buffer offset */ + for(u = 0, loc = 0; u < ndims; u++) + loc += offset[u] * slab[u]; + + /* Set local copies of information for the fastest changing dimension */ + fast_dim_block = tdiminfo[fast_dim].block; + + /* Calculate the number of elements to sequence through */ + H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t); + io_left = MIN((size_t)iter->elmt_left, maxelem); + + /* Compute the number of blocks which would fit into the buffer */ + H5_CHECK_OVERFLOW(io_left / fast_dim_block, hsize_t, size_t); + tot_blk_count = (size_t)(io_left / fast_dim_block); + + /* Don't go over the maximum number of sequences allowed */ + tot_blk_count = MIN(tot_blk_count, maxseq); + + /* Set the number of elements to write each time */ + H5_CHECKED_ASSIGN(actual_elem, size_t, fast_dim_block, hsize_t); + + /* Check for blocks to operate on */ + if(tot_blk_count > 0) { + size_t actual_bytes; /* The actual number of bytes to copy */ + + /* Set the number of actual bytes */ + actual_bytes = actual_elem * elem_size; + + /* Check for 1-dim selection */ + if(0 == fast_dim) { + /* Sanity checks */ + HDassert(1 == tot_blk_count); + HDassert(io_left == actual_elem); + + /* Store the sequence information */ + *off++ = loc; + *len++ = actual_bytes; + } /* end if */ + else { + hsize_t skip_slab; /* Temporary copy of slab[fast_dim - 1] */ + size_t blk_count; /* Total number of blocks left to output */ + + /* Find first dimension w/block >1 */ + skip_dim = fast_dim; + for(i = (int)(fast_dim - 1); i >= 0; i--) + if(tdiminfo[i].block > 1) { + skip_dim = (unsigned)i; + break; + } /* end if */ + skip_slab = slab[skip_dim]; + + /* Check for being able to use fast algorithm for 1-D */ + if(0 == skip_dim) { + /* Create sequences until an entire row can't be used */ + blk_count = tot_blk_count; + while(blk_count > 0) { + /* Store the sequence information */ + *off++ = loc; + *len++ = actual_bytes; + + /* Increment offset in destination buffer */ + loc += skip_slab; + + /* Decrement block count */ + blk_count--; + } /* end while */ + + /* Move to the next location */ + offset[skip_dim] += tot_blk_count; + } /* end if */ + else { + hsize_t tmp_block[H5O_LAYOUT_NDIMS];/* Temporary block offset */ + hsize_t skip[H5O_LAYOUT_NDIMS]; /* Bytes to skip between blocks */ + int temp_dim; /* Temporary rank holder */ + + /* Set the starting block location */ + for(u = 0; u < ndims; u++) + tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start; + + /* Compute the amount to skip between sequences */ + for(u = 0; u < ndims; u++) + skip[u] = (mem_size[u] - tdiminfo[u].block) * slab[u]; + + /* Create sequences until an entire row can't be used */ + blk_count = tot_blk_count; + while(blk_count > 0) { + /* Store the sequence information */ + *off++ = loc; + *len++ = actual_bytes; + + /* Set temporary dimension for advancing offsets */ + temp_dim = (int)skip_dim; + + /* Increment offset in destination buffer */ + loc += skip_slab; + + /* Increment the offset and count for the other dimensions */ + while(temp_dim >= 0) { + /* Move to the next row in the curent dimension */ + offset[temp_dim]++; + tmp_block[temp_dim]++; + + /* If this block is still in the range of blocks to output for the dimension, break out of loop */ + if(tmp_block[temp_dim] < tdiminfo[temp_dim].block) + break; + else { + offset[temp_dim] = base_offset[temp_dim]; + loc += skip[temp_dim]; + tmp_block[temp_dim] = 0; + } /* end else */ + + /* Decrement dimension count */ + temp_dim--; + } /* end while */ + + /* Decrement block count */ + blk_count--; + } /* end while */ + } /* end else */ + } /* end else */ + + /* Update the iterator, if there were any blocks used */ + + /* Decrement the number of elements left in selection */ + iter->elmt_left -= tot_blk_count * actual_elem; + + /* Check if there are elements left in iterator */ + if(iter->elmt_left > 0) { + /* Update the iterator with the location we stopped */ + /* (Subtract out the selection offset) */ + for(u = 0; u < ndims; u++) + iter->u.hyp.off[u] = (hsize_t)((hssize_t)offset[u] - sel_off[u]); + } /* end if */ + + /* Increment the number of sequences generated */ + *nseq += tot_blk_count; + + /* Increment the number of elements used */ + *nelem += tot_blk_count * actual_elem; + } /* end if */ + + /* Check for partial block, with room for another sequence */ + if(io_left > (tot_blk_count * actual_elem) && tot_blk_count < maxseq) { + size_t elmt_remainder; /* Elements remaining */ + + /* Compute elements left */ + elmt_remainder = io_left - (tot_blk_count * actual_elem); + HDassert(elmt_remainder < fast_dim_block); + HDassert(elmt_remainder > 0); + + /* Store the sequence information */ + *off++ = loc; + *len++ = elmt_remainder * elem_size; + + /* Update the iterator with the location we stopped */ + iter->u.hyp.off[fast_dim] += (hsize_t)elmt_remainder; + + /* Decrement the number of elements left in selection */ + iter->elmt_left -= elmt_remainder; + + /* Increment the number of sequences generated */ + (*nseq)++; + + /* Increment the number of elements used */ + *nelem += elmt_remainder; + } /* end if */ + + /* Sanity check */ + HDassert(*nseq > 0); + HDassert(*nelem > 0); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* end H5S_hyper_get_seq_list_single() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_get_seq_list + PURPOSE + Create a list of offsets & lengths for a 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 + 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(const H5S_t *space, unsigned H5_ATTR_UNUSED flags, H5S_sel_iter_t *iter, + size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem, + hsize_t *off, size_t *len) +{ + herr_t ret_value = FAIL; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* 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 */ + 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[H5O_LAYOUT_NDIMS]; /* 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); + } /* 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() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_project_intersection + PURPOSE + Projects the intersection of of the selections of src_space and + src_intersect_space within the selection of src_space as a selection + within the selection of dst_space + USAGE + herr_t H5S__hyper_project_intersection(src_space,dst_space,src_intersect_space,proj_space) + H5S_t *src_space; IN: Selection that is mapped to dst_space, and intersected with src_intersect_space + H5S_t *dst_space; IN: Selection that is mapped to src_space, and which contains the result + H5S_t *src_intersect_space; IN: Selection whose intersection with src_space is projected to dst_space to obtain the result + H5S_t *proj_space; OUT: Will contain the result (intersection of src_intersect_space and src_space projected from src_space to dst_space) after the operation + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + Projects the intersection of of the selections of src_space and + src_intersect_space within the selection of src_space as a selection + within the selection of dst_space. The result is placed in the + selection of proj_space. Note src_space, dst_space, and + src_intersect_space do not need to use hyperslab selections, but they + cannot use point selections. The result is always a hyperslab + selection. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +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) +{ + hsize_t ss_off[H5S_PROJECT_INTERSECT_NSEQS]; /* Offset array for src_space */ + size_t ss_len[H5S_PROJECT_INTERSECT_NSEQS]; /* Length array for src_space */ + size_t ss_nseq; /* Number of sequences for src_space */ + size_t ss_nelem; /* Number of elements for src_space */ + size_t ss_i = (size_t)0; /* Index into offset/length arrays for src_space */ + hbool_t advance_ss = FALSE; /* Whether to advance ss_i on the next iteration */ + H5S_sel_iter_t *ss_iter = NULL; /* Selection iterator for src_space */ + hbool_t ss_iter_init = FALSE; /* Whether ss_iter is initialized */ + hsize_t ss_sel_off = (hsize_t)0; /* Offset within src_space selection */ + hsize_t ds_off[H5S_PROJECT_INTERSECT_NSEQS]; /* Offset array for dst_space */ + size_t ds_len[H5S_PROJECT_INTERSECT_NSEQS]; /* Length array for dst_space */ + size_t ds_nseq; /* Number of sequences for dst_space */ + size_t ds_nelem; /* Number of elements for dst_space */ + size_t ds_i = (size_t)0; /* Index into offset/length arrays for dst_space */ + H5S_sel_iter_t *ds_iter = NULL; /* Selection iterator for dst_space */ + hbool_t ds_iter_init = FALSE; /* Whether ds_iter is initialized */ + hsize_t ds_sel_off = (hsize_t)0; /* Offset within dst_space selection */ + hsize_t sis_off[H5S_PROJECT_INTERSECT_NSEQS]; /* Offset array for src_intersect_space */ + size_t sis_len[H5S_PROJECT_INTERSECT_NSEQS]; /* Length array for src_intersect_space */ + size_t sis_nseq; /* Number of sequences for src_intersect_space */ + size_t sis_nelem; /* Number of elements for src_intersect_space */ + size_t sis_i = (size_t)0; /* Index into offset/length arrays for src_intersect_space */ + hbool_t advance_sis = FALSE; /* Whether to advance sis_i on the next iteration */ + H5S_sel_iter_t *sis_iter = NULL; /* Selection iterator for src_intersect_space */ + hbool_t sis_iter_init = FALSE; /* Whether sis_iter is initialized */ + hsize_t int_sel_off; /* Offset within intersected selections (ss/sis and ds/ps) */ + size_t int_len; /* Length of segment in intersected selections */ + hsize_t proj_off; /* Segment offset in proj_space */ + size_t proj_len; /* Segment length in proj_space */ + size_t proj_len_rem; /* Remaining length in proj_space for segment */ + hsize_t proj_down_dims[H5S_MAX_RANK]; /* "Down" dimensions in proj_space */ + H5S_hyper_span_info_t *curr_span_tree[H5S_MAX_RANK]; /* Current span tree being built (in each dimension) */ + H5S_hyper_span_t *prev_span[H5S_MAX_RANK]; /* Previous span in tree (in each dimension) */ + hsize_t curr_span_up_dim[H5S_MAX_RANK]; /* "Up" dimensions for current span */ + unsigned proj_rank; /* Rank of proj_space */ + hsize_t low; /* Low value of span */ + hsize_t high; /* High value of span */ + size_t span_len; /* Length of span */ + size_t nelem; /* Number of elements returned for get_seq_list op */ + unsigned i; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_PACKAGE + + /* Check parameters */ + HDassert(src_space); + HDassert(dst_space); + HDassert(src_intersect_space); + HDassert(proj_space); + + /* Assert that src_space and src_intersect_space have same extent and there + * are no point selections */ + HDassert(H5S_GET_EXTENT_NDIMS(src_space) + == H5S_GET_EXTENT_NDIMS(src_intersect_space)); + HDassert(!HDmemcmp(src_space->extent.size, src_intersect_space->extent.size, + (size_t)H5S_GET_EXTENT_NDIMS(src_space) + * sizeof(src_space->extent.size[0]))); + HDassert(H5S_GET_SELECT_TYPE(src_space) != H5S_SEL_POINTS); + HDassert(H5S_GET_SELECT_TYPE(dst_space) != H5S_SEL_POINTS); + HDassert(H5S_GET_SELECT_TYPE(src_intersect_space) != H5S_SEL_POINTS); + + /* Initialize prev_space, curr_span_tree, and curr_span_up_dim */ + for(i = 0; i < H5S_MAX_RANK; i++) { + curr_span_tree[i] = NULL; + prev_span[i] = NULL; + curr_span_up_dim[i] = (hsize_t)0; + } /* end for */ + + /* Save rank of projected space */ + proj_rank = proj_space->extent.rank; + HDassert(proj_rank > 0); + + /* Get numbers of elements */ + ss_nelem = (size_t)H5S_GET_SELECT_NPOINTS(src_space); + ds_nelem = (size_t)H5S_GET_SELECT_NPOINTS(dst_space); + sis_nelem = (size_t)H5S_GET_SELECT_NPOINTS(src_intersect_space); + HDassert(ss_nelem == ds_nelem); + + /* Calculate proj_down_dims (note loop relies on unsigned i wrapping around) + */ + if(H5VM_array_down(proj_rank, proj_space->extent.size, proj_down_dims) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't compute 'down' chunk size value") + + /* Remove current selection from proj_space */ + if(H5S_SELECT_RELEASE(proj_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") + + /* If any selections are empty, skip to the end so "none" is selected */ + if((ss_nelem == 0) || (ds_nelem == 0) || (sis_nelem == 0)) + goto loop_end; + + /* Allocate space for the hyperslab selection information (note this sets + * diminfo_valid to FALSE, diminfo arrays to 0, and span list to NULL) */ + if((proj_space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info") + + /* Set selection type */ + proj_space->select.type = H5S_sel_hyper; + + /* Set unlim_dim */ + proj_space->select.sel_info.hslab->unlim_dim = -1; + + /* Allocate the source space iterator */ + if(NULL == (ss_iter = H5FL_MALLOC(H5S_sel_iter_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate source space iterator") + + /* Initialize source space iterator */ + if(H5S_select_iter_init(ss_iter, src_space, (size_t)1) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") + ss_iter_init = TRUE; + + /* Get sequence list for source space */ + if(H5S_SELECT_GET_SEQ_LIST(src_space, 0u, ss_iter, H5S_PROJECT_INTERSECT_NSEQS, ss_nelem, &ss_nseq, &nelem, ss_off, ss_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + ss_nelem -= nelem; + HDassert(ss_nseq > 0); + + /* Allocate the destination space iterator */ + if(NULL == (ds_iter = H5FL_MALLOC(H5S_sel_iter_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate destination space iterator") + + /* Initialize destination space iterator */ + if(H5S_select_iter_init(ds_iter, dst_space, (size_t)1) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") + ds_iter_init = TRUE; + + /* Get sequence list for destination space */ + if(H5S_SELECT_GET_SEQ_LIST(dst_space, 0u, ds_iter, H5S_PROJECT_INTERSECT_NSEQS, ds_nelem, &ds_nseq, &nelem, ds_off, ds_len) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") + ds_nelem -= nelem; + HDassert(ds_nseq > 0); + + /* Allocate the source intersect space iterator */ + if(NULL == (sis_iter = H5FL_MALLOC(H5S_sel_iter_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate source intersect space iterator") + + /* Initialize source intersect space iterator */ + if(H5S_select_iter_init(sis_iter, src_intersect_space, (size_t)1) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator") + sis_iter_init = TRUE; + + /* Get sequence list for source intersect space */ + if(H5S_SELECT_GET_SEQ_LIST(src_intersect_space, 0u, sis_iter, H5S_PROJECT_INTERSECT_NSEQS, sis_nelem, &sis_nseq, &nelem, sis_off, sis_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + sis_nelem -= nelem; + HDassert(sis_nseq > 0); + + /* Loop until we run out of sequences in either the source or source + * intersect space */ + while(1) { + while(advance_ss || (ss_off[ss_i] + ss_len[ss_i] <= sis_off[sis_i])) { + /* Either we finished the current source sequence or the + * sequences do not intersect. Advance source space. */ + ss_sel_off += (hsize_t)ss_len[ss_i]; + if(++ss_i == ss_nseq) { + if(ss_nelem > 0) { + /* Try to grab more sequences from src_space */ + if(H5S_SELECT_GET_SEQ_LIST(src_space, 0u, ss_iter, H5S_PROJECT_INTERSECT_NSEQS, ss_nelem, &ss_nseq, &nelem, ss_off, ss_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + HDassert(ss_len[0] > 0); + + /* Update ss_nelem */ + HDassert(nelem > 0); + HDassert(nelem <= ss_nelem); + ss_nelem -= nelem; + + /* Reset source space index */ + ss_i = 0; + } /* end if */ + else + /* There are no more sequences in src_space, so we can exit + * the loop. Use goto instead of break so we exit the outer + * loop. */ + goto loop_end; + } /* end if */ + + /* Reset advance_ss */ + advance_ss = FALSE; + } /* end if */ + if(advance_sis + || (sis_off[sis_i] + sis_len[sis_i] <= ss_off[ss_i])) { + do { + /* Either we finished the current source intersect sequence or + * the sequences do not intersect. Advance source intersect + * space. */ + if(++sis_i == sis_nseq) { + if(sis_nelem > 0) { + /* Try to grab more sequences from src_intersect_space + */ + if(H5S_SELECT_GET_SEQ_LIST(src_intersect_space, 0u, sis_iter, H5S_PROJECT_INTERSECT_NSEQS, sis_nelem, &sis_nseq, &nelem, sis_off, sis_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + HDassert(sis_len[0] > 0); + + /* Update ss_nelem */ + HDassert(nelem > 0); + HDassert(nelem <= sis_nelem); + sis_nelem -= nelem; + + /* Reset source space index */ + sis_i = 0; + } /* end if */ + else + /* There are no more sequences in src_intersect_space, + * so we can exit the loop. Use goto instead of break + * so we exit the outer loop. */ + goto loop_end; + } /* end if */ + } while(sis_off[sis_i] + sis_len[sis_i] <= ss_off[ss_i]); + + /* Reset advance_sis */ + advance_sis = FALSE; + } /* end if */ + else { + /* Sequences intersect, add intersection to projected space */ + /* Calculate intersection sequence in terms of offset within source + * selection and advance any sequences we complete */ + if(ss_off[ss_i] >= sis_off[sis_i]) + int_sel_off = ss_sel_off; + else + int_sel_off = sis_off[sis_i] - ss_off[ss_i] + ss_sel_off; + if((ss_off[ss_i] + (hsize_t)ss_len[ss_i]) <= (sis_off[sis_i] + + (hsize_t)sis_len[sis_i])) { + int_len = (size_t)((hsize_t)ss_len[ss_i] + ss_sel_off - int_sel_off); + advance_ss = TRUE; + } /* end if */ + else + int_len = (size_t)(sis_off[sis_i] + (hsize_t)sis_len[sis_i] - ss_off[ss_i] + ss_sel_off - int_sel_off); + if((ss_off[ss_i] + (hsize_t)ss_len[ss_i]) >= (sis_off[sis_i] + + (hsize_t)sis_len[sis_i])) + advance_sis = TRUE; + + /* Project intersection sequence to destination selection */ + while(int_len > (size_t)0) { + while(ds_sel_off + (hsize_t)ds_len[ds_i] <= int_sel_off) { + /* Intersection is not projected to this destination + * sequence, advance destination space */ + ds_sel_off += (hsize_t)ds_len[ds_i]; + if(++ds_i == ds_nseq) { + HDassert(ds_nelem > 0); + + /* Try to grab more sequences from dst_space */ + if(H5S_SELECT_GET_SEQ_LIST(dst_space, 0u, ds_iter, H5S_PROJECT_INTERSECT_NSEQS, ds_nelem, &ds_nseq, &nelem, ds_off, ds_len) < 0) + HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed") + HDassert(ds_len[0] > 0); + + /* Update ss_nelem */ + HDassert(nelem > 0); + HDassert(nelem <= ds_nelem); + ds_nelem -= nelem; + + /* Reset source space index */ + ds_i = 0; + } /* end if */ + } /* end while */ + + /* Add sequence to projected space */ + HDassert(ds_sel_off <= int_sel_off); + proj_off = ds_off[ds_i] + int_sel_off - ds_sel_off; + proj_len = proj_len_rem = (size_t)MIN(int_len, + (size_t)(ds_sel_off + (hsize_t)ds_len[ds_i] + - int_sel_off)); + + /* Add to span tree */ + while(proj_len_rem > (size_t)0) { + /* Check for more than one full row (in every dim) and + * append multiple spans at once? -NAF */ + /* Append spans in higher dimensions if we're going ouside + * the plane of the span currently being built (i.e. it's + * finished being built) */ + for(i = proj_rank - 1; ((i > 0) + && ((proj_off / proj_down_dims[i - 1]) + != curr_span_up_dim[i - 1])); i--) { + if(curr_span_tree[i]) { + HDassert(prev_span[i]); + + /* Append complete lower dimension span tree to + * current dimension */ + low = curr_span_up_dim[i - 1] % proj_space->extent.size[i - 1]; + if(H5S_hyper_append_span(&prev_span[i - 1], &curr_span_tree[i - 1], low, low, curr_span_tree[i], NULL) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + + /* Reset lower dimension's span tree and previous + * span since we just committed it and will start + * over with a new one */ + if(H5S_hyper_free_span_info(curr_span_tree[i]) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free span info") + curr_span_tree[i] = NULL; + prev_span[i] = NULL; + } /* end if */ + + /* Update curr_span_up_dim */ + curr_span_up_dim[i - 1] = proj_off / proj_down_dims[i - 1]; + } /* end for */ + + /* Compute bounds for new span in lowest dimension */ + low = proj_off % proj_space->extent.size[proj_rank - 1]; + span_len = MIN(proj_len_rem, + (size_t)(proj_space->extent.size[proj_rank - 1] + - low)); + HDassert(proj_len_rem >= span_len); + high = low + (hsize_t)span_len - (hsize_t)1; + + /* Append span in lowest dimension */ + if(H5S_hyper_append_span(&prev_span[proj_rank - 1], &curr_span_tree[proj_rank - 1], low, high, NULL, NULL) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + + /* Update remaining offset and length */ + proj_off += (hsize_t)span_len; + proj_len_rem -= span_len; + } /* end while */ + + /* Update intersection sequence */ + int_sel_off += (hsize_t)proj_len; + int_len -= proj_len; + } /* end while */ + } /* end else */ + } /* end while */ + +loop_end: + /* Add remaining spans to span tree */ + for(i = proj_rank - 1; i > 0; i--) + if(curr_span_tree[i]) { + HDassert(prev_span[i]); + + /* Append remaining span tree to higher dimension */ + low = curr_span_up_dim[i - 1] % proj_space->extent.size[i - 1]; + if(H5S_hyper_append_span(&prev_span[i - 1], &curr_span_tree[i - 1], low, low, curr_span_tree[i], NULL) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span") + + /* Reset span tree */ + if(H5S_hyper_free_span_info(curr_span_tree[i]) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free span info") + curr_span_tree[i] = NULL; + } /* end if */ + + /* Add span tree to proj_space */ + if(curr_span_tree[0]) { + proj_space->select.sel_info.hslab->span_lst = curr_span_tree[0]; + curr_span_tree[0] = NULL; + + /* Set the number of elements in current selection */ + proj_space->select.num_elem = H5S_hyper_spans_nelem(proj_space->select.sel_info.hslab->span_lst); + + /* Attempt to rebuild "optimized" start/stride/count/block information. + * from resulting hyperslab span tree */ + if(H5S_hyper_rebuild(proj_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't rebuild hyperslab info") + } /* end if */ + else + /* If we did not add anything to proj_space, select none instead */ + if(H5S_select_none(proj_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection") + +done: + /* Release source selection iterator */ + if(ss_iter_init && H5S_SELECT_ITER_RELEASE(ss_iter) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator") + if(ss_iter) + ss_iter = H5FL_FREE(H5S_sel_iter_t, ss_iter); + + /* Release destination selection iterator */ + if(ds_iter_init && H5S_SELECT_ITER_RELEASE(ds_iter) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator") + if(ds_iter) + ds_iter = H5FL_FREE(H5S_sel_iter_t, ds_iter); + + /* Release source intersect selection iterator */ + if(sis_iter_init && H5S_SELECT_ITER_RELEASE(sis_iter) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator") + if(sis_iter) + sis_iter = H5FL_FREE(H5S_sel_iter_t, sis_iter); + + /* Cleanup on error */ + if(ret_value < 0) { + /* Remove current selection from proj_space */ + if(H5S_SELECT_RELEASE(proj_space) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") + + /* Free span trees */ + for(i = 0; i < proj_rank; i++) + if(curr_span_tree[i]) { + if(H5S_hyper_free_span_info(curr_span_tree[i]) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free span info") + curr_span_tree[i] = NULL; + } /* end if */ + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_project_intersection() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_subtract + PURPOSE + Subtract one hyperslab selection from another + USAGE + herr_t H5S__hyper_subtract(space,subtract_space) + H5S_t *space; IN/OUT: Selection to be operated on + H5S_t *subtract_space; IN: Selection that will be subtracted from space + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + Removes any and all portions of space that are also present in + subtract_space. In essence, performs an A_NOT_B operation with the + two selections. + + Note this function basically duplicates a subset of the functionality + of H5S_select_select(). It should probably be removed when that + function is enabled. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5S__hyper_subtract(H5S_t *space, H5S_t *subtract_space) +{ + H5S_hyper_span_info_t *a_not_b = NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */ + H5S_hyper_span_info_t *a_and_b = NULL; /* Span tree for hyperslab spans in both old and new span trees */ + H5S_hyper_span_info_t *b_not_a = NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Check args */ + HDassert(space); + HDassert(subtract_space); + + /* Check that the space selections both have span trees */ + if(space->select.sel_info.hslab->span_lst == NULL) + if(H5S_hyper_generate_spans(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") + if(subtract_space->select.sel_info.hslab->span_lst == NULL) + if(H5S_hyper_generate_spans(subtract_space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree") + + /* Generate lists of spans which overlap and don't overlap */ + if(H5S_hyper_clip_spans(space->select.sel_info.hslab->span_lst, subtract_space->select.sel_info.hslab->span_lst, &a_not_b, &a_and_b, &b_not_a)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information") + + /* Reset the other dataspace selection information */ + if(H5S_SELECT_RELEASE(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection") + + /* Allocate space for the hyperslab selection information */ + if((space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info") + + /* Set unlim_dim */ + space->select.sel_info.hslab->unlim_dim = -1; + + /* Check for anything returned in a_not_b */ + if(a_not_b) { + /* Update spans in space */ + space->select.sel_info.hslab->span_lst = a_not_b; + a_not_b = NULL; + + /* Update number of elements */ + space->select.num_elem = H5S_hyper_spans_nelem(space->select.sel_info.hslab->span_lst); + + /* Attempt to rebuild "optimized" start/stride/count/block information. + * from resulting hyperslab span tree */ + if(H5S_hyper_rebuild(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't rebuild hyperslab info") + } /* end if */ + else { + H5S_hyper_span_info_t *spans; /* Empty hyperslab span tree */ + + /* Set number of elements */ + space->select.num_elem = 0; + + /* Allocate a span info node */ + if(NULL == (spans = H5FL_MALLOC(H5S_hyper_span_info_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span") + + /* Set the reference count */ + spans->count = 1; + + /* Reset the scratch pad space */ + spans->scratch = 0; + + /* Set to empty tree */ + spans->head = NULL; + + /* Set pointer to empty span tree */ + space->select.sel_info.hslab->span_lst = spans; + } /* end if */ + +done: + /* Free span trees */ + if(a_and_b) + H5S_hyper_free_span_info(a_and_b); + if(b_not_a) + H5S_hyper_free_span_info(b_not_a); + if(a_not_b) { + HDassert(ret_value < 0); + H5S_hyper_free_span_info(b_not_a); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_subtract() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_get_clip_diminfo + PURPOSE + Calculates the count and block required to clip the specified + unlimited dimension to include clip_size. The returned selection may + extent beyond clip_size. + USAGE + void H5S__hyper_get_clip_diminfo(start,stride,count,block,clip_size) + hsize_t start; IN: Start of hyperslab in unlimited dimension + hsize_t stride; IN: Stride of hyperslab in unlimited dimension + hsize_t *count; IN/OUT: Count of hyperslab in unlimited dimension + hsize_t *block; IN/OUT: Block of hyperslab in unlimited dimension + hsize_t clip_size; IN: Extent that hyperslab will be clipped to + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + This function recalculates the internal description of the hyperslab + to make the unlimited dimension extend to the specified extent. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +void +H5S__hyper_get_clip_diminfo(hsize_t start, hsize_t stride, hsize_t *count, + hsize_t *block, hsize_t clip_size) +{ + FUNC_ENTER_PACKAGE_NOERR + + /* Check for selection outside clip size */ + if(start >= clip_size) { + if(*block == H5S_UNLIMITED) + *block = 0; + else + *count = 0; + } /* end if */ + /* Check for single block in unlimited dimension */ + else if((*block == H5S_UNLIMITED) || (*block == stride)) { + /* Calculate actual block size for this clip size */ + *block = clip_size - start; + *count = (hsize_t)1; + } /* end if */ + else { + HDassert(*count == H5S_UNLIMITED); + + /* Calculate initial count (last block may be partial) */ + *count = (clip_size - start + stride - (hsize_t)1) / stride; + HDassert(*count > (hsize_t)0); + } /* end else */ + + FUNC_LEAVE_NOAPI_VOID +} /* end H5S_hyper_get_clip_diminfo() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_clip_unlim + PURPOSE + Clips the unlimited dimension of the hyperslab selection to the + specified size + USAGE + void H5S_hyper_clip_unlim(space,clip_size) + H5S_t *space, IN/OUT: Unlimited space to clip + hsize_t clip_size; IN: Extent that hyperslab will be clipped to + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + This function changes the unlimited selection into a limited selection + with the extent of the formerly unlimited dimension specified by + * clip_size. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Note this function does not take the offset into account. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5S_hyper_clip_unlim(H5S_t *space, hsize_t clip_size) +{ + H5S_hyper_sel_t *hslab; /* Convenience pointer to hyperslab info */ + hsize_t orig_count; /* Original count in unlimited dimension */ + int orig_unlim_dim; /* Original unliminted dimension */ + H5S_hyper_dim_t *diminfo; /* Convenience pointer to opt_diminfo in unlimited dimension */ + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(FAIL) + + /* Check parameters */ + HDassert(space); + hslab = space->select.sel_info.hslab; + HDassert(hslab); + HDassert(hslab->unlim_dim >= 0); + HDassert(!hslab->span_lst); + + /* Save original unlimited dimension */ + orig_unlim_dim = hslab->unlim_dim; + + diminfo = &hslab->opt_diminfo[orig_unlim_dim]; + + /* Save original count in unlimited dimension */ + orig_count = diminfo->count; + + /* Get initial diminfo */ + H5S__hyper_get_clip_diminfo(diminfo->start, diminfo->stride, &diminfo->count, &diminfo->block, clip_size); + + /* Selection is no longer unlimited */ + space->select.sel_info.hslab->unlim_dim = -1; + + /* Check for nothing returned */ + if((diminfo->block == 0) || (diminfo->count == 0)) { + /* Convert to "none" selection */ + if(H5S_select_none(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection") + } /* end if */ + /* Check for single block in unlimited dimension */ + else if(orig_count == (hsize_t)1) { + /* Calculate number of elements */ + space->select.num_elem = diminfo->block * hslab->num_elem_non_unlim; + + /* Mark that opt_diminfo is valid */ + hslab->diminfo_valid = TRUE; + } /* end if */ + else { + /* Calculate number of elements */ + space->select.num_elem = diminfo->count * diminfo->block + * hslab->num_elem_non_unlim; + + /* Check if last block is partial. If superset is set, just keep the + * last block complete to speed computation. */ + HDassert(clip_size > diminfo->start); + if(((diminfo->stride * (diminfo->count - (hsize_t)1)) + diminfo->block) + > (clip_size - diminfo->start)) { + hsize_t start[H5S_MAX_RANK]; + hsize_t block[H5S_MAX_RANK]; + unsigned i; + + /* Last block is partial, need to construct compound selection */ + /* Fill start with zeros */ + HDmemset(start, 0, sizeof(start)); + + /* Set block to clip_size in unlimited dimension, H5S_MAX_SIZE in + * others so only unlimited dimension is clipped */ + for(i = 0; i < space->extent.rank; i++) + if((int)i == orig_unlim_dim) + block[i] = clip_size; + else + block[i] = H5S_MAX_SIZE; + + /* Generate span tree in selection */ + if(!hslab->span_lst) + if(H5S_hyper_generate_spans(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to generate span tree") + + /* Indicate that the regular dimensions are no longer valid */ + hslab->diminfo_valid = FALSE; + + /* "And" selection with calculated block to perform clip operation + */ + if(H5S_generate_hyperslab(space, H5S_SELECT_AND, start, _ones, _ones, block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs") + } /* end if */ + else + /* Last block is complete, simply mark that opt_diminfo is valid */ + hslab->diminfo_valid = TRUE; + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_clip_unlim() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__hyper_get_clip_extent_real + PURPOSE + Gets the extent a space should be clipped to in order to contain the + specified number of slices in the unlimited dimension + USAGE + hsize_t H5S__hyper_get_clip_extent_real(clip_space,num_slices,incl_trail) + const H5S_t *clip_space, IN: Space that clip size will be calculated based on + hsize_t num_slizes, IN: Number of slices clip_space should contain when clipped + hbool_t incl_trail; IN: Whether to include trailing unselected space + RETURNS + Clip extent to match num_slices (never fails) + DESCRIPTION + Calculates and returns the extent that clip_space should be clipped to + (via H5S_hyper_clip_unlim) in order for it to contain num_slices + slices in the unlimited dimension. If the clipped selection would end + immediately before a section of unselected space (i.e. at the end of a + block), then if incl_trail is TRUE, the returned clip extent is + selected to include that trailing "blank" space, otherwise it is + selected to end at the end before the blank space. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Note this assumes the offset has been normalized. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static hsize_t +H5S__hyper_get_clip_extent_real(const H5S_t *clip_space, hsize_t num_slices, + hbool_t incl_trail) +{ + const H5S_hyper_dim_t *diminfo; /* Convenience pointer to opt_unlim_diminfo in unlimited dimension */ + hsize_t count; + hsize_t rem_slices; + hsize_t ret_value = 0; /* Return value */ + + FUNC_ENTER_STATIC_NOERR + + /* Check parameters */ + HDassert(clip_space); + HDassert(clip_space->select.sel_info.hslab); + HDassert(clip_space->select.sel_info.hslab->unlim_dim >= 0); + + diminfo = &clip_space->select.sel_info.hslab->opt_diminfo[clip_space->select.sel_info.hslab->unlim_dim]; + + if(num_slices == 0) + ret_value = incl_trail ? diminfo->start : 0; + else if((diminfo->block == H5S_UNLIMITED) + || (diminfo->block == diminfo->stride)) + /* Unlimited block, just set the extent large enough for the block size + * to match num_slices */ + ret_value = diminfo->start + num_slices; + else { + /* Unlimited count, need to match extent so a block (possibly) gets cut + * off so the number of slices matches num_slices */ + HDassert(diminfo->count == H5S_UNLIMITED); + + /* Calculate number of complete blocks in clip_space */ + count = num_slices / diminfo->block; + + /* Calculate slices remaining */ + rem_slices = num_slices - (count * diminfo->block); + + if(rem_slices > 0) + /* Must end extent in middle of partial block (or beginning of empty + * block if include_trailing_space and rem_slices == 0) */ + ret_value = diminfo->start + (count * diminfo->stride) + rem_slices; + else { + if(incl_trail) + /* End extent just before first missing block */ + ret_value = diminfo->start + (count * diminfo->stride); + else + /* End extent at end of last block */ + ret_value = diminfo->start + ((count - (hsize_t)1) + * diminfo->stride) + diminfo->block; + } /* end else */ + } /* end else */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S__hyper_get_clip_extent_real() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_get_clip_extent + PURPOSE + Gets the extent a space should be clipped to in order to contain the + same number of elements as another space + USAGE + hsize_t H5S__hyper_get_clip_extent(clip_space,match_space,incl_trail) + const H5S_t *clip_space, IN: Space that clip size will be calculated based on + const H5S_t *match_space, IN: Space containing the same number of elements as clip_space should after clipping + hbool_t incl_trail; IN: Whether to include trailing unselected space + RETURNS + Calculated clip extent (never fails) + DESCRIPTION + Calculates and returns the extent that clip_space should be clipped to + (via H5S_hyper_clip_unlim) in order for it to contain the same number + of elements as match_space. If the clipped selection would end + immediately before a section of unselected space (i.e. at the end of a + block), then if incl_trail is TRUE, the returned clip extent is + selected to include that trailing "blank" space, otherwise it is + selected to end at the end before the blank space. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Note this assumes the offset has been normalized. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +hsize_t +H5S_hyper_get_clip_extent(const H5S_t *clip_space, const H5S_t *match_space, + hbool_t incl_trail) +{ + hsize_t num_slices; /* Number of slices in unlimited dimension */ + hsize_t ret_value = 0; /* Return value */ + + FUNC_ENTER_NOAPI(0) + + /* Check parameters */ + HDassert(clip_space); + HDassert(match_space); + HDassert(clip_space->select.sel_info.hslab->unlim_dim >= 0); + + /* Check for "none" match space */ + if(match_space->select.type->type == H5S_SEL_NONE) + num_slices = (hsize_t)0; + else { + HDassert(match_space->select.type->type == H5S_SEL_HYPERSLABS); + HDassert(match_space->select.sel_info.hslab); + + /* Calculate number of slices */ + num_slices = match_space->select.num_elem + / clip_space->select.sel_info.hslab->num_elem_non_unlim; + HDassert((match_space->select.num_elem + % clip_space->select.sel_info.hslab->num_elem_non_unlim) == 0); + } /* end else */ + + /* Call "real" get_clip_extent function */ + ret_value = H5S__hyper_get_clip_extent_real(clip_space, num_slices, incl_trail); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_get_clip_extent() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_get_clip_extent_match + PURPOSE + Gets the extent a space should be clipped to in order to contain the + same number of elements as another unlimited space that has been + clipped to a different extent + USAGE + hsize_t H5S__hyper_get_clip_extent_match(clip_space,match_space,match_clip_size,incl_trail) + const H5S_t *clip_space, IN: Space that clip size will be calculated based on + const H5S_t *match_space, IN: Space that, after being clipped to match_clip_size, contains the same number of elements as clip_space should after clipping + hsize_t match_clip_size, IN: Extent match_space would be clipped to to match the number of elements in clip_space + hbool_t incl_trail; IN: Whether to include trailing unselected space + RETURNS + Calculated clip extent (never fails) + DESCRIPTION + Calculates and returns the extent that clip_space should be clipped to + (via H5S_hyper_clip_unlim) in order for it to contain the same number + of elements as match_space would have after being clipped to + match_clip_size. If the clipped selection would end immediately + before a section of unselected space (i.e. at the end of a block), + then if incl_trail is TRUE, the returned clip extent is selected to + include that trailing "blank" space, otherwise it is selected to end + at the end before the blank space. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Note this assumes the offset has been normalized. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +hsize_t +H5S_hyper_get_clip_extent_match(const H5S_t *clip_space, + const H5S_t *match_space, hsize_t match_clip_size, hbool_t incl_trail) +{ + const H5S_hyper_dim_t *match_diminfo; /* Convenience pointer to opt_unlim_diminfo in unlimited dimension in match_space */ + hsize_t count; /* Temporary count */ + hsize_t block; /* Temporary block */ + hsize_t num_slices; /* Number of slices in unlimited dimension */ + hsize_t ret_value = 0; /* Return value */ + + FUNC_ENTER_NOAPI(0) + + /* Check parameters */ + HDassert(clip_space); + HDassert(match_space); + HDassert(clip_space->select.sel_info.hslab); + HDassert(match_space->select.sel_info.hslab); + HDassert(clip_space->select.sel_info.hslab->unlim_dim >= 0); + HDassert(match_space->select.sel_info.hslab->unlim_dim >= 0); + HDassert(clip_space->select.sel_info.hslab->num_elem_non_unlim + == match_space->select.sel_info.hslab->num_elem_non_unlim); + + match_diminfo = &match_space->select.sel_info.hslab->opt_diminfo[match_space->select.sel_info.hslab->unlim_dim]; + + /* Get initial count and block */ + count = match_diminfo->count; + block = match_diminfo->block; + H5S__hyper_get_clip_diminfo(match_diminfo->start, match_diminfo->stride, &count, &block, match_clip_size); + + /* Calculate number of slices */ + /* Check for nothing returned */ + if((block == 0) || (count == 0)) + num_slices = (hsize_t)0; + /* Check for single block in unlimited dimension */ + else if(count == (hsize_t)1) + num_slices = block; + else { + /* Calculate initial num_slices */ + num_slices = block * count; + + /* Check for partial last block */ + HDassert(match_clip_size >= match_diminfo->start); + if(((match_diminfo->stride * (count - (hsize_t)1)) + block) + > (match_clip_size - match_diminfo->start)) { + /* Subtract slices missing from last block */ + HDassert((((match_diminfo->stride * (count - (hsize_t)1)) + block) + - (match_clip_size - match_diminfo->start)) < num_slices); + num_slices -= ((match_diminfo->stride * (count - (hsize_t)1)) + + block) - (match_clip_size - match_diminfo->start); + } /* end if */ + } /* end else */ + + /* Call "real" get_clip_extent function */ + ret_value = H5S__hyper_get_clip_extent_real(clip_space, num_slices, incl_trail); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_get_clip_extent_match() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_get_unlim_block + PURPOSE + Get the nth block in the unlimited dimension + USAGE + H5S_t *H5S_hyper_get_unlim_block(space,block_index) + const H5S_t *space, IN: Space with unlimited selection + hsize_t block_index, IN: Index of block to return in unlimited dimension + hbool_t incl_trail; IN: Whether to include trailing unselected space + RETURNS + New space on success/NULL on failure. + DESCRIPTION + Returns a space containing only the block_indexth block in the + unlimited dimension on space. All blocks in all other dimensions are + preserved. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Note this assumes the offset has been normalized. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +H5S_t * +H5S_hyper_get_unlim_block(const H5S_t *space, hsize_t block_index) +{ + H5S_hyper_sel_t *hslab; /* Convenience pointer to hyperslab info */ + H5S_t *space_out = NULL; + hsize_t start[H5S_MAX_RANK]; + hsize_t stride[H5S_MAX_RANK]; + hsize_t count[H5S_MAX_RANK]; + hsize_t block[H5S_MAX_RANK]; + unsigned i; + H5S_t *ret_value = NULL; + + FUNC_ENTER_NOAPI(NULL) + + /* Check parameters */ + HDassert(space); + hslab = space->select.sel_info.hslab; + HDassert(hslab); + HDassert(hslab->unlim_dim >= 0); + HDassert(hslab->opt_diminfo[hslab->unlim_dim].count == H5S_UNLIMITED); + + /* Set start to select block_indexth block in unlimited dimension and set + * count to 1 in that dimension to only select that block. Copy all other + * diminfo parameters. */ + for(i = 0; i < space->extent.rank; i++) { + if((int)i == hslab->unlim_dim){ + start[i] = hslab->opt_diminfo[i].start + (block_index + * hslab->opt_diminfo[i].stride); + count[i] = (hsize_t)1; + } /* end if */ + else { + start[i] = hslab->opt_diminfo[i].start; + count[i] = hslab->opt_diminfo[i].count; + } /* end else */ + stride[i] = hslab->opt_diminfo[i].stride; + block[i] = hslab->opt_diminfo[i].block; + } /* end for */ + + /* Create output space, copy extent */ + if(NULL == (space_out = H5S_create(H5S_SIMPLE))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, NULL, "unable to create output dataspace") + if(H5S_extent_copy_real(&space_out->extent, &space->extent, TRUE) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "unable to copy destination space extent") + + /* Select block as defined by start/stride/count/block computed above */ + if(H5S_select_hyperslab(space_out, H5S_SELECT_SET, start, stride, count, block) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "can't select hyperslab") + + /* Set return value */ + ret_value = space_out; + +done: + /* Free space on error */ + if(!ret_value) + if(space_out && H5S_close(space_out) < 0) + HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, NULL, "unable to release dataspace") + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_get_unlim_block */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_get_first_inc_block + PURPOSE + Get the index of the first incomplete block in the specified extent + USAGE + hsize_t H5S_hyper_get_first_inc_block(space,clip_size,partial) + const H5S_t *space, IN: Space with unlimited selection + hsize_t clip_size, IN: Extent space would be clipped to + hbool_t *partial; OUT: Whether the ret_valueth block (first incomplete block) is partial + RETURNS + Index of first incomplete block in clip_size (never fails). + DESCRIPTION + Calculates and returns the index (as would be passed to + H5S_hyper_get_unlim_block()) of the first block in the unlimited + dimension of space which would be incomplete or missing when space is + clipped to clip_size. partial is set to TRUE if the first incomplete + block is partial, and FALSE if the first incomplete block is missing. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Note this assumes the offset has been normalized. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +hsize_t +H5S_hyper_get_first_inc_block(const H5S_t *space, hsize_t clip_size, + hbool_t *partial) +{ + H5S_hyper_sel_t *hslab; /* Convenience pointer to hyperslab info */ + H5S_hyper_dim_t *diminfo; /* Convenience pointer to opt_diminfo in unlimited dimension */ + hsize_t ret_value = 0; + + FUNC_ENTER_NOAPI(0) + + /* Check parameters */ + HDassert(space); + hslab = space->select.sel_info.hslab; + HDassert(hslab); + HDassert(hslab->unlim_dim >= 0); + HDassert(hslab->opt_diminfo[hslab->unlim_dim].count == H5S_UNLIMITED); + + diminfo = &hslab->opt_diminfo[hslab->unlim_dim]; + + /* Check for selection outside of clip_size */ + if(diminfo->start >= clip_size) { + ret_value = 0; + if(partial) + partial = FALSE; + } /* end if */ + else { + /* Calculate index of first incomplete block */ + ret_value = (clip_size - diminfo->start + diminfo->stride + - diminfo->block) / diminfo->stride; + + if(partial) { + /* Check for partial block */ + if((diminfo->stride * ret_value) < (clip_size - diminfo->start)) + *partial = TRUE; + else + *partial = FALSE; + } /* end if */ + } /* end else */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_hyper_get_first_inc_block */ + + +/*-------------------------------------------------------------------------- + NAME + H5Sis_regular_hyperslab + PURPOSE + Determine if a hyperslab selection is regular + USAGE + htri_t H5Sis_regular_hyperslab(dsid) + hid_t dsid; IN: Dataspace ID of hyperslab selection to query + RETURNS + TRUE/FALSE for hyperslab selection, FAIL on error or when querying other + selection types. + DESCRIPTION + If a hyperslab can be represented as a single call to H5Sselect_hyperslab, + with the H5S_SELECT_SET option, it is regular. If the hyperslab selection + would require multiple calls to H5Sselect_hyperslab, it is irregular. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +htri_t +H5Sis_regular_hyperslab(hid_t spaceid) +{ + H5S_t *space; /* Dataspace to query */ + htri_t ret_value; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE1("t", "i", spaceid); + + /* 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") + + ret_value = H5S_hyper_is_regular(space); + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Sis_regular_hyperslab() */ + + +/*-------------------------------------------------------------------------- + NAME + H5Sgetregular_hyperslab + PURPOSE + Retrieve a regular hyperslab selection + USAGE + herr_t H5Sget_regular_hyperslab(dsid, start, stride, block, count) + hid_t dsid; IN: Dataspace ID of hyperslab selection to query + hsize_t start[]; OUT: Offset of start of hyperslab + hsize_t stride[]; OUT: Hyperslab stride + hsize_t count[]; OUT: Number of blocks included in hyperslab + hsize_t block[]; OUT: Size of block in hyperslab + RETURNS + Non-negative on success/Negative on failure. (It is an error to query + the regular hyperslab selections for non-regular hyperslab selections) + DESCRIPTION + Retrieve the start/stride/count/block for a regular hyperslab selection. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + Note that if a hyperslab is originally regular, then becomes irregular + through selection operations, and then becomes regular again, the new + final regular selection may be equivalent but not identical to the + original regular selection. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5Sget_regular_hyperslab(hid_t spaceid, hsize_t start[], hsize_t stride[], + hsize_t count[], hsize_t block[]) +{ + H5S_t *space; /* Dataspace to query */ + unsigned u; /* Local index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE5("e", "i*h*h*h*h", spaceid, start, stride, count, block); + + /* 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(TRUE != H5S_hyper_is_regular(space)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a regular hyperslab selection") + + /* Retrieve hyperslab parameters */ + if(start) + for(u = 0; u < space->extent.rank; u++) + start[u] = space->select.sel_info.hslab->app_diminfo[u].start; + if(stride) + for(u = 0; u < space->extent.rank; u++) + stride[u] = space->select.sel_info.hslab->app_diminfo[u].stride; + if(count) + for(u = 0; u < space->extent.rank; u++) + count[u] = space->select.sel_info.hslab->app_diminfo[u].count; + if(block) + for(u = 0; u < space->extent.rank; u++) + block[u] = space->select.sel_info.hslab->app_diminfo[u].block; + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Sget_regular_hyperslab() */ + |