#include "H5Smodule.h"
#include "H5private.h"
#include "H5Eprivate.h"
#include "H5FLprivate.h"
#include "H5Iprivate.h"
#include "H5MMprivate.h"
#include "H5Spkg.h"
#include "H5VMprivate.h"
typedef hsize_t hcoords_t;
static herr_t H5S__point_add(H5S_t *space, H5S_seloper_t op, size_t num_elem,
const hsize_t *coord);
static H5S_pnt_list_t *H5S__copy_pnt_list(const H5S_pnt_list_t *src,
unsigned rank);
static void H5S__free_pnt_list(H5S_pnt_list_t *pnt_lst);
static herr_t H5S__point_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection);
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, 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 htri_t H5S__point_shape_same(const H5S_t *space1, const H5S_t *space2);
static htri_t H5S__point_intersect_block(const H5S_t *space, const hsize_t *start, const hsize_t *end);
static herr_t H5S__point_adjust_u(H5S_t *space, const hsize_t *offset);
static herr_t H5S__point_adjust_s(H5S_t *space, const hssize_t *offset);
static herr_t H5S__point_project_scalar(const H5S_t *space, hsize_t *offset);
static herr_t H5S__point_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset);
static herr_t H5S__point_iter_init(const H5S_t *space, H5S_sel_iter_t *iter);
static herr_t H5S__point_get_version_enc_size(const H5S_t *space, uint32_t *version, uint8_t *enc_size);
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_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq,
size_t maxbytes, size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len);
static herr_t H5S__point_iter_release(H5S_sel_iter_t *sel_iter);
const H5S_select_class_t H5S_sel_point[1] = {{
H5S_SEL_POINTS,
H5S__point_copy,
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_shape_same,
H5S__point_intersect_block,
H5S__point_adjust_u,
H5S__point_adjust_s,
H5S__point_project_scalar,
H5S__point_project_simple,
H5S__point_iter_init,
}};
static const H5S_sel_iter_class_t H5S_sel_iter_point[1] = {{
H5S_SEL_POINTS,
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_get_seq_list,
H5S__point_iter_release,
}};
H5FL_BARR_DEFINE_STATIC(H5S_pnt_node_t, hcoords_t, H5S_MAX_RANK);
H5FL_DEFINE_STATIC(H5S_pnt_list_t);
static herr_t
H5S__point_iter_init(const H5S_t *space, H5S_sel_iter_t *iter)
{
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
HDassert(space && H5S_SEL_POINTS == H5S_GET_SELECT_TYPE(space));
HDassert(iter);
if((iter->flags & H5S_SEL_ITER_API_CALL) &&
!(iter->flags & H5S_SEL_ITER_SHARE_WITH_DATASPACE)) {
if(NULL == (iter->u.pnt.pnt_lst = H5S__copy_pnt_list(space->select.sel_info.pnt_lst, space->extent.rank)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy point list")
}
else
iter->u.pnt.pnt_lst = space->select.sel_info.pnt_lst;
iter->u.pnt.curr = iter->u.pnt.pnt_lst->head;
iter->type = H5S_sel_iter_point;
done:
FUNC_LEAVE_NOAPI(ret_value)
}
static herr_t
H5S__point_iter_coords(const H5S_sel_iter_t *iter, hsize_t *coords)
{
FUNC_ENTER_STATIC_NOERR
HDassert(iter);
HDassert(coords);
H5MM_memcpy(coords, iter->u.pnt.curr->pnt, sizeof(hsize_t) * iter->rank);
FUNC_LEAVE_NOAPI(SUCCEED)
}
static herr_t
H5S__point_iter_block(const H5S_sel_iter_t *iter, hsize_t *start, hsize_t *end)
{
FUNC_ENTER_STATIC_NOERR
HDassert(iter);
HDassert(start);
HDassert(end);
H5MM_memcpy(start, iter->u.pnt.curr->pnt, sizeof(hsize_t) * iter->rank);
H5MM_memcpy(end, iter->u.pnt.curr->pnt, sizeof(hsize_t) * iter->rank);
FUNC_LEAVE_NOAPI(SUCCEED)
}
static hsize_t
H5S__point_iter_nelmts(const H5S_sel_iter_t *iter)
{
FUNC_ENTER_STATIC_NOERR
HDassert(iter);
FUNC_LEAVE_NOAPI(iter->elmt_left)
}
static htri_t
H5S__point_iter_has_next_block(const H5S_sel_iter_t *iter)
{
htri_t ret_value = TRUE;
FUNC_ENTER_STATIC_NOERR
HDassert(iter);
if(iter->u.pnt.curr->next == NULL)
HGOTO_DONE(FALSE);
done:
FUNC_LEAVE_NOAPI(ret_value)
}
static herr_t
H5S__point_iter_next(H5S_sel_iter_t *iter, size_t nelem)
{
FUNC_ENTER_STATIC_NOERR
HDassert(iter);
HDassert(nelem > 0);
while(nelem > 0) {
iter->u.pnt.curr = iter->u.pnt.curr->next;
nelem--;
}
FUNC_LEAVE_NOAPI(SUCCEED)
}
static herr_t
H5S__point_iter_next_block(H5S_sel_iter_t *iter)
{
FUNC_ENTER_STATIC_NOERR
HDassert(iter);
iter->u.pnt.curr = iter->u.pnt.curr->next;
FUNC_LEAVE_NOAPI(SUCCEED)
}
static herr_t
H5S__point_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem,
size_t *nseq, size_t *nelem, hsize_t *off, size_t *len)
{
size_t io_left;
size_t start_io_left;
H5S_pnt_node_t *node;
unsigned ndims;
hsize_t acc;
hsize_t loc;
size_t curr_seq;
int i;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC_NOERR
HDassert(iter);
HDassert(maxseq > 0);
HDassert(maxelem > 0);
HDassert(nseq);
HDassert(nelem);
HDassert(off);
HDassert(len);
H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t);
start_io_left = io_left = (size_t)MIN(iter->elmt_left, maxelem);
ndims = iter->rank;
node = iter->u.pnt.curr;
curr_seq = 0;
while(NULL != node) {
for(i = (int)(ndims - 1), acc = iter->elmt_size, loc = 0; i >= 0; i--) {
loc += (hsize_t)((hssize_t)node->pnt[i] + iter->sel_off[i]) * acc;
acc *= iter->dims[i];
}
if(curr_seq > 0) {
if((iter->flags & H5S_SEL_ITER_GET_SEQ_LIST_SORTED) && loc < off[curr_seq - 1])
break;
if(loc == (off[curr_seq - 1] + len[curr_seq - 1])) {
len[curr_seq - 1] += iter->elmt_size;
}
else {
off[curr_seq] = loc;
len[curr_seq] = iter->elmt_size;
curr_seq++;
}
}
else {
off[curr_seq] = loc;
len[curr_seq] = iter->elmt_size;
curr_seq++;
}
io_left--;
iter->u.pnt.curr = node->next;
iter->elmt_left--;
if(curr_seq == maxseq)
break;
if(io_left == 0)
break;
node = node->next;
}
*nseq = curr_seq;
*nelem = start_io_left - io_left;
FUNC_LEAVE_NOAPI(ret_value)
}
static herr_t
H5S__point_iter_release(H5S_sel_iter_t * iter)
{
FUNC_ENTER_STATIC_NOERR
HDassert(iter);
if((iter->flags & H5S_SEL_ITER_API_CALL) &&
!(iter->flags & H5S_SEL_ITER_SHARE_WITH_DATASPACE))
H5S__free_pnt_list(iter->u.pnt.pnt_lst);
FUNC_LEAVE_NOAPI(SUCCEED)
}
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;
unsigned u;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
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++) {
unsigned dim;
if(NULL == (new_node = (H5S_pnt_node_t *)H5FL_ARR_MALLOC(hcoords_t, space->extent.rank)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node")
new_node->next = NULL;
H5MM_memcpy(new_node->pnt, coord + (u * space->extent.rank), (space->extent.rank * sizeof(hsize_t)));
if(top == NULL)
top = new_node;
else
curr->next = new_node;
curr = new_node;
for(dim = 0; dim < space->extent.rank; dim++) {
space->select.sel_info.pnt_lst->low_bounds[dim] = MIN(space->select.sel_info.pnt_lst->low_bounds[dim], curr->pnt[dim]);
space->select.sel_info.pnt_lst->high_bounds[dim] = MAX(space->select.sel_info.pnt_lst->high_bounds[dim], curr->pnt[dim]);
}
}
new_node = NULL;
if(op == H5S_SELECT_SET || op == H5S_SELECT_PREPEND) {
if(NULL != space->select.sel_info.pnt_lst->head)
curr->next = space->select.sel_info.pnt_lst->head;
space->select.sel_info.pnt_lst->head = top;
if(NULL == space->select.sel_info.pnt_lst->tail)
space->select.sel_info.pnt_lst->tail = curr;
}
else {
H5S_pnt_node_t *tmp_node;
tmp_node = space->select.sel_info.pnt_lst->head;
if(tmp_node != NULL) {
HDassert(space->select.sel_info.pnt_lst->tail);
space->select.sel_info.pnt_lst->tail->next = top;
}
else
space->select.sel_info.pnt_lst->head = top;
space->select.sel_info.pnt_lst->tail = curr;
}
if(op == H5S_SELECT_SET)
space->select.num_elem = num_elem;
else
space->select.num_elem += num_elem;
done:
if(ret_value < 0) {
if(new_node)
new_node = (H5S_pnt_node_t *)H5FL_ARR_FREE(hcoords_t, new_node);
while(top) {
curr = top->next;
top = (H5S_pnt_node_t *)H5FL_ARR_FREE(hcoords_t, top);
top = curr;
}
}
FUNC_LEAVE_NOAPI(ret_value)
}
static herr_t
H5S__point_release(H5S_t *space)
{
FUNC_ENTER_STATIC_NOERR
HDassert(space);
H5S__free_pnt_list(space->select.sel_info.pnt_lst);
space->select.sel_info.pnt_lst = NULL;
space->select.num_elem = 0;
FUNC_LEAVE_NOAPI(SUCCEED)
}
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;
FUNC_ENTER_NOAPI(FAIL)
HDassert(space);
HDassert(num_elem);
HDassert(coord);
HDassert(op == H5S_SELECT_SET || op == H5S_SELECT_APPEND || op == H5S_SELECT_PREPEND);
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")
if(H5S_GET_SELECT_TYPE(space) != H5S_SEL_POINTS || space->select.sel_info.pnt_lst == NULL) {
hsize_t tmp = HSIZET_MAX;
if(NULL == (space->select.sel_info.pnt_lst = H5FL_CALLOC(H5S_pnt_list_t)))
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate element information")
H5VM_array_fill(space->select.sel_info.pnt_lst->low_bounds, &tmp, sizeof(hsize_t), space->extent.rank);
HDmemset(space->select.sel_info.pnt_lst->high_bounds, 0, sizeof(hsize_t) * space->extent.rank);
}
if(H5S__point_add(space, op, num_elem, coord) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert elements")
space->select.type = H5S_sel_point;
done:
FUNC_LEAVE_NOAPI(ret_value)
}
static H5S_pnt_list_t *
H5S__copy_pnt_list(const H5S_pnt_list_t *src, unsigned rank)
{
H5S_pnt_list_t *dst = NULL;
H5S_pnt_node_t *curr, *new_tail;
H5S_pnt_list_t *ret_value = NULL;
FUNC_ENTER_STATIC
HDassert(src);
HDassert(rank > 0);
if(NULL == (dst = H5FL_MALLOC(H5S_pnt_list_t)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate point list node")
curr = src->head;
new_tail = NULL;
while(curr) {
H5S_pnt_node_t *new_node;
if(NULL == (new_node = (H5S_pnt_node_t *)H5FL_ARR_MALLOC(hcoords_t, rank)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate point node")
new_node->next = NULL;
H5MM_memcpy(new_node->pnt, curr->pnt, (rank * sizeof(hsize_t)));
if(NULL == new_tail)
new_tail = dst->head = new_node;
else {
new_tail->next = new_node;
new_tail = new_node;
}
curr = curr->next;
}
dst->tail = new_tail;
H5MM_memcpy(dst->high_bounds, src->high_bounds, (rank * sizeof(hsize_t)));
H5MM_memcpy(dst->low_bounds, src->low_bounds, (rank * sizeof(hsize_t)));
ret_value = dst;
done:
if(NULL == ret_value && dst)
H5S__free_pnt_list(dst);
FUNC_LEAVE_NOAPI(ret_value)
}
static void
H5S__free_pnt_list(H5S_pnt_list_t *pnt_lst)
{
H5S_pnt_node_t *curr;
FUNC_ENTER_STATIC_NOERR
HDassert(pnt_lst);
curr = pnt_lst->head;
while(curr) {
H5S_pnt_node_t *tmp_node = curr;
curr = curr->next;
tmp_node = (H5S_pnt_node_t *)H5FL_ARR_FREE(hcoords_t, tmp_node);
}
H5FL_FREE(H5S_pnt_list_t, pnt_lst);
FUNC_LEAVE_NOAPI_VOID
}
static herr_t
H5S__point_copy(H5S_t *dst, const H5S_t *src, hbool_t H5_ATTR_UNUSED share_selection)
{
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
HDassert(src);
HDassert(dst);
if(NULL == (dst->select.sel_info.pnt_lst = H5S__copy_pnt_list(src->select.sel_info.pnt_lst, src->extent.rank)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy point list")
done:
FUNC_LEAVE_NOAPI(ret_value)
}
static htri_t
H5S__point_is_valid(const H5S_t *space)
{
unsigned u;
htri_t ret_value = TRUE;
FUNC_ENTER_STATIC_NOERR
HDassert(space);
for(u = 0; u < space->extent.rank; u++) {
if((space->select.sel_info.pnt_lst->high_bounds[u] + (hsize_t)space->select.offset[u]) > space->extent.size[u])
HGOTO_DONE(FALSE)
if(((hssize_t)space->select.sel_info.pnt_lst->low_bounds[u] + space->select.offset[u]) < 0)
HGOTO_DONE(FALSE)
}
done:
FUNC_LEAVE_NOAPI(ret_value)
}
hssize_t
H5Sget_select_elem_npoints(hid_t spaceid)
{
H5S_t *space;
hssize_t ret_value;
FUNC_ENTER_API(FAIL)
H5TRACE1("Hs", "i", spaceid);
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_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)
}
static herr_t
H5S__point_get_version_enc_size(const H5S_t *space, uint32_t *version, uint8_t *enc_size)
{
hbool_t exceed = FALSE;
hsize_t bounds_start[H5S_MAX_RANK];
hsize_t bounds_end[H5S_MAX_RANK];
unsigned u;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
HDmemset(bounds_end, 0, sizeof(bounds_end));
if(H5S__point_bounds(space, bounds_start, bounds_end) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't get selection bounds")
for(u = 0; u < space->extent.rank; u++)
if(bounds_end[u] > H5S_UINT32_MAX) {
exceed = TRUE;
break;
}
if(space->select.num_elem > H5S_UINT32_MAX)
HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "The number of points in point selection exceeds 2^32")
else if(exceed)
HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "The end of bounding box in point selection exceeds 2^32")
*version = H5S_POINT_VERSION_1;
*enc_size = H5S_SELECT_INFO_ENC_SIZE_4;
done:
FUNC_LEAVE_NOAPI(ret_value)
}
static hssize_t
H5S__point_serial_size(const H5S_t *space)
{
H5S_pnt_node_t *curr;
uint32_t version;
uint8_t enc_size;
hssize_t ret_value = -1;
FUNC_ENTER_STATIC
HDassert(space);
if(H5S__point_get_version_enc_size(space, &version, &enc_size) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't determine version and enc_size")
HDassert(version == H5S_POINT_VERSION_1);
HDassert(enc_size == H5S_SELECT_INFO_ENC_SIZE_4);
ret_value = 20;
ret_value += enc_size;
curr = space->select.sel_info.pnt_lst->head;
while(curr != NULL) {
ret_value += enc_size * space->extent.rank;
curr = curr->next;
}
done:
FUNC_LEAVE_NOAPI(ret_value)
}
static herr_t
H5S__point_serialize(const H5S_t *space, uint8_t **p)
{
H5S_pnt_node_t *curr;
uint8_t *pp;
uint8_t *lenp = NULL;
uint32_t len=0;
unsigned u;
uint32_t version;
uint8_t enc_size;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
HDassert(space);
HDassert(p);
pp = (*p);
HDassert(pp);
if(H5S__point_get_version_enc_size(space, &version, &enc_size) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTGET, FAIL, "can't determine version and enc_size")
HDassert(enc_size == H5S_SELECT_INFO_ENC_SIZE_4);
HDassert(version == H5S_POINT_VERSION_1);
UINT32ENCODE(pp, (uint32_t)H5S_GET_SELECT_TYPE(space));
UINT32ENCODE(pp, version);
UINT32ENCODE(pp, (uint32_t)0);
lenp = pp;
pp += 4;
len += 8;
UINT32ENCODE(pp, (uint32_t)space->extent.rank);
UINT32ENCODE(pp, (uint32_t)space->select.num_elem);
curr=space->select.sel_info.pnt_lst->head;
while(curr!=NULL) {
len += 4 * space->extent.rank;
for(u=0; u<space->extent.rank; u++)
UINT32ENCODE(pp, (uint32_t)curr->pnt[u]);
curr=curr->next;
}
UINT32ENCODE(lenp, (uint32_t)len);
*p = pp;
done:
FUNC_LEAVE_NOAPI(ret_value)
}
static herr_t
H5S__point_deserialize(H5S_t **space, const uint8_t **p)
{
H5S_t *tmp_space = NULL;
hsize_t dims[H5S_MAX_RANK];
uint32_t version;
hsize_t *coord = NULL, *tcoord;
const uint8_t *pp;
uint64_t num_elem = 0;
unsigned rank;
unsigned i, j;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
HDassert(p);
pp = (*p);
HDassert(pp);
if(!*space) {
if(NULL == (tmp_space = H5S_create(H5S_SIMPLE)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCREATE, FAIL, "can't create dataspace")
}
else
tmp_space = *space;
UINT32DECODE(pp, version);
if(version < H5S_POINT_VERSION_1 || version > H5S_POINT_VERSION_LATEST)
HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "bad version number for point selection")
pp += 8;
UINT32DECODE(pp,rank);
if(!*space) {
(void)HDmemset(dims, 0, (size_t)rank * sizeof(dims[0]));
if(H5S_set_extent_simple(tmp_space, rank, dims, NULL) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't set dimensions")
}
else
if(rank != tmp_space->extent.rank)
HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "rank of serialized selection does not match dataspace")
UINT32DECODE(pp, num_elem);
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")
for(tcoord = coord, i = 0; i < num_elem; i++)
for(j = 0; j < (unsigned)rank; j++, tcoord++)
UINT32DECODE(pp, *tcoord);
if(H5S_select_elements(tmp_space, H5S_SELECT_SET, num_elem, (const hsize_t *)coord) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection")
*p = pp;
if(!*space)
*space = tmp_space;
done:
if(!*space && tmp_space)
if(H5S_close(tmp_space) < 0)
HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't close dataspace")
if(coord != NULL)
H5MM_xfree(coord);
FUNC_LEAVE_NOAPI(ret_value)
}
static herr_t
H5S__get_select_elem_pointlist(const H5S_t *space, hsize_t startpoint, hsize_t numpoints, hsize_t *buf)
{
H5S_pnt_node_t *node;
unsigned rank;
FUNC_ENTER_STATIC_NOERR
HDassert(space);
HDassert(buf);
rank = space->extent.rank;
node = space->select.sel_info.pnt_lst->head;
while(node != NULL && startpoint > 0) {
startpoint--;
node = node->next;
}
while(node != NULL && numpoints > 0) {
H5MM_memcpy(buf, node->pnt, sizeof(hsize_t) * rank);
buf += rank;
numpoints--;
node = node->next;
}
FUNC_LEAVE_NOAPI(SUCCEED)
}
herr_t
H5Sget_select_elem_pointlist(hid_t spaceid, hsize_t startpoint,
hsize_t numpoints, hsize_t buf[])
{
H5S_t *space;
herr_t ret_value;
FUNC_ENTER_API(FAIL)
H5TRACE4("e", "ihh*[a2]h", spaceid, startpoint, numpoints, buf);
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 dataspace")
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)
}
static herr_t
H5S__point_bounds(const H5S_t *space, hsize_t *start, hsize_t *end)
{
unsigned u;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
HDassert(space);
HDassert(start);
HDassert(end);
for(u = 0; u < space->extent.rank; u++) {
HDassert(space->select.sel_info.pnt_lst->low_bounds[u] <= space->select.sel_info.pnt_lst->high_bounds[u]);
if(((hssize_t)space->select.sel_info.pnt_lst->low_bounds[u] + space->select.offset[u]) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds")
start[u] = (hsize_t)((hssize_t)space->select.sel_info.pnt_lst->low_bounds[u] + space->select.offset[u]);
end[u] = (hsize_t)((hssize_t)space->select.sel_info.pnt_lst->high_bounds[u] + space->select.offset[u]);
}
done:
FUNC_LEAVE_NOAPI(ret_value)
}
static herr_t
H5S__point_offset(const H5S_t *space, hsize_t *offset)
{
const hsize_t *pnt;
const hssize_t *sel_offset;
const hsize_t *dim_size;
hsize_t accum;
int i;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
HDassert(space);
HDassert(offset);
*offset = 0;
pnt = space->select.sel_info.pnt_lst->head->pnt;
sel_offset = space->select.offset;
dim_size = space->extent.size;
accum = 1;
for(i = (int)space->extent.rank - 1; i >= 0; i--) {
hssize_t pnt_offset = (hssize_t)pnt[i] + sel_offset[i];
if(pnt_offset < 0 || (hsize_t)pnt_offset >= dim_size[i])
HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds")
*offset += (hsize_t)pnt_offset * accum;
accum *= dim_size[i];
}
done:
FUNC_LEAVE_NOAPI(ret_value)
}
static int
H5S__point_unlim_dim(const H5S_t H5_ATTR_UNUSED *space)
{
FUNC_ENTER_STATIC_NOERR
FUNC_LEAVE_NOAPI(-1)
}
static htri_t
H5S__point_is_contiguous(const H5S_t *space)
{
htri_t ret_value = FAIL;
FUNC_ENTER_STATIC_NOERR
HDassert(space);
if(space->select.num_elem == 1)
ret_value = TRUE;
else
ret_value = FALSE;
FUNC_LEAVE_NOAPI(ret_value)
}
static htri_t
H5S__point_is_single(const H5S_t *space)
{
htri_t ret_value = FAIL;
FUNC_ENTER_STATIC_NOERR
HDassert(space);
if(space->select.num_elem == 1)
ret_value = TRUE;
else
ret_value = FALSE;
FUNC_LEAVE_NOAPI(ret_value)
}
static htri_t
H5S__point_is_regular(const H5S_t *space)
{
htri_t ret_value = FAIL;
FUNC_ENTER_STATIC_NOERR
HDassert(space);
if(space->select.num_elem == 1)
ret_value = TRUE;
else
ret_value = FALSE;
FUNC_LEAVE_NOAPI(ret_value)
}
static htri_t
H5S__point_shape_same(const H5S_t *space1, const H5S_t *space2)
{
H5S_pnt_node_t *pnt1, *pnt2;
hssize_t offset[H5S_MAX_RANK];
unsigned space1_rank;
unsigned space2_rank;
int space1_dim;
int space2_dim;
htri_t ret_value = TRUE;
FUNC_ENTER_STATIC_NOERR
HDassert(space1);
HDassert(space2);
space1_rank = space1->extent.rank;
space2_rank = space2->extent.rank;
HDassert(space1_rank >= space2_rank);
HDassert(space2_rank > 0);
space1_dim = (int)space1_rank - 1;
space2_dim = (int)space2_rank - 1;
pnt1 = space1->select.sel_info.pnt_lst->head;
pnt2 = space2->select.sel_info.pnt_lst->head;
while(space2_dim >= 0) {
offset[space1_dim] = (hssize_t)pnt2->pnt[space2_dim] - (hssize_t)pnt1->pnt[space1_dim];
space1_dim--;
space2_dim--;
}
while(space1_dim >= 0) {
offset[space1_dim] = (hssize_t)pnt1->pnt[space1_dim];
space1_dim--;
}
pnt1 = pnt1->next;
pnt2 = pnt2->next;
while(pnt1 && pnt2) {
space1_dim = (int)space1_rank - 1;
space2_dim = (int)space2_rank - 1;
while(space2_dim >= 0) {
if((hsize_t)((hssize_t)pnt1->pnt[space1_dim] + offset[space1_dim]) != pnt2->pnt[space2_dim])
HGOTO_DONE(FALSE)
space1_dim--;
space2_dim--;
}
while(space1_dim >= 0) {
if((hssize_t)pnt1->pnt[space1_dim] != offset[space1_dim])
HGOTO_DONE(FALSE)
space1_dim--;
}
pnt1 = pnt1->next;
pnt2 = pnt2->next;
}
done:
FUNC_LEAVE_NOAPI(ret_value)
}
htri_t
H5S__point_intersect_block(const H5S_t *space, const hsize_t *start,
const hsize_t *end)
{
H5S_pnt_node_t *pnt;
htri_t ret_value = FALSE;
FUNC_ENTER_STATIC_NOERR
HDassert(space);
HDassert(H5S_SEL_POINTS == H5S_GET_SELECT_TYPE(space));
HDassert(start);
HDassert(end);
pnt = space->select.sel_info.pnt_lst->head;
while(pnt) {
unsigned u;
for(u = 0; u < space->extent.rank; u++)
if(pnt->pnt[u] < start[u] || pnt->pnt[u] > end[u])
break;
if(u == space->extent.rank)
HGOTO_DONE(TRUE)
pnt = pnt->next;
}
done:
FUNC_LEAVE_NOAPI(ret_value)
}
static herr_t
H5S__point_adjust_u(H5S_t *space, const hsize_t *offset)
{
hbool_t non_zero_offset = FALSE;
H5S_pnt_node_t *node;
unsigned rank;
unsigned u;
FUNC_ENTER_STATIC_NOERR
HDassert(space);
HDassert(offset);
for(u = 0; u < space->extent.rank; u++)
if(0 != offset[u]) {
non_zero_offset = TRUE;
break;
}
if(non_zero_offset) {
node = space->select.sel_info.pnt_lst->head;
rank = space->extent.rank;
while(node) {
for(u = 0; u < rank; u++) {
HDassert(node->pnt[u] >= offset[u]);
node->pnt[u] -= offset[u];
}
node = node->next;
}
for(u = 0; u < rank; u++) {
space->select.sel_info.pnt_lst->low_bounds[u] -= offset[u];
space->select.sel_info.pnt_lst->high_bounds[u] -= offset[u];
}
}
FUNC_LEAVE_NOAPI(SUCCEED)
}
static herr_t
H5S__point_adjust_s(H5S_t *space, const hssize_t *offset)
{
hbool_t non_zero_offset = FALSE;
H5S_pnt_node_t *node;
unsigned rank;
unsigned u;
FUNC_ENTER_STATIC_NOERR
HDassert(space);
HDassert(offset);
for(u = 0; u < space->extent.rank; u++)
if(0 != offset[u]) {
non_zero_offset = TRUE;
break;
}
if(non_zero_offset) {
node = space->select.sel_info.pnt_lst->head;
rank = space->extent.rank;
while(node) {
for(u = 0; u < rank; u++) {
HDassert((hssize_t)node->pnt[u] >= offset[u]);
node->pnt[u] = (hsize_t)((hssize_t)node->pnt[u] - offset[u]);
}
node = node->next;
}
for(u = 0; u < rank; u++) {
HDassert((hssize_t)space->select.sel_info.pnt_lst->low_bounds[u] >= offset[u]);
space->select.sel_info.pnt_lst->low_bounds[u] = (hsize_t)((hssize_t)space->select.sel_info.pnt_lst->low_bounds[u] - offset[u]);
space->select.sel_info.pnt_lst->high_bounds[u] = (hsize_t)((hssize_t)space->select.sel_info.pnt_lst->high_bounds[u] - offset[u]);
}
}
FUNC_LEAVE_NOAPI(SUCCEED)
}
static herr_t
H5S__point_project_scalar(const H5S_t *space, hsize_t *offset)
{
const H5S_pnt_node_t *node;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
HDassert(space && H5S_SEL_POINTS == H5S_GET_SELECT_TYPE(space));
HDassert(offset);
node = space->select.sel_info.pnt_lst->head;
if(node->next)
HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "point selection of one element has more than one node!")
*offset = H5VM_array_offset(space->extent.rank, space->extent.size, node->pnt);
done:
FUNC_LEAVE_NOAPI(ret_value)
}
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;
H5S_pnt_node_t *new_node;
H5S_pnt_node_t *prev_node;
unsigned rank_diff;
unsigned u;
herr_t ret_value = SUCCEED;
FUNC_ENTER_STATIC
HDassert(base_space && H5S_SEL_POINTS == H5S_GET_SELECT_TYPE(base_space));
HDassert(new_space);
HDassert(offset);
if(H5S_SELECT_RELEASE(new_space) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
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")
if(new_space->extent.rank < base_space->extent.rank) {
hsize_t block[H5S_MAX_RANK];
rank_diff = base_space->extent.rank - new_space->extent.rank;
HDmemset(block, 0, sizeof(block));
H5MM_memcpy(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);
base_node = base_space->select.sel_info.pnt_lst->head;
prev_node = NULL;
while(base_node) {
if(NULL == (new_node = (H5S_pnt_node_t *)H5FL_ARR_MALLOC(hcoords_t, new_space->extent.rank)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node")
new_node->next = NULL;
H5MM_memcpy(new_node->pnt, &base_node->pnt[rank_diff], (new_space->extent.rank * sizeof(hsize_t)));
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;
}
base_node = base_node->next;
}
for(u = 0; u < new_space->extent.rank; u++) {
new_space->select.sel_info.pnt_lst->low_bounds[u] = base_space->select.sel_info.pnt_lst->low_bounds[u + rank_diff];
new_space->select.sel_info.pnt_lst->high_bounds[u] = base_space->select.sel_info.pnt_lst->high_bounds[u + rank_diff];
}
}
else {
HDassert(new_space->extent.rank > base_space->extent.rank);
rank_diff = new_space->extent.rank - base_space->extent.rank;
*offset = 0;
base_node = base_space->select.sel_info.pnt_lst->head;
prev_node = NULL;
while(base_node) {
if(NULL == (new_node = (H5S_pnt_node_t *)H5FL_ARR_MALLOC(hcoords_t, new_space->extent.rank)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate point node")
new_node->next = NULL;
HDmemset(new_node->pnt, 0, sizeof(hsize_t) * rank_diff);
H5MM_memcpy(&new_node->pnt[rank_diff], base_node->pnt, (new_space->extent.rank * sizeof(hsize_t)));
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;
}
base_node = base_node->next;
}
for(u = 0; u < rank_diff; u++) {
new_space->select.sel_info.pnt_lst->low_bounds[u] = 0;
new_space->select.sel_info.pnt_lst->high_bounds[u] = 0;
}
for(; u < new_space->extent.rank; u++) {
new_space->select.sel_info.pnt_lst->low_bounds[u] = base_space->select.sel_info.pnt_lst->low_bounds[u - rank_diff];
new_space->select.sel_info.pnt_lst->high_bounds[u] = base_space->select.sel_info.pnt_lst->high_bounds[u - rank_diff];
}
}
new_space->select.num_elem = base_space->select.num_elem;
new_space->select.type = H5S_sel_point;
done:
FUNC_LEAVE_NOAPI(ret_value)
}
herr_t
H5Sselect_elements(hid_t spaceid, H5S_seloper_t op, size_t num_elem,
const hsize_t *coord)
{
H5S_t *space;
herr_t ret_value;
FUNC_ENTER_API(FAIL)
H5TRACE4("e", "iSsz*h", spaceid, op, num_elem, coord);
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")
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)
}