diff options
Diffstat (limited to 'src/H5Spoint.c')
-rw-r--r-- | src/H5Spoint.c | 1766 |
1 files changed, 1766 insertions, 0 deletions
diff --git a/src/H5Spoint.c b/src/H5Spoint.c new file mode 100644 index 0000000..251a063 --- /dev/null +++ b/src/H5Spoint.c @@ -0,0 +1,1766 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * 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> + * Tuesday, June 16, 1998 + * + * Purpose: Point 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 "H5MMprivate.h" /* Memory Management functions */ +#include "H5Spkg.h" /* Dataspace functions */ +#include "H5VMprivate.h" /* Vector functions */ + +/* Static function prototypes */ + +/* Selection callbacks */ +static herr_t H5S_point_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection); +static herr_t H5S_point_get_seq_list(const H5S_t *space, unsigned flags, + H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes, + size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len); +static herr_t H5S_point_release(H5S_t *space); +static htri_t H5S_point_is_valid(const H5S_t *space); +static hssize_t H5S_point_serial_size(const H5S_t *space); +static herr_t H5S_point_serialize(const H5S_t *space, uint8_t **p); +static herr_t H5S_point_deserialize(H5S_t *space, uint32_t version, uint8_t flags, + const uint8_t **p); +static herr_t H5S_point_bounds(const H5S_t *space, hsize_t *start, hsize_t *end); +static herr_t H5S_point_offset(const H5S_t *space, hsize_t *off); +static int H5S__point_unlim_dim(const H5S_t *space); +static htri_t H5S_point_is_contiguous(const H5S_t *space); +static htri_t H5S_point_is_single(const H5S_t *space); +static htri_t H5S_point_is_regular(const H5S_t *space); +static herr_t H5S_point_adjust_u(H5S_t *space, const hsize_t *offset); +static herr_t H5S_point_project_scalar(const H5S_t *space, hsize_t *offset); +static herr_t H5S_point_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset); +static herr_t H5S_point_iter_init(H5S_sel_iter_t *iter, const H5S_t *space); + +/* Selection iteration callbacks */ +static herr_t H5S_point_iter_coords(const H5S_sel_iter_t *iter, hsize_t *coords); +static herr_t H5S_point_iter_block(const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end); +static hsize_t H5S_point_iter_nelmts(const H5S_sel_iter_t *iter); +static htri_t H5S_point_iter_has_next_block(const H5S_sel_iter_t *iter); +static herr_t H5S_point_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem); +static herr_t H5S_point_iter_next_block(H5S_sel_iter_t *sel_iter); +static herr_t H5S_point_iter_release(H5S_sel_iter_t *sel_iter); + +/* Selection properties for point selections */ +const H5S_select_class_t H5S_sel_point[1] = {{ + H5S_SEL_POINTS, + + /* Methods on selection */ + H5S_point_copy, + H5S_point_get_seq_list, + H5S_point_release, + H5S_point_is_valid, + H5S_point_serial_size, + H5S_point_serialize, + H5S_point_deserialize, + H5S_point_bounds, + H5S_point_offset, + H5S__point_unlim_dim, + NULL, + H5S_point_is_contiguous, + H5S_point_is_single, + H5S_point_is_regular, + H5S_point_adjust_u, + H5S_point_project_scalar, + H5S_point_project_simple, + H5S_point_iter_init, +}}; + +/* Iteration properties for point selections */ +static const H5S_sel_iter_class_t H5S_sel_iter_point[1] = {{ + H5S_SEL_POINTS, + + /* Methods on selection iterator */ + H5S_point_iter_coords, + H5S_point_iter_block, + H5S_point_iter_nelmts, + H5S_point_iter_has_next_block, + H5S_point_iter_next, + H5S_point_iter_next_block, + H5S_point_iter_release, +}}; + +/* Declare a free list to manage the H5S_pnt_node_t struct */ +H5FL_DEFINE_STATIC(H5S_pnt_node_t); + +/* Declare a free list to manage the H5S_pnt_list_t struct */ +H5FL_DEFINE_STATIC(H5S_pnt_list_t); + + +/*------------------------------------------------------------------------- + * Function: H5S_point_iter_init + * + * Purpose: Initializes iteration information for point selection. + * + * Return: non-negative on success, negative on failure. + * + * Programmer: Quincey Koziol + * Tuesday, June 16, 1998 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_point_iter_init(H5S_sel_iter_t *iter, const H5S_t *space) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(space && H5S_SEL_POINTS==H5S_GET_SELECT_TYPE(space)); + HDassert(iter); + + /* Initialize the number of points to iterate over */ + iter->elmt_left=space->select.num_elem; + + /* Start at the head of the list of points */ + iter->u.pnt.curr=space->select.sel_info.pnt_lst->head; + + /* Initialize type of selection iterator */ + iter->type=H5S_sel_iter_point; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_point_iter_init() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_point_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_point_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 */ + HDmemcpy(coords,iter->u.pnt.curr->pnt,sizeof(hsize_t)*iter->rank); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_point_iter_coords() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_point_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 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_point_iter_block (const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(iter); + HDassert(start); + HDassert(end); + + /* Copy the current point as a block */ + HDmemcpy(start,iter->u.pnt.curr->pnt,sizeof(hsize_t)*iter->rank); + HDmemcpy(end,iter->u.pnt.curr->pnt,sizeof(hsize_t)*iter->rank); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_point_iter_block() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_point_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_point_iter_nelmts (const H5S_sel_iter_t *iter) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(iter); + + FUNC_LEAVE_NOAPI(iter->elmt_left) +} /* H5S_point_iter_nelmts() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_iter_has_next_block + PURPOSE + Check if there is another block left in the current iterator + USAGE + htri_t H5S_point_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_point_iter_has_next_block(const H5S_sel_iter_t *iter) +{ + htri_t ret_value=TRUE; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(iter); + + /* Check if there is another point in the list */ + if(iter->u.pnt.curr->next==NULL) + HGOTO_DONE(FALSE); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_point_iter_has_next_block() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_iter_next + PURPOSE + Increment selection iterator + USAGE + herr_t H5S_point_iter_next(iter, nelem) + H5S_sel_iter_t *iter; IN: Pointer to selection iterator + size_t nelem; IN: Number of elements to advance by + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Advance selection iterator to the NELEM'th next element in the selection. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_point_iter_next(H5S_sel_iter_t *iter, size_t nelem) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(iter); + HDassert(nelem>0); + + /* Increment the iterator */ + while(nelem>0) { + iter->u.pnt.curr=iter->u.pnt.curr->next; + nelem--; + } /* end while */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_point_iter_next() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_iter_next_block + PURPOSE + Increment selection iterator to next block + USAGE + herr_t H5S_point_iter_next_block(iter) + H5S_sel_iter_t *iter; IN: Pointer to selection iterator + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Advance selection iterator to the next block in the selection. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_point_iter_next_block(H5S_sel_iter_t *iter) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(iter); + + /* Increment the iterator */ + iter->u.pnt.curr=iter->u.pnt.curr->next; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_point_iter_next_block() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_iter_release + PURPOSE + Release point selection iterator information for a dataspace + USAGE + herr_t H5S_point_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 point selection iterator + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_point_iter_release (H5S_sel_iter_t H5_ATTR_UNUSED * iter) +{ + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(iter); + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_point_iter_release() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_add + PURPOSE + Add a series of elements to a point selection + USAGE + herr_t H5S_point_add(space, num_elem, coord) + H5S_t *space; IN: Dataspace of selection to modify + size_t num_elem; IN: Number of elements in COORD array. + const hsize_t *coord[]; IN: The location of each element selected + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + This function adds elements to the current point selection for a dataspace + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_point_add(H5S_t *space, H5S_seloper_t op, size_t num_elem, const hsize_t *coord) +{ + H5S_pnt_node_t *top = NULL, *curr = NULL, *new_node = NULL; /* Point selection nodes */ + unsigned u; /* Counter */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(space); + HDassert(num_elem > 0); + HDassert(coord); + HDassert(op == H5S_SELECT_SET || op == H5S_SELECT_APPEND || op == H5S_SELECT_PREPEND); + + for(u = 0; u < num_elem; u++) { + /* Allocate space for the new node */ + if(NULL == (new_node = H5FL_MALLOC(H5S_pnt_node_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node") + + /* Initialize fields in node */ + new_node->next = NULL; + if(NULL == (new_node->pnt = (hsize_t *)H5MM_malloc(space->extent.rank * sizeof(hsize_t)))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate coordinate information") + + /* Copy over the coordinates */ + HDmemcpy(new_node->pnt, coord + (u * space->extent.rank), (space->extent.rank * sizeof(hsize_t))); + + /* Link into list */ + if(top == NULL) + top = new_node; + else + curr->next = new_node; + curr = new_node; + } /* end for */ + new_node = NULL; + + /* Insert the list of points selected in the proper place */ + if(op == H5S_SELECT_SET || op == H5S_SELECT_PREPEND) { + /* Append current list, if there is one */ + if(space->select.sel_info.pnt_lst->head != NULL) + curr->next = space->select.sel_info.pnt_lst->head; + + /* Put new list in point selection */ + space->select.sel_info.pnt_lst->head = top; + } /* end if */ + else { /* op==H5S_SELECT_APPEND */ + H5S_pnt_node_t *tmp_node; /* Temporary point selection node */ + + tmp_node = space->select.sel_info.pnt_lst->head; + if(tmp_node != NULL) { + while(tmp_node->next != NULL) + tmp_node = tmp_node->next; + + /* Append new list to point selection */ + tmp_node->next = top; + } /* end if */ + else + space->select.sel_info.pnt_lst->head = top; + } /* end else */ + + /* Set the number of elements in the new selection */ + if(op == H5S_SELECT_SET) + space->select.num_elem = num_elem; + else + space->select.num_elem += num_elem; + +done: + if(ret_value < 0) { + /* Release possibly partially initialized new node */ + if(new_node) + new_node = H5FL_FREE(H5S_pnt_node_t, new_node); + + /* Release possible linked list of nodes */ + while(top) { + curr = top->next; + H5MM_xfree(top->pnt); + top = H5FL_FREE(H5S_pnt_node_t, top); + top = curr; + } /* end while */ + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_point_add() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_release + PURPOSE + Release point selection information for a dataspace + USAGE + herr_t H5S_point_release(space) + H5S_t *space; IN: Pointer to dataspace + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Releases all point selection information for a dataspace + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_point_release (H5S_t *space) +{ + H5S_pnt_node_t *curr, *next; /* Point selection nodes */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(space); + + /* Delete all the nodes from the list */ + curr = space->select.sel_info.pnt_lst->head; + while(curr != NULL) { + next = curr->next; + H5MM_xfree(curr->pnt); + curr = H5FL_FREE(H5S_pnt_node_t, curr); + curr = next; + } /* end while */ + + /* Free & reset the point list header */ + space->select.sel_info.pnt_lst = H5FL_FREE(H5S_pnt_list_t, space->select.sel_info.pnt_lst); + + /* Reset the number of elements in the selection */ + space->select.num_elem = 0; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_point_release() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_select_elements + PURPOSE + Specify a series of elements in the dataspace to select + USAGE + herr_t H5S_select_elements(dsid, op, num_elem, coord) + hid_t dsid; IN: Dataspace ID of selection to modify + H5S_seloper_t op; IN: Operation to perform on current selection + size_t num_elem; IN: Number of elements in COORD array. + const hsize_t *coord; IN: The location of each element selected + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + This function selects array elements to be included in the selection for + the dataspace. The COORD array is a 2-D array of size <dataspace rank> + by NUM_ELEM (ie. a list of coordinates in the dataspace). The order of + the element coordinates in the COORD array specifies the order that the + array elements are iterated through when I/O is performed. Duplicate + coordinates are not checked for. The selection operator, OP, determines + how the new selection is to be combined with the existing selection for + the dataspace. Currently, only H5S_SELECT_SET is supported, which replaces + the existing selection with the one defined in this call. When operators + other than H5S_SELECT_SET are used to combine a new selection with an + existing selection, the selection ordering is reset to 'C' array ordering. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5S_select_elements(H5S_t *space, H5S_seloper_t op, size_t num_elem, + const hsize_t *coord) +{ + herr_t ret_value = SUCCEED; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Check args */ + HDassert(space); + HDassert(num_elem); + HDassert(coord); + HDassert(op == H5S_SELECT_SET || op == H5S_SELECT_APPEND || op == H5S_SELECT_PREPEND); + + /* If we are setting a new selection, remove current selection first */ + if(op == H5S_SELECT_SET || H5S_GET_SELECT_TYPE(space) != H5S_SEL_POINTS) + if(H5S_SELECT_RELEASE(space) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release point selection") + + /* Allocate space for the point selection information if necessary */ + if(H5S_GET_SELECT_TYPE(space) != H5S_SEL_POINTS || space->select.sel_info.pnt_lst == NULL) + if(NULL == (space->select.sel_info.pnt_lst = H5FL_CALLOC(H5S_pnt_list_t))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate element information") + + /* Add points to selection */ + if(H5S_point_add(space, op, num_elem, coord) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert elements") + + /* Set selection type */ + space->select.type = H5S_sel_point; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_select_elements() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_copy + PURPOSE + Copy a selection from one dataspace to another + USAGE + herr_t H5S_point_copy(dst, src) + H5S_t *dst; OUT: Pointer to the destination dataspace + H5S_t *src; IN: Pointer to the source dataspace + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + Copies all the point selection information from the source + dataspace to the destination dataspace. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_point_copy(H5S_t *dst, const H5S_t *src, hbool_t H5_ATTR_UNUSED share_selection) +{ + H5S_pnt_node_t *curr, *new_node, *new_tail; /* Point information nodes */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(src); + HDassert(dst); + + /* Allocate room for the head of the point list */ + if(NULL == (dst->select.sel_info.pnt_lst = H5FL_MALLOC(H5S_pnt_list_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point list node") + + curr = src->select.sel_info.pnt_lst->head; + new_tail = NULL; + while(curr) { + /* Create new point */ + if(NULL == (new_node = H5FL_MALLOC(H5S_pnt_node_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node") + new_node->next = NULL; + if(NULL == (new_node->pnt = (hsize_t *)H5MM_malloc(src->extent.rank * sizeof(hsize_t)))) { + new_node = H5FL_FREE(H5S_pnt_node_t, new_node); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate coordinate information") + } /* end if */ + + /* Copy over the point's coordinates */ + HDmemcpy(new_node->pnt, curr->pnt, (src->extent.rank * sizeof(hsize_t))); + + /* Keep the order the same when copying */ + if(NULL == new_tail) + new_tail = dst->select.sel_info.pnt_lst->head = new_node; + else { + new_tail->next = new_node; + new_tail = new_node; + } /* end else */ + + curr = curr->next; + } /* end while */ + +done: + if(ret_value < 0 && dst->select.sel_info.pnt_lst) { + /* Traverse the (incomplete?) dst list, freeing all memory */ + curr = dst->select.sel_info.pnt_lst->head; + while(curr) { + H5S_pnt_node_t *tmp_node = curr; + + curr->pnt = (hsize_t *)H5MM_xfree(curr->pnt); + curr = curr->next; + tmp_node = H5FL_FREE(H5S_pnt_node_t, tmp_node); + } /* end while */ + + dst->select.sel_info.pnt_lst = H5FL_FREE(H5S_pnt_list_t, dst->select.sel_info.pnt_lst); + } /* end if */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_point_copy() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_is_valid + PURPOSE + Check whether the selection fits within the extent, with the current + offset defined. + USAGE + htri_t H5S_point_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_point_is_valid (const H5S_t *space) +{ + H5S_pnt_node_t *curr; /* Point information nodes */ + unsigned u; /* Counter */ + htri_t ret_value=TRUE; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(space); + + /* Check each point to determine whether selection+offset is within extent */ + curr = space->select.sel_info.pnt_lst->head; + while(curr != NULL) { + /* Check each dimension */ + for(u = 0; u < space->extent.rank; u++) { + /* Check if an offset has been defined */ + /* Bounds check the selected point + offset against the extent */ + if(((curr->pnt[u] + (hsize_t)space->select.offset[u]) > space->extent.size[u]) + || (((hssize_t)curr->pnt[u] + space->select.offset[u]) < 0)) + HGOTO_DONE(FALSE) + } /* end for */ + + curr = curr->next; + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_point_is_valid() */ + + +/*-------------------------------------------------------------------------- + NAME + H5Sget_select_elem_npoints + PURPOSE + Get the number of points in current element selection + USAGE + hssize_t H5Sget_select_elem_npoints(dsid) + hid_t dsid; IN: Dataspace ID of selection to query + RETURNS + The number of element points in selection on success, negative on failure + DESCRIPTION + Returns the number of element points in current selection for dataspace. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +hssize_t +H5Sget_select_elem_npoints(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_POINTS) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not an element selection") + + ret_value = (hssize_t)H5S_GET_SELECT_NPOINTS(space); + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Sget_select_elem_npoints() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_serial_size + PURPOSE + Determine the number of bytes needed to store the serialized point selection + information. + USAGE + hssize_t H5S_point_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 point + selection information for storage on disk. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static hssize_t +H5S_point_serial_size (const H5S_t *space) +{ + H5S_pnt_node_t *curr; /* Point information nodes */ + hssize_t ret_value = -1; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(space); + + /* Basic number of bytes required to serialize point selection: + * <type (4 bytes)> + <version (4 bytes)> + <padding (4 bytes)> + + * <length (4 bytes)> + <rank (4 bytes)> + <# of points (4 bytes)> = 24 bytes + */ + ret_value=24; + + /* Count points in selection */ + curr=space->select.sel_info.pnt_lst->head; + while(curr!=NULL) { + /* Add 4 bytes times the rank for each element selected */ + ret_value+=4*space->extent.rank; + curr=curr->next; + } /* end while */ + + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_point_serial_size() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_serialize + PURPOSE + Serialize the current selection into a user-provided buffer. + USAGE + herr_t H5S_point_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_point_serialize (const H5S_t *space, uint8_t **p) +{ + H5S_pnt_node_t *curr; /* Point information nodes */ + uint8_t *pp = (*p); /* Local pointer for decoding */ + uint8_t *lenp; /* pointer to length location for later storage */ + uint32_t len=0; /* number of bytes used */ + unsigned u; /* local counting variable */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + /* Check args */ + HDassert(space); + HDassert(p); + HDassert(pp); + + /* Store the preamble information */ + UINT32ENCODE(pp, (uint32_t)H5S_GET_SELECT_TYPE(space)); /* Store the type of selection */ + UINT32ENCODE(pp, (uint32_t)1); /* Store the version number */ + 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; + + /* Encode number of elements */ + UINT32ENCODE(pp, (uint32_t)space->select.num_elem); + len+=4; + + /* Encode each point in selection */ + curr=space->select.sel_info.pnt_lst->head; + while(curr!=NULL) { + /* Add 4 bytes times the rank for each element selected */ + len+=4*space->extent.rank; + + /* Encode each point */ + for(u=0; u<space->extent.rank; u++) + UINT32ENCODE(pp, (uint32_t)curr->pnt[u]); + + curr=curr->next; + } /* end while */ + + /* Encode length */ + UINT32ENCODE(lenp, (uint32_t)len); /* Store the length of the extra information */ + + /* Update encoding pointer */ + *p = pp; + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_point_serialize() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_deserialize + PURPOSE + Deserialize the current selection from a user-provided buffer. + USAGE + herr_t H5S_point_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_point_deserialize(H5S_t *space, uint32_t H5_ATTR_UNUSED version, uint8_t H5_ATTR_UNUSED flags, + const uint8_t **p) +{ + H5S_seloper_t op = H5S_SELECT_SET; /* Selection operation */ + hsize_t *coord = NULL, *tcoord; /* Pointer to array of elements */ + const uint8_t *pp = (*p); /* Local pointer for decoding */ + size_t num_elem = 0; /* Number of elements in selection */ + unsigned rank; /* Rank of points */ + unsigned i, j; /* local counting variables */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Check args */ + HDassert(space); + HDassert(p); + HDassert(pp); + + /* Deserialize points to select */ + /* (The header and rank have already beed decoded) */ + rank = space->extent.rank; /* Retrieve rank from space */ + UINT32DECODE(pp, num_elem); /* decode the number of points */ + + /* Allocate space for the coordinates */ + if(NULL == (coord = (hsize_t *)H5MM_malloc(num_elem * rank * sizeof(hsize_t)))) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate coordinate information") + + /* Retrieve the coordinates from the buffer */ + for(tcoord = coord, i = 0; i < num_elem; i++) + for(j = 0; j < (unsigned)rank; j++, tcoord++) + UINT32DECODE(pp, *tcoord); + + /* Select points */ + if(H5S_select_elements(space, op, num_elem, (const hsize_t *)coord) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection") + + /* Update decoding pointer */ + *p = pp; + +done: + /* Free the coordinate array if necessary */ + if(coord != NULL) + H5MM_xfree(coord); + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_point_deserialize() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_get_select_elem_pointlist + PURPOSE + Get the list of element points currently selected + USAGE + herr_t H5S_get_select_elem_pointlist(space, hsize_t *buf) + H5S_t *space; IN: Dataspace pointer of selection to query + hsize_t startpoint; IN: Element point to start with + hsize_t numpoints; IN: Number of element points to get + hsize_t *buf; OUT: List of element points selected + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Puts a list of the element points into the user's buffer. The points + start with the 'startpoint'th block in the list of points and put + 'numpoints' number of points into the user's buffer (or until the end of + the list of points, whichever happen first) + The point coordinates have the same dimensionality (rank) as the + dataspace they are located within. The list of points is formatted as + follows: <coordinate> followed by the next coordinate, etc. until all the + point information in the selection have been put into the user's buffer. + The points are returned in the order they will be interated through + when a selection is read/written from/to disk. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_get_select_elem_pointlist(H5S_t *space, hsize_t startpoint, hsize_t numpoints, hsize_t *buf) +{ + H5S_pnt_node_t *node; /* Point node */ + unsigned rank; /* Dataspace rank */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(space); + HDassert(buf); + + /* Get the dataspace extent rank */ + rank = space->extent.rank; + + /* Get the head of the point list */ + node = space->select.sel_info.pnt_lst->head; + + /* Iterate to the first point to return */ + while(node != NULL && startpoint > 0) { + startpoint--; + node = node->next; + } /* end while */ + + /* Iterate through the node, copying each point's information */ + while(node != NULL && numpoints > 0) { + HDmemcpy(buf, node->pnt, sizeof(hsize_t) * rank); + buf += rank; + numpoints--; + node = node->next; + } /* end while */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_get_select_elem_pointlist() */ + + +/*-------------------------------------------------------------------------- + NAME + H5Sget_select_elem_pointlist + PURPOSE + Get the list of element points currently selected + USAGE + herr_t H5Sget_select_elem_pointlist(dsid, hsize_t *buf) + hid_t dsid; IN: Dataspace ID of selection to query + hsize_t startpoint; IN: Element point to start with + hsize_t numpoints; IN: Number of element points to get + hsize_t buf[]; OUT: List of element points selected + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Puts a list of the element points into the user's buffer. The points + start with the 'startpoint'th block in the list of points and put + 'numpoints' number of points into the user's buffer (or until the end of + the list of points, whichever happen first) + The point coordinates have the same dimensionality (rank) as the + dataspace they are located within. The list of points is formatted as + follows: <coordinate> followed by the next coordinate, etc. until all the + point information in the selection have been put into the user's buffer. + The points are returned in the order they will be interated through + when a selection is read/written from/to disk. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5Sget_select_elem_pointlist(hid_t spaceid, hsize_t startpoint, + hsize_t numpoints, hsize_t buf[/*numpoints*/]) +{ + H5S_t *space; /* Dataspace to modify selection of */ + herr_t ret_value; /* return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE4("e", "ihh*[a2]h", spaceid, startpoint, numpoints, buf); + + /* Check args */ + if(NULL == buf) + 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_POINTS) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a point selection") + + ret_value = H5S_get_select_elem_pointlist(space, startpoint, numpoints, buf); + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Sget_select_elem_pointlist() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_bounds + PURPOSE + Gets the bounding box containing the selection. + USAGE + herr_t H5S_point_bounds(space, start, 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_point_bounds(const H5S_t *space, hsize_t *start, hsize_t *end) +{ + H5S_pnt_node_t *node; /* Point node */ + unsigned rank; /* Dataspace rank */ + unsigned u; /* index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + HDassert(space); + HDassert(start); + HDassert(end); + + /* Get the dataspace extent rank */ + rank = space->extent.rank; + + /* Set the start and end arrays up */ + for(u = 0; u < rank; u++) { + start[u] = HSIZET_MAX; + end[u] = 0; + } /* end for */ + + /* Iterate through the node, checking the bounds on each element */ + node = space->select.sel_info.pnt_lst->head; + while(node != NULL) { + for(u = 0; u < rank; u++) { + /* Check for offset moving selection negative */ + if(((hssize_t)node->pnt[u] + space->select.offset[u]) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds") + + if(start[u] > (hsize_t)((hssize_t)node->pnt[u] + space->select.offset[u])) + start[u] = (hsize_t)((hssize_t)node->pnt[u] + space->select.offset[u]); + if(end[u] < (hsize_t)((hssize_t)node->pnt[u] + space->select.offset[u])) + end[u] = (hsize_t)((hssize_t)node->pnt[u] + space->select.offset[u]); + } /* end for */ + node = node->next; + } /* end while */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_point_bounds() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_offset + PURPOSE + Gets the linear offset of the first element for the selection. + USAGE + herr_t H5S_point_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_point_offset(const H5S_t *space, hsize_t *offset) +{ + const hsize_t *pnt; /* Pointer to a selected point's coordinates */ + 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 */ + int i; /* index variable */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI(FAIL) + + HDassert(space); + HDassert(offset); + + /* Start at linear offset 0 */ + *offset = 0; + + /* Set up pointers to arrays of values */ + pnt = space->select.sel_info.pnt_lst->head->pnt; + sel_offset = space->select.offset; + dim_size = space->extent.size; + + /* Loop through coordinates, calculating the linear offset */ + accum = 1; + for(i = (int)space->extent.rank - 1; i >= 0; i--) { + hssize_t pnt_offset = (hssize_t)pnt[i] + sel_offset[i]; /* Point's offset in this dimension */ + + /* Check for offset moving selection out of the dataspace */ + if(pnt_offset < 0 || (hsize_t)pnt_offset >= dim_size[i]) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds") + + /* Add the point's offset in this dimension to the total linear offset */ + *offset += (hsize_t)pnt_offset * accum; + + /* Increase the accumulator */ + accum *= dim_size[i]; + } /* end for */ + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_point_offset() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S__point_unlim_dim + PURPOSE + Return unlimited dimension of selection, or -1 if none + USAGE + int H5S__point_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 in this selection, or -1 + if the selection has no unlimited dimension. Currently point + selections cannot have an unlimited dimension, so this function always + returns -1. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static int +H5S__point_unlim_dim(const H5S_t H5_ATTR_UNUSED *space) +{ + FUNC_ENTER_STATIC_NOERR + + FUNC_LEAVE_NOAPI(-1) +} /* end H5S__point_unlim_dim() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_is_contiguous + PURPOSE + Check if a point selection is contiguous within the dataspace extent. + USAGE + htri_t H5S_point_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. + This code currently doesn't properly check for contiguousness when there is + more than one point, as that would take a lot of extra coding that we + don't need now. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static htri_t +H5S_point_is_contiguous(const H5S_t *space) +{ + htri_t ret_value = FAIL; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(space); + + /* One point is definitely contiguous */ + if(space->select.num_elem==1) + ret_value=TRUE; + else /* More than one point might be contiguous, but it's complex to check and we don't need it right now */ + ret_value=FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_point_is_contiguous() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_is_single + PURPOSE + Check if a point selection is single within the dataspace extent. + USAGE + htri_t H5S_point_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_point_is_single(const H5S_t *space) +{ + htri_t ret_value = FAIL; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(space); + + /* One point is definitely 'single' :-) */ + if(space->select.num_elem==1) + ret_value=TRUE; + else + ret_value=FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_point_is_single() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_is_regular + PURPOSE + Check if a point selection is "regular" + USAGE + htri_t H5S_point_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 points selected to be next to one another in a regular + pattern yet. + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static htri_t +H5S_point_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 points for now... */ + if(space->select.num_elem==1) + ret_value=TRUE; + else + ret_value=FALSE; + + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_point_is_regular() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_adjust_u + PURPOSE + Adjust a "point" selection by subtracting an offset + USAGE + herr_t H5S_point_adjust_u(space, offset) + H5S_t *space; IN/OUT: Pointer to dataspace to adjust + const hsize_t *offset; IN: Offset to subtract + RETURNS + Non-negative on success, negative on failure + DESCRIPTION + Moves a point selection by subtracting an offset from it. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_point_adjust_u(H5S_t *space, const hsize_t *offset) +{ + H5S_pnt_node_t *node; /* Point node */ + unsigned rank; /* Dataspace rank */ + + FUNC_ENTER_NOAPI_NOINIT_NOERR + + HDassert(space); + HDassert(offset); + + /* Iterate through the nodes, checking the bounds on each element */ + node = space->select.sel_info.pnt_lst->head; + rank = space->extent.rank; + while(node) { + unsigned u; /* Local index variable */ + + /* Adjust each coordinate for point node */ + for(u = 0; u < rank; u++) { + /* Check for offset moving selection negative */ + HDassert(node->pnt[u] >= offset[u]); + + /* Adjust node's coordinate location */ + node->pnt[u] -= offset[u]; + } /* end for */ + + /* Advance to next point node in selection */ + node = node->next; + } /* end while */ + + FUNC_LEAVE_NOAPI(SUCCEED) +} /* H5S_point_adjust_u() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_point_project_scalar + * + * Purpose: Projects a single element point selection into a scalar + * dataspace + * + * Return: non-negative on success, negative on failure. + * + * Programmer: Quincey Koziol + * Sunday, July 18, 2010 + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_point_project_scalar(const H5S_t *space, hsize_t *offset) +{ + const H5S_pnt_node_t *node; /* Point node */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Check args */ + HDassert(space && H5S_SEL_POINTS == H5S_GET_SELECT_TYPE(space)); + HDassert(offset); + + /* Get the head of the point list */ + node = space->select.sel_info.pnt_lst->head; + + /* Check for more than one point selected */ + if(node->next) + HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "point selection of one element has more than one node!") + + /* Calculate offset of selection in projected buffer */ + *offset = H5VM_array_offset(space->extent.rank, space->extent.size, node->pnt); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_point_project_scalar() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_point_project_simple + * + * Purpose: Projects a point 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_point_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *offset) +{ + const H5S_pnt_node_t *base_node; /* Point node in base space */ + H5S_pnt_node_t *new_node; /* Point node in new space */ + H5S_pnt_node_t *prev_node; /* Previous point node in new space */ + unsigned rank_diff; /* Difference in ranks between spaces */ + herr_t ret_value = SUCCEED; /* Return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Check args */ + HDassert(base_space && H5S_SEL_POINTS == 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 room for the head of the point list */ + if(NULL == (new_space->select.sel_info.pnt_lst = H5FL_MALLOC(H5S_pnt_list_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point list node") + + /* Check if the new space's rank is < or > base space's rank */ + if(new_space->extent.rank < base_space->extent.rank) { + hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */ + + /* Compute the difference in ranks */ + rank_diff = base_space->extent.rank - new_space->extent.rank; + + /* Calculate offset of selection in projected buffer */ + HDmemset(block, 0, sizeof(block)); + HDmemcpy(block, base_space->select.sel_info.pnt_lst->head->pnt, sizeof(hsize_t) * rank_diff); + *offset = H5VM_array_offset(base_space->extent.rank, base_space->extent.size, block); + + /* Iterate through base space's point nodes, copying the point information */ + base_node = base_space->select.sel_info.pnt_lst->head; + prev_node = NULL; + while(base_node) { + /* Create new point */ + if(NULL == (new_node = H5FL_MALLOC(H5S_pnt_node_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node") + new_node->next = NULL; + if(NULL == (new_node->pnt = (hsize_t *)H5MM_malloc(new_space->extent.rank * sizeof(hsize_t)))) { + new_node = H5FL_FREE(H5S_pnt_node_t, new_node); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate coordinate information") + } /* end if */ + + /* Copy over the point's coordinates */ + HDmemcpy(new_node->pnt, &base_node->pnt[rank_diff], (new_space->extent.rank * sizeof(hsize_t))); + + /* Keep the order the same when copying */ + if(NULL == prev_node) + prev_node = new_space->select.sel_info.pnt_lst->head = new_node; + else { + prev_node->next = new_node; + prev_node = new_node; + } /* end else */ + + /* Advance to next node */ + base_node = base_node->next; + } /* end while */ + } /* end if */ + else { + HDassert(new_space->extent.rank > base_space->extent.rank); + + /* Compute the difference in ranks */ + rank_diff = new_space->extent.rank - base_space->extent.rank; + + /* The offset is zero when projected into higher dimensions */ + *offset = 0; + + /* Iterate through base space's point nodes, copying the point information */ + base_node = base_space->select.sel_info.pnt_lst->head; + prev_node = NULL; + while(base_node) { + /* Create new point */ + if(NULL == (new_node = H5FL_MALLOC(H5S_pnt_node_t))) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node") + new_node->next = NULL; + if(NULL == (new_node->pnt = (hsize_t *)H5MM_malloc(new_space->extent.rank * sizeof(hsize_t)))) { + new_node = H5FL_FREE(H5S_pnt_node_t, new_node); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate coordinate information") + } /* end if */ + + /* Copy over the point's coordinates */ + HDmemset(new_node->pnt, 0, sizeof(hsize_t) * rank_diff); + HDmemcpy(&new_node->pnt[rank_diff], base_node->pnt, (new_space->extent.rank * sizeof(hsize_t))); + + /* Keep the order the same when copying */ + if(NULL == prev_node) + prev_node = new_space->select.sel_info.pnt_lst->head = new_node; + else { + prev_node->next = new_node; + prev_node = new_node; + } /* end else */ + + /* Advance to next node */ + base_node = base_node->next; + } /* end while */ + } /* 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_point; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* H5S_point_project_simple() */ + + +/*-------------------------------------------------------------------------- + NAME + H5Sselect_elements + PURPOSE + Specify a series of elements in the dataspace to select + USAGE + herr_t H5Sselect_elements(dsid, op, num_elem, coord) + hid_t dsid; IN: Dataspace ID of selection to modify + H5S_seloper_t op; IN: Operation to perform on current selection + size_t num_elem; IN: Number of elements in COORD array. + const hsize_t *coord; IN: The location of each element selected + RETURNS + Non-negative on success/Negative on failure + DESCRIPTION + This function selects array elements to be included in the selection for + the dataspace. The COORD array is a 2-D array of size <dataspace rank> + by NUM_ELEM (ie. a list of coordinates in the dataspace). The order of + the element coordinates in the COORD array specifies the order that the + array elements are iterated through when I/O is performed. Duplicate + coordinates are not checked for. The selection operator, OP, determines + how the new selection is to be combined with the existing selection for + the dataspace. Currently, only H5S_SELECT_SET is supported, which replaces + the existing selection with the one defined in this call. When operators + other than H5S_SELECT_SET are used to combine a new selection with an + existing selection, the selection ordering is reset to 'C' array ordering. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5Sselect_elements(hid_t spaceid, H5S_seloper_t op, size_t num_elem, + const hsize_t *coord) +{ + H5S_t *space; /* Dataspace to modify selection of */ + herr_t ret_value; /* Return value */ + + FUNC_ENTER_API(FAIL) + H5TRACE4("e", "iSsz*h", spaceid, op, num_elem, coord); + + /* 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_SCALAR == H5S_GET_EXTENT_TYPE(space)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "point doesn't support H5S_SCALAR space") + if(H5S_NULL == H5S_GET_EXTENT_TYPE(space)) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "point doesn't support H5S_NULL space") + if(coord == NULL || num_elem == 0) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "elements not specified") + if(!(op == H5S_SELECT_SET || op == H5S_SELECT_APPEND || op == H5S_SELECT_PREPEND)) + HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "unsupported operation attempted") + + /* Call the real element selection routine */ + if((ret_value = H5S_select_elements(space, op, num_elem, coord)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't select elements") + +done: + FUNC_LEAVE_API(ret_value) +} /* H5Sselect_elements() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_point_get_seq_list + PURPOSE + Create a list of offsets & lengths for a selection + USAGE + herr_t H5S_point_get_seq_list(space,flags,iter,maxseq,maxelem,nseq,nelem,off,len) + H5S_t *space; IN: Dataspace containing selection to use. + unsigned flags; IN: Flags for extra information about operation + H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last + position of interest in selection. + size_t maxseq; IN: Maximum number of sequences to generate + size_t maxelem; IN: Maximum number of elements to include in the + generated sequences + size_t *nseq; OUT: Actual number of sequences generated + size_t *nelem; OUT: Actual number of elements in sequences generated + hsize_t *off; OUT: Array of offsets + size_t *len; OUT: Array of lengths + RETURNS + Non-negative on success/Negative on failure. + DESCRIPTION + Use the selection in the dataspace to generate a list of byte offsets and + lengths for the region(s) selected. Start/Restart from the position in the + ITER parameter. The number of sequences generated is limited by the MAXSEQ + parameter and the number of sequences actually generated is stored in the + NSEQ parameter. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +static herr_t +H5S_point_get_seq_list(const H5S_t *space, unsigned flags, H5S_sel_iter_t *iter, + size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem, + hsize_t *off, size_t *len) +{ + size_t io_left; /* The number of bytes left in the selection */ + size_t start_io_left; /* The initial number of bytes left in the selection */ + H5S_pnt_node_t *node; /* Point node */ + hsize_t dims[H5O_LAYOUT_NDIMS]; /* Total size of memory buf */ + int ndims; /* Dimensionality of space*/ + hsize_t acc; /* Coordinate accumulator */ + hsize_t loc; /* Coordinate offset */ + size_t curr_seq; /* Current sequence being operated on */ + int i; /* Local index variable */ + herr_t ret_value=SUCCEED; /* return value */ + + FUNC_ENTER_NOAPI_NOINIT + + /* Check args */ + HDassert(space); + HDassert(iter); + HDassert(maxseq > 0); + HDassert(maxelem > 0); + HDassert(nseq); + HDassert(nelem); + HDassert(off); + HDassert(len); + + /* Choose the minimum number of bytes to sequence through */ + H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t); + start_io_left = io_left = (size_t)MIN(iter->elmt_left, maxelem); + + /* Get the dataspace dimensions */ + if((ndims = H5S_get_simple_extent_dims (space, dims, NULL)) < 0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to retrieve data space dimensions") + + /* Walk through the points in the selection, starting at the current */ + /* location in the iterator */ + node = iter->u.pnt.curr; + curr_seq = 0; + while(NULL != node) { + /* Compute the offset of each selected point in the buffer */ + for(i = ndims - 1, acc = iter->elmt_size, loc = 0; i >= 0; i--) { + loc += (hsize_t)((hssize_t)node->pnt[i] + space->select.offset[i]) * acc; + acc *= dims[i]; + } /* end for */ + + /* Check if this is a later point in the selection */ + if(curr_seq>0) { + /* If a sorted sequence is requested, make certain we don't go backwards in the offset */ + if((flags&H5S_GET_SEQ_LIST_SORTED) && loc<off[curr_seq-1]) + break; + + /* Check if this point extends the previous sequence */ + /* (Unlikely, but possible) */ + if(loc==(off[curr_seq-1]+len[curr_seq-1])) { + /* Extend the previous sequence */ + len[curr_seq-1]+=iter->elmt_size; + } /* end if */ + else { + /* Add a new sequence */ + off[curr_seq]=loc; + len[curr_seq]=iter->elmt_size; + + /* Increment sequence count */ + curr_seq++; + } /* end else */ + } /* end if */ + else { + /* Add a new sequence */ + off[curr_seq]=loc; + len[curr_seq]=iter->elmt_size; + + /* Increment sequence count */ + curr_seq++; + } /* end else */ + + /* Decrement number of elements left to process */ + io_left--; + + /* Move the iterator */ + iter->u.pnt.curr=node->next; + iter->elmt_left--; + + /* Check if we're finished with all sequences */ + if(curr_seq==maxseq) + break; + + /* Check if we're finished with all the elements available */ + if(io_left==0) + break; + + /* Advance to the next point */ + node=node->next; + } /* end while */ + + /* Set the number of sequences generated */ + *nseq=curr_seq; + + /* Set the number of elements used */ + *nelem=start_io_left-io_left; + +done: + FUNC_LEAVE_NOAPI(ret_value) +} /* end H5S_point_get_seq_list() */ + |