summaryrefslogtreecommitdiffstats
path: root/src/H5Shyper.c
diff options
context:
space:
mode:
authorDana Robinson <derobins@hdfgroup.org>2020-07-16 19:16:05 (GMT)
committerDana Robinson <derobins@hdfgroup.org>2020-07-16 19:16:05 (GMT)
commit02762e8244741b9ff1f9203788e7237f53cf8d96 (patch)
tree9ddfe80514742123b191b1b38ec0d885ff819e63 /src/H5Shyper.c
parent1ecb6ec9c5075a97572d06a1f509cd763be2bc94 (diff)
downloadhdf5-02762e8244741b9ff1f9203788e7237f53cf8d96.zip
hdf5-02762e8244741b9ff1f9203788e7237f53cf8d96.tar.gz
hdf5-02762e8244741b9ff1f9203788e7237f53cf8d96.tar.bz2
Merge of dataspace improvements from develop.
Diffstat (limited to 'src/H5Shyper.c')
-rw-r--r--src/H5Shyper.c9579
1 files changed, 5600 insertions, 3979 deletions
diff --git a/src/H5Shyper.c b/src/H5Shyper.c
index af9e3bc..42b9acd 100644
--- a/src/H5Shyper.c
+++ b/src/H5Shyper.c
@@ -12,7 +12,7 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
- * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu>
+ * Programmer: Quincey Koziol
* Thursday, June 18, 1998
*
* Purpose: Hyperslab selection dataspace I/O functions.
@@ -37,56 +37,138 @@
#include "H5Spkg.h" /* Dataspace functions */
#include "H5VMprivate.h" /* Vector functions */
-/* Format version bounds for dataspace hyperslab selection */
-const unsigned H5O_sds_hyper_ver_bounds[] = {
- H5S_HYPER_VERSION_1, /* H5F_LIBVER_EARLIEST */
- H5S_HYPER_VERSION_1, /* H5F_LIBVER_V18 */
- H5S_HYPER_VERSION_2 /* H5F_LIBVER_LATEST */
-};
/****************/
/* Local Macros */
/****************/
+/* Flags for which hyperslab fragments to compute */
+#define H5S_HYPER_COMPUTE_B_NOT_A 0x01
+#define H5S_HYPER_COMPUTE_A_AND_B 0x02
+#define H5S_HYPER_COMPUTE_A_NOT_B 0x04
+
+/* Macro to advance a span, possibly recycling it first */
+#define H5S_HYPER_ADVANCE_SPAN(recover, curr_span, next_span) \
+ do { \
+ H5S_hyper_span_t *saved_next_span = (next_span); \
+ \
+ /* Check if the span should be recovered */ \
+ if(recover) { \
+ H5S__hyper_free_span(curr_span); \
+ (recover) = FALSE; \
+ } /* end if */ \
+ \
+ /* Set the current span to saved next span */ \
+ (curr_span) = saved_next_span; \
+ } while(0)
+
+/* Macro to add "skipped" elements to projection during the execution of
+ * H5S__hyper_project_intersect() */
+#define H5S_HYPER_PROJ_INT_ADD_SKIP(UDATA, ADD, ERR) \
+ do { \
+ /* If there are any elements to add, we must add them \
+ * to the projection first before adding skip */ \
+ if((UDATA)->nelem > 0) \
+ if(H5S__hyper_proj_int_build_proj(UDATA) < 0) \
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, ERR, "can't add elements to projected selection") \
+ (UDATA)->skip += (ADD); \
+ } while(0) /* end H5S_HYPER_PROJ_INT_ADD_SKIP() */
+
/******************/
/* Local Typedefs */
/******************/
+/* Define alias for hsize_t, for allocating H5S_hyper_span_info_t + bounds objects */
+/* (Makes it easier to understand the alloc / free calls) */
+typedef hsize_t hbounds_t;
+
+/* Struct for holding persistent information during iteration for
+ * H5S__hyper_project_intersect() */
+typedef struct {
+ const H5S_hyper_span_t *ds_span[H5S_MAX_RANK]; /* Array of the current spans in the destination space in each dimension */
+ hsize_t ds_low[H5S_MAX_RANK]; /* Array of current low bounds (of iteration) for each element in ds_span */
+ H5S_hyper_span_info_t *ps_span_info[H5S_MAX_RANK]; /* Array of span info structs for projected space during iteration */
+ uint32_t ps_clean_bitmap; /* Bitmap of whether the nth rank has a clean projected space since the last time it was set to 1 */
+ unsigned ss_rank; /* Rank of source space */
+ unsigned ds_rank; /* Rank of destination space */
+ unsigned depth; /* Current depth of iterator in destination space */
+ hsize_t skip; /* Number of elements to skip in projected space */
+ hsize_t nelem; /* Number of elements to add to projected space (after skip) */
+ uint64_t op_gen; /* Operation generation for counting elements */
+ hbool_t share_selection; /* Whether span trees in dst_space can be shared with proj_space */
+} H5S_hyper_project_intersect_ud_t;
+
+/* Assert that H5S_MAX_RANK is <= 32 so our trick with using a 32 bit bitmap
+ * (ps_clean_bitmap) works. If H5S_MAX_RANK increases either increase the size
+ * of ps_clean_bitmap or change the algorithm to use an array. */
+#if H5S_MAX_RANK > 32
+#error H5S_MAX_RANK too large for ps_clean_bitmap field in H5S_hyper_project_intersect_ud_t struct
+#endif
+
+
/********************/
/* Local Prototypes */
/********************/
static H5S_hyper_span_t *H5S__hyper_new_span(hsize_t low, hsize_t high,
H5S_hyper_span_info_t *down, H5S_hyper_span_t *next);
-static herr_t H5S__hyper_span_precompute(H5S_hyper_span_info_t *spans, size_t elmt_size);
-static void H5S__hyper_span_scratch(H5S_hyper_span_info_t *spans);
-static H5S_hyper_span_info_t *H5S__hyper_copy_span(H5S_hyper_span_info_t *spans);
+static H5S_hyper_span_info_t *H5S__hyper_new_span_info(unsigned rank);
+static H5S_hyper_span_info_t *H5S__hyper_copy_span_helper(
+ H5S_hyper_span_info_t *spans, unsigned rank, unsigned op_info_i,
+ uint64_t op_gen);
+static H5S_hyper_span_info_t *H5S__hyper_copy_span(H5S_hyper_span_info_t *spans,
+ unsigned rank);
static hbool_t H5S__hyper_cmp_spans(const H5S_hyper_span_info_t *span_info1,
const H5S_hyper_span_info_t *span_info2);
-static herr_t H5S__hyper_free_span_info(H5S_hyper_span_info_t *span_info);
-static herr_t H5S__hyper_free_span(H5S_hyper_span_t *span);
-static hbool_t H5S__hyper_is_valid_helper(const H5S_hyper_span_info_t *spans,
- const hssize_t *offset, const hsize_t *size);
-static herr_t H5S__hyper_recover_span(hbool_t *recover,
- H5S_hyper_span_t **curr_span, H5S_hyper_span_t *next_span);
-static H5S_hyper_span_t *H5S__hyper_coord_to_span(unsigned rank,
- const hsize_t *coords);
-static herr_t H5S__hyper_append_span(H5S_hyper_span_t **prev_span,
- H5S_hyper_span_info_t **span_tree, hsize_t low, hsize_t high,
- H5S_hyper_span_info_t *down, H5S_hyper_span_t *next);
+static void H5S__hyper_free_span_info(H5S_hyper_span_info_t *span_info);
+static void H5S__hyper_free_span(H5S_hyper_span_t *span);
+static herr_t H5S__hyper_span_blocklist(const H5S_hyper_span_info_t *spans,
+ hsize_t start[], hsize_t end[], hsize_t rank, hsize_t *startblock, hsize_t *numblocks,
+ hsize_t **buf);
+static herr_t H5S__get_select_hyper_blocklist(H5S_t *space, hsize_t startblock,
+ hsize_t numblocks, hsize_t *buf);
+static H5S_hyper_span_t *H5S__hyper_coord_to_span(unsigned rank, const hsize_t *coords);
+static herr_t H5S__hyper_append_span(H5S_hyper_span_info_t **span_tree,
+ unsigned ndims, hsize_t low, hsize_t high, H5S_hyper_span_info_t *down);
static herr_t H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans,
- H5S_hyper_span_info_t *b_spans, H5S_hyper_span_info_t **a_not_b,
+ H5S_hyper_span_info_t *b_spans, unsigned selector,
+ unsigned ndims, H5S_hyper_span_info_t **a_not_b,
H5S_hyper_span_info_t **a_and_b, H5S_hyper_span_info_t **b_not_a);
-static herr_t H5S__hyper_merge_spans(H5S_t *space,
- H5S_hyper_span_info_t *new_spans, hbool_t can_own);
-static hsize_t H5S__hyper_spans_nelem(const H5S_hyper_span_info_t *spans);
+static herr_t H5S__hyper_merge_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans);
+static hsize_t H5S__hyper_spans_nelem_helper(H5S_hyper_span_info_t *spans,
+ unsigned op_info_i, uint64_t op_gen);
+static hsize_t H5S__hyper_spans_nelem(H5S_hyper_span_info_t *spans);
+static herr_t H5S__hyper_add_disjoint_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans);
static H5S_hyper_span_info_t *H5S__hyper_make_spans(unsigned rank,
- const hsize_t *start, const hsize_t *stride, const hsize_t *count,
- const hsize_t *block);
+ const hsize_t *start, const hsize_t *stride,
+ const hsize_t *count, const hsize_t *block);
+static herr_t H5S__hyper_update_diminfo(H5S_t *space, H5S_seloper_t op,
+ const H5S_hyper_dim_t *new_hyper_diminfo);
static herr_t H5S__hyper_generate_spans(H5S_t *space);
+static hbool_t H5S__check_spans_overlap(const H5S_hyper_span_info_t *spans1,
+ const H5S_hyper_span_info_t *spans2);
+static herr_t H5S__fill_in_new_space(H5S_t *space1, H5S_seloper_t op,
+ H5S_hyper_span_info_t *space2_span_lst, hbool_t can_own_span2,
+ hbool_t *span2_owned, hbool_t *updated_spans, H5S_t **result);
static herr_t H5S__generate_hyperslab(H5S_t *space, H5S_seloper_t op,
const hsize_t start[], const hsize_t stride[], const hsize_t count[],
const hsize_t block[]);
+static herr_t H5S__set_regular_hyperslab(H5S_t *space, const hsize_t start[],
+ const hsize_t *app_stride, const hsize_t app_count[], const hsize_t *app_block,
+ const hsize_t *opt_stride, const hsize_t opt_count[], const hsize_t *opt_block);
+static herr_t H5S__fill_in_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2,
+ H5S_t **result);
+static H5S_t *H5S__combine_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2);
+static herr_t H5S__hyper_iter_get_seq_list_gen(H5S_sel_iter_t *iter, size_t maxseq,
+ size_t maxelem, size_t *nseq, size_t *nelem, hsize_t *off, size_t *len);
+static herr_t H5S__hyper_iter_get_seq_list_opt(H5S_sel_iter_t *iter, size_t maxseq,
+ size_t maxelem, size_t *nseq, size_t *nelem, hsize_t *off, size_t *len);
+static herr_t H5S__hyper_iter_get_seq_list_single(H5S_sel_iter_t *iter, size_t maxseq,
+ size_t maxelem, size_t *nseq, size_t *nelem, hsize_t *off, size_t *len);
+static herr_t H5S__hyper_proj_int_build_proj(H5S_hyper_project_intersect_ud_t *udata);
+static herr_t H5S__hyper_proj_int_iterate(const H5S_hyper_span_info_t *ss_span_info,
+ const H5S_hyper_span_info_t *sis_span_info, hsize_t count, unsigned depth,
+ H5S_hyper_project_intersect_ud_t *udata);
static void H5S__hyper_get_clip_diminfo(hsize_t start, hsize_t stride,
hsize_t *count, hsize_t *block, hsize_t clip_size);
static hsize_t H5S__hyper_get_clip_extent_real(const H5S_t *clip_space,
@@ -94,11 +176,9 @@ static hsize_t H5S__hyper_get_clip_extent_real(const H5S_t *clip_space,
/* Selection callbacks */
static herr_t H5S__hyper_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection);
-static herr_t H5S__hyper_get_seq_list(const H5S_t *space, unsigned flags,
- H5S_sel_iter_t *iter, size_t maxseq, size_t maxbytes,
- size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len);
static herr_t H5S__hyper_release(H5S_t *space);
static htri_t H5S__hyper_is_valid(const H5S_t *space);
+static hsize_t H5S__hyper_span_nblocks(H5S_hyper_span_info_t *spans);
static hssize_t H5S__hyper_serial_size(const H5S_t *space);
static herr_t H5S__hyper_serialize(const H5S_t *space, uint8_t **p);
static herr_t H5S__hyper_deserialize(H5S_t **space, const uint8_t **p);
@@ -110,7 +190,11 @@ static herr_t H5S__hyper_num_elem_non_unlim(const H5S_t *space,
static htri_t H5S__hyper_is_contiguous(const H5S_t *space);
static htri_t H5S__hyper_is_single(const H5S_t *space);
static htri_t H5S__hyper_is_regular(const H5S_t *space);
+static htri_t H5S__hyper_shape_same(const H5S_t *space1, const H5S_t *space2);
+static htri_t H5S__hyper_intersect_block(const H5S_t *space, const hsize_t *start,
+ const hsize_t *end);
static herr_t H5S__hyper_adjust_u(H5S_t *space, const hsize_t *offset);
+static herr_t H5S__hyper_adjust_s(H5S_t *space, const hssize_t *offset);
static herr_t H5S__hyper_project_scalar(const H5S_t *space, hsize_t *offset);
static herr_t H5S__hyper_project_simple(const H5S_t *space, H5S_t *new_space, hsize_t *offset);
static herr_t H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter);
@@ -122,11 +206,9 @@ static hsize_t H5S__hyper_iter_nelmts(const H5S_sel_iter_t *iter);
static htri_t H5S__hyper_iter_has_next_block(const H5S_sel_iter_t *sel_iter);
static herr_t H5S__hyper_iter_next(H5S_sel_iter_t *sel_iter, size_t nelem);
static herr_t H5S__hyper_iter_next_block(H5S_sel_iter_t *sel_iter);
+static herr_t H5S__hyper_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq,
+ size_t maxbytes, size_t *nseq, size_t *nbytes, hsize_t *off, size_t *len);
static herr_t H5S__hyper_iter_release(H5S_sel_iter_t *sel_iter);
-/* Static function for optimizing hyperslab */
-static hbool_t H5S__hyper_rebuild_helper(const H5S_hyper_span_t *span,
- H5S_hyper_dim_t span_slab_info[], unsigned rank);
-static hbool_t H5S__hyper_rebuild(H5S_t *space);
/*****************************/
@@ -144,7 +226,6 @@ const H5S_select_class_t H5S_sel_hyper[1] = {{
/* Methods on selection */
H5S__hyper_copy,
- H5S__hyper_get_seq_list,
H5S__hyper_release,
H5S__hyper_is_valid,
H5S__hyper_serial_size,
@@ -157,12 +238,26 @@ const H5S_select_class_t H5S_sel_hyper[1] = {{
H5S__hyper_is_contiguous,
H5S__hyper_is_single,
H5S__hyper_is_regular,
+ H5S__hyper_shape_same,
+ H5S__hyper_intersect_block,
H5S__hyper_adjust_u,
+ H5S__hyper_adjust_s,
H5S__hyper_project_scalar,
H5S__hyper_project_simple,
H5S__hyper_iter_init,
}};
+/* Format version bounds for dataspace hyperslab selection */
+const unsigned H5O_sds_hyper_ver_bounds[] = {
+ H5S_HYPER_VERSION_1, /* H5F_LIBVER_EARLIEST */
+ H5S_HYPER_VERSION_1, /* H5F_LIBVER_V18 */
+ H5S_HYPER_VERSION_2 /* H5F_LIBVER_LATEST */
+};
+
+/*******************/
+/* Local Variables */
+/*******************/
+
/* Iteration properties for hyperslab selections */
static const H5S_sel_iter_class_t H5S_sel_iter_hyper[1] = {{
H5S_SEL_HYPERSLABS,
@@ -174,6 +269,7 @@ static const H5S_sel_iter_class_t H5S_sel_iter_hyper[1] = {{
H5S__hyper_iter_has_next_block,
H5S__hyper_iter_next,
H5S__hyper_iter_next_block,
+ H5S__hyper_iter_get_seq_list,
H5S__hyper_iter_release,
}};
@@ -195,12 +291,17 @@ H5FL_DEFINE_STATIC(H5S_hyper_sel_t);
/* Declare a free list to manage the H5S_hyper_span_t struct */
H5FL_DEFINE_STATIC(H5S_hyper_span_t);
-/* Declare a free list to manage the H5S_hyper_span_info_t struct */
-H5FL_DEFINE_STATIC(H5S_hyper_span_info_t);
+/* Declare a free list to manage the H5S_hyper_span_info_t + hsize_t array struct */
+H5FL_BARR_DEFINE_STATIC(H5S_hyper_span_info_t, hbounds_t, H5S_MAX_RANK * 2);
/* Declare extern free list to manage the H5S_sel_iter_t struct */
H5FL_EXTERN(H5S_sel_iter_t);
+/* Current operation generation */
+/* (Start with '1' to avoid clashing with '0' value in newly allocated structs) */
+static uint64_t H5S_hyper_op_gen_g = 1;
+
+
/* Uncomment this to provide the debugging routines for printing selection info */
/* #define H5S_HYPER_DEBUG */
#ifdef H5S_HYPER_DEBUG
@@ -210,9 +311,9 @@ H5S__hyper_print_spans_helper(FILE *f, const H5S_hyper_span_t *span, unsigned de
FUNC_ENTER_STATIC_NOERR
while(span) {
- HDfprintf(f,"%s: depth=%u, span=%p, (%Hu, %Hu), nelem=%Hu, pstride=%Hu\n", FUNC, depth, span, span->low, span->high, span->nelem, span->pstride);
- if(span->down && span->down->head) {
- HDfprintf(f,"%s: spans=%p, count=%u, scratch=%p, head=%p\n", FUNC, span->down, span->down->count, span->down->scratch, span->down->head);
+ HDfprintf(f,"%s: %*sdepth=%u, span=%p, (%Hu, %Hu), next=%p\n", FUNC, depth * 2, "", depth, span, span->low, span->high, span->next);
+ if(span->down) {
+ HDfprintf(f,"%s: %*sspans=%p, count=%u, bounds[0]={%Hu, %Hu}, head=%p\n", FUNC, (depth + 1) * 2, "", span->down, span->down->count, span->down->low_bounds[0], span->down->high_bounds[0], span->down->head);
H5S__hyper_print_spans_helper(f, span->down->head, depth + 1);
} /* end if */
span = span->next;
@@ -227,7 +328,7 @@ H5S__hyper_print_spans(FILE *f, const H5S_hyper_span_info_t *span_lst)
FUNC_ENTER_STATIC_NOERR
if(span_lst != NULL) {
- HDfprintf(f, "%s: spans=%p, count=%u, scratch=%p, head=%p\n", FUNC, span_lst, span_lst->count, span_lst->scratch, span_lst->head);
+ HDfprintf(f, "%s: spans=%p, count=%u, bounds[0]={%Hu, %Hu}, head=%p\n", FUNC, span_lst, span_lst->count, span_lst->low_bounds[0], span_lst->high_bounds[0], span_lst->head);
H5S__hyper_print_spans_helper(f, span_lst->head, 0);
} /* end if */
@@ -281,10 +382,179 @@ H5S__hyper_print_diminfo(FILE *f, const H5S_t *space)
FUNC_LEAVE_NOAPI(SUCCEED)
}
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_print_spans_dfs
+ PURPOSE
+ Output the span elements for one span list in depth-first order
+ USAGE
+ herr_t H5S__hyper_print_spans_dfs(f, span_lst, depth)
+ FILE *f; IN: the file to output
+ const H5S_hyper_span_info_t *span_lst; IN: the span list to output
+ unsigned depth; IN: the level of this span list
+ RETURNS
+ non-negative on success, negative on failure
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S__hyper_print_spans_dfs(FILE *f, const H5S_hyper_span_info_t *span_lst,
+ unsigned depth, unsigned dims)
+{
+ H5S_hyper_span_t *actual_tail = NULL;
+ H5S_hyper_span_t *cur_elem;
+ unsigned num_elems = 0;
+ unsigned u, elem_idx;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* get the actual tail from head */
+ cur_elem = span_lst->head;
+ HDassert(cur_elem); /* at least 1 element */
+ while(cur_elem) {
+ actual_tail = cur_elem;
+ cur_elem = cur_elem->next;
+ num_elems++;
+ } /* end while */
+
+ for(u = 0; u < depth; u++)
+ HDfprintf(f, "\t");
+ HDfprintf(f, "DIM[%u]: ref_count=%u, #elems=%u, head=%p, tail=%p, actual_tail=%p, matched=%t\n", depth,
+ span_lst->count, num_elems, span_lst->head,
+ span_lst->tail, actual_tail, (span_lst->tail == actual_tail));
+
+ for(u = 0; u < depth; u++)
+ HDfprintf(f, "\t");
+ HDfprintf(f, "low_bounds=[");
+ for(u = 0; u < dims - 1; u++)
+ HDfprintf(f, "%llu,", span_lst->low_bounds[u]);
+ HDfprintf(f, "%llu]\n", span_lst->low_bounds[dims - 1]);
+
+ for(u = 0; u < depth; u++)
+ HDfprintf(f, "\t");
+ HDfprintf(f, "high_bounds=[");
+ for(u = 0; u < dims - 1; u++)
+ HDfprintf(f, "%llu,", span_lst->high_bounds[u]);
+ HDfprintf(f, "%llu]\n", span_lst->high_bounds[dims - 1]);
+
+ cur_elem = span_lst->head;
+ elem_idx = 0;
+ while(cur_elem) {
+ for(u = 0; u < depth; u++)
+ HDfprintf(f, "\t");
+ HDfprintf(f, "ELEM[%u]: ptr=%p, low=%Hu, high=%Hu, down=%p\n",
+ elem_idx++, cur_elem, cur_elem->low, cur_elem->high, cur_elem->down);
+ if(cur_elem->down)
+ H5S__hyper_print_spans_dfs(f, cur_elem->down, depth + 1, dims);
+ cur_elem = cur_elem->next;
+ } /* end while */
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S__hyper_print_spans_dfs() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_print_space_dfs
+ PURPOSE
+ Output the span elements for one hyperslab selection space in depth-first order
+ USAGE
+ herr_t H5S__hyper_print_space_dfs(f, space)
+ FILE *f; IN: the file to output
+ const H5S_t *space; IN: the selection space to output
+ RETURNS
+ non-negative on success, negative on failure
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S__hyper_print_space_dfs(FILE *f, const H5S_t *space)
+{
+ const H5S_hyper_sel_t *hslab = space->select.sel_info.hslab;
+ const unsigned dims = space->extent.rank;
+ unsigned u;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ HDassert(hslab);
+
+ HDfprintf(f, "=======================\n");
+ HDfprintf(f, "SPACE: span_lst=%p, #dims=%u, offset_changed=%d\n", hslab->span_lst, dims, space->select.offset_changed);
+
+ HDfprintf(f, " offset=[");
+ for(u = 0; u < dims - 1; u++)
+ HDfprintf(f, "%lld,", space->select.offset[u]);
+ HDfprintf(f, "%lld]\n", space->select.offset[dims - 1]);
+
+ HDfprintf(f, " low_bounds=[");
+ if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
+ for(u = 0; u < dims - 1; u++)
+ HDfprintf(f, "%llu,", space->select.sel_info.hslab->diminfo.low_bounds[u]);
+ HDfprintf(f, "%llu]\n", space->select.sel_info.hslab->diminfo.low_bounds[dims - 1]);
+ } /* end if */
+ else {
+ for(u = 0; u < dims - 1; u++)
+ HDfprintf(f, "%llu,", space->select.sel_info.hslab->span_lst->low_bounds[u]);
+ HDfprintf(f, "%llu]\n", space->select.sel_info.hslab->span_lst->low_bounds[dims - 1]);
+ } /* end else */
+
+ HDfprintf(f, " high_bounds=[");
+ if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
+ for(u = 0; u < dims - 1; u++)
+ HDfprintf(f, "%llu,", space->select.sel_info.hslab->diminfo.high_bounds[u]);
+ HDfprintf(f, "%llu]\n", space->select.sel_info.hslab->diminfo.high_bounds[dims - 1]);
+ } /* end if */
+ else {
+ for(u = 0; u < dims - 1; u++)
+ HDfprintf(f, "%llu,", space->select.sel_info.hslab->span_lst->high_bounds[u]);
+ HDfprintf(f, "%llu]\n", space->select.sel_info.hslab->span_lst->high_bounds[dims - 1]);
+ } /* end else */
+
+ /* Print out diminfo, if it's valid */
+ if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES)
+ H5S__hyper_print_diminfo(f, space);
+
+ /* Start print out the highest-order of dimension */
+ if(hslab->span_lst)
+ H5S__hyper_print_spans_dfs(f, hslab->span_lst, 0, dims);
+ HDfprintf(f, "=======================\n\n");
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S__hyper_print_space_dfs() */
#endif /* H5S_HYPER_DEBUG */
/*-------------------------------------------------------------------------
+ * Function: H5S__hyper_get_op_gen
+ *
+ * Purpose: Acquire a unique operation generation value
+ *
+ * Return: Operation generation value (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, January 19, 2019
+ *
+ * Notes: Assumes that a 64-bit value will not wrap around during
+ * the lifespan of the process.
+ *
+ *-------------------------------------------------------------------------
+ */
+uint64_t
+H5S__hyper_get_op_gen(void)
+{
+ FUNC_ENTER_PACKAGE_NOERR
+
+ FUNC_LEAVE_NOAPI(H5S_hyper_op_gen_g++);
+} /* end H5S__hyper_op_gen() */
+
+
+/*-------------------------------------------------------------------------
* Function: H5S__hyper_iter_init
*
* Purpose: Initializes iteration information for hyperslab selection.
@@ -304,38 +574,45 @@ H5S__hyper_print_diminfo(FILE *f, const H5S_t *space)
static herr_t
H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter)
{
- const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
- H5S_hyper_span_info_t *spans; /* Pointer to hyperslab span info node */
+ hsize_t *slab_size; /* Pointer to the dataspace dimensions to use for calc. slab */
+ hsize_t acc; /* Accumulator for computing cumulative sizes */
+ unsigned slab_dim; /* Rank of the fastest changing dimension for calc. slab */
unsigned rank; /* Dataspace's dimension rank */
unsigned u; /* Index variable */
int i; /* Index variable */
+ herr_t ret_value = SUCCEED; /* return value */
- FUNC_ENTER_STATIC_NOERR
+ FUNC_ENTER_STATIC
/* Check args */
HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
HDassert(iter);
HDassert(space->select.sel_info.hslab->unlim_dim < 0);
- /* Initialize the number of points to iterate over */
- iter->elmt_left = space->select.num_elem;
+ /* Initialize the hyperslab iterator's rank */
iter->u.hyp.iter_rank = 0;
/* Get the rank of the dataspace */
- rank = space->extent.rank;
+ rank = iter->rank;
- /* Set the temporary pointer to the dimension information */
- tdiminfo = space->select.sel_info.hslab->diminfo.opt;
+ /* Attempt to rebuild diminfo if it is invalid and has not been confirmed
+ * to be impossible.
+ */
+ if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
+ H5S__hyper_rebuild((H5S_t *)space); /* Casting away const OK -NAF */
/* Check for the special case of just one H5Sselect_hyperslab call made */
if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
- /* Initialize the information needed for regular hyperslab I/O */
+/* Initialize the information needed for regular hyperslab I/O */
+ const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
const hsize_t *mem_size; /* Temporary pointer to dataspace extent's dimension sizes */
- hsize_t acc; /* Accumulator for "flattened" dimension's sizes */
unsigned cont_dim = 0; /* # of contiguous dimensions */
+ /* Set the temporary pointer to the dimension information */
+ tdiminfo = space->select.sel_info.hslab->diminfo.opt;
+
/* Set the temporary pointer to the dataspace extent's dimension sizes */
- mem_size = space->extent.size;
+ mem_size = iter->dims;
/*
* For a regular hyperslab to be contiguous up to some dimension, it
@@ -393,7 +670,7 @@ H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter)
iter->u.hyp.diminfo[curr_dim].count = tdiminfo[i].count;
iter->u.hyp.diminfo[curr_dim].block = tdiminfo[i].block * acc;
iter->u.hyp.size[curr_dim] = mem_size[i] * acc;
- iter->u.hyp.sel_off[curr_dim] = space->select.offset[i] * (hssize_t)acc;
+ iter->u.hyp.sel_off[curr_dim] = iter->sel_off[i] * (hssize_t)acc;
/* Reset the "last dim flattened" flag to avoid flattened any further dimensions */
last_dim_flattened = FALSE;
@@ -408,7 +685,7 @@ H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter)
iter->u.hyp.diminfo[curr_dim].count = tdiminfo[i].count;
iter->u.hyp.diminfo[curr_dim].block = tdiminfo[i].block;
iter->u.hyp.size[curr_dim] = mem_size[i];
- iter->u.hyp.sel_off[curr_dim] = space->select.offset[i];
+ iter->u.hyp.sel_off[curr_dim] = iter->sel_off[i];
} /* end else */
/* Decrement "current" flattened dimension */
@@ -419,20 +696,23 @@ H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter)
/* Initialize "flattened" iterator offset to initial location and dataspace extent and selection information to correct values */
for(u = 0; u < flat_rank; u++)
iter->u.hyp.off[u] = iter->u.hyp.diminfo[u].start;
+
+ /* Set up information for computing slab sizes */
+ slab_dim = iter->u.hyp.iter_rank - 1;
+ slab_size = iter->u.hyp.size;
} /* end if */
else {
+ /* Make local copy of the regular selection information */
+ HDcompile_assert(sizeof(iter->u.hyp.diminfo) == sizeof(space->select.sel_info.hslab->diminfo.opt));
+ H5MM_memcpy(iter->u.hyp.diminfo, tdiminfo, sizeof(iter->u.hyp.diminfo));
+
/* Initialize position to initial location */
- /* Also make local copy of the regular selection information */
- for(u = 0; u < rank; u++) {
- /* Regular selection information */
- iter->u.hyp.diminfo[u].start = tdiminfo[u].start;
- iter->u.hyp.diminfo[u].stride = tdiminfo[u].stride;
- iter->u.hyp.diminfo[u].count = tdiminfo[u].count;
- iter->u.hyp.diminfo[u].block = tdiminfo[u].block;
-
- /* Position information */
+ for(u = 0; u < rank; u++)
iter->u.hyp.off[u] = tdiminfo[u].start;
- } /* end if */
+
+ /* Set up information for computing slab sizes */
+ slab_dim = iter->rank - 1;
+ slab_size = iter->dims;
} /* end else */
/* Flag the diminfo information as valid in the iterator */
@@ -441,14 +721,30 @@ H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter)
/* Initialize irregular region information also (for release) */
iter->u.hyp.spans = NULL;
} /* end if */
- else {
-/* Initialize the information needed for non-regular hyperslab I/O */
- HDassert(space->select.sel_info.hslab->span_lst);
- /* Make a copy of the span tree to iterate over */
- iter->u.hyp.spans = H5S__hyper_copy_span(space->select.sel_info.hslab->span_lst);
+ else { /* Initialize the information needed for non-regular hyperslab I/O */
+ H5S_hyper_span_info_t *spans; /* Pointer to hyperslab span info node */
- /* Set the nelem & pstride values according to the element size */
- H5S__hyper_span_precompute(iter->u.hyp.spans, iter->elmt_size);
+ /* If this iterator is created from an API call, by default we clone the
+ * selection now, as the dataspace could be modified or go out of scope.
+ *
+ * However, if the H5S_SEL_ITER_SHARE_WITH_DATASPACE flag is given,
+ * the selection is shared between the selection iterator and the
+ * dataspace. In this case, the application _must_not_ modify or
+ * close the dataspace that the iterator is operating on, or undefined
+ * behavior will occur.
+ */
+ if((iter->flags & H5S_SEL_ITER_API_CALL) &&
+ !(iter->flags & H5S_SEL_ITER_SHARE_WITH_DATASPACE)) {
+ /* Copy the span tree */
+ if(NULL == (iter->u.hyp.spans = H5S__hyper_copy_span(space->select.sel_info.hslab->span_lst, space->extent.rank)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy span tree")
+ } /* end if */
+ else {
+ /* Share the source dataspace's span tree by incrementing the reference count on it */
+ HDassert(space->select.sel_info.hslab->span_lst);
+ iter->u.hyp.spans = space->select.sel_info.hslab->span_lst;
+ iter->u.hyp.spans->count++;
+ } /* end else */
/* Initialize the starting span_info's and spans */
spans = iter->u.hyp.spans;
@@ -467,14 +763,33 @@ H5S__hyper_iter_init(const H5S_t *space, H5S_sel_iter_t *iter)
spans = spans->head->down;
} /* end for */
+ /* Set up information for computing slab sizes */
+ slab_dim = iter->rank - 1;
+ slab_size = iter->dims;
+
/* Flag the diminfo information as not valid in the iterator */
iter->u.hyp.diminfo_valid = FALSE;
} /* end else */
+ /* Compute the cumulative size of dataspace dimensions */
+ for(i = (int)slab_dim, acc = iter->elmt_size; i >= 0; i--) {
+ iter->u.hyp.slab[i] = acc;
+ acc *= slab_size[i];
+ } /* end for */
+
+ /* Initialize more information for irregular hyperslab selections */
+ if(!iter->u.hyp.diminfo_valid) {
+ /* Set the offset of the first element iterated on, in each dimension */
+ for(u = 0; u < rank; u++)
+ /* Compute the sequential element offset */
+ iter->u.hyp.loc_off[u] = ((hsize_t)((hssize_t)iter->u.hyp.off[u] + iter->sel_off[u])) * iter->u.hyp.slab[u];
+ } /* end if */
+
/* Initialize type of selection iterator */
iter->type = H5S_sel_iter_hyper;
- FUNC_LEAVE_NOAPI(SUCCEED)
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
} /* end H5S__hyper_iter_init() */
@@ -1077,226 +1392,1461 @@ H5S__hyper_iter_next_block(H5S_sel_iter_t *iter)
/*--------------------------------------------------------------------------
NAME
- H5S__hyper_iter_release
+ H5S__hyper_iter_get_seq_list_gen
PURPOSE
- Release hyperslab selection iterator information for a dataspace
+ Create a list of offsets & lengths for a selection
USAGE
- herr_t H5S__hyper_iter_release(iter)
- H5S_sel_iter_t *iter; IN: Pointer to selection iterator
+ herr_t H5S__hyper_iter_get_seq_list_gen(iter,maxseq,maxelem,nseq,nelem,off,len)
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last
+ position of interest in selection.
+ size_t maxseq; IN: Maximum number of sequences to generate
+ size_t maxelem; IN: Maximum number of elements to include in the
+ generated sequences
+ size_t *nseq; OUT: Actual number of sequences generated
+ size_t *nelem; OUT: Actual number of elements in sequences generated
+ hsize_t *off; OUT: Array of offsets
+ size_t *len; OUT: Array of lengths
RETURNS
Non-negative on success/Negative on failure
DESCRIPTION
- Releases all information for a dataspace hyperslab selection iterator
+ Use the selection in the dataspace to generate a list of byte offsets and
+ lengths for the region(s) selected. Start/Restart from the position in the
+ ITER parameter. The number of sequences generated is limited by the MAXSEQ
+ parameter and the number of sequences actually generated is stored in the
+ NSEQ parameter.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
static herr_t
-H5S__hyper_iter_release(H5S_sel_iter_t *iter)
+H5S__hyper_iter_get_seq_list_gen(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem,
+ size_t *nseq, size_t *nelem, hsize_t *off, size_t *len)
{
+ H5S_hyper_span_t *curr_span; /* Current hyperslab span node */
+ H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */
+ hsize_t *slab; /* Cumulative size of each dimension in bytes */
+ hsize_t loc_off; /* Byte offset in the dataspace */
+ hsize_t last_span_end = 0; /* The offset of the end of the last span */
+ hsize_t *abs_arr; /* Absolute hyperslab span position, in elements */
+ hsize_t *loc_arr; /* Byte offset of hyperslab span position within buffer */
+ const hssize_t *sel_off; /* Offset within the dataspace extent */
+ size_t span_elmts = 0; /* Number of elements to actually use for this span */
+ size_t span_size = 0; /* Number of bytes in current span to actually process */
+ size_t io_left; /* Initial number of elements to process */
+ size_t io_elmts_left; /* Number of elements left to process */
+ size_t io_used; /* Number of elements processed */
+ size_t curr_seq = 0; /* Number of sequence/offsets stored in the arrays */
+ size_t elem_size; /* Size of each element iterating over */
+ unsigned ndims; /* Number of dimensions of dataset */
+ unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ int curr_dim; /* Current dimension being operated on */
+ unsigned u; /* Index variable */
+
FUNC_ENTER_STATIC_NOERR
/* Check args */
HDassert(iter);
+ HDassert(maxseq > 0);
+ HDassert(maxelem > 0);
+ HDassert(nseq);
+ HDassert(nelem);
+ HDassert(off);
+ HDassert(len);
-/* Release the information needed for non-regular hyperslab I/O */
- /* Free the copy of the selections span tree */
- if(iter->u.hyp.spans != NULL)
- H5S__hyper_free_span_info(iter->u.hyp.spans);
+ /* Set the rank of the fastest changing dimension */
+ ndims = iter->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;
+ loc_arr = iter->u.hyp.loc_off;
+ slab = iter->u.hyp.slab;
+ sel_off = iter->sel_off;
+ ispan = iter->u.hyp.span;
+ elem_size = iter->elmt_size;
+
+ /* Set the amount of elements to perform I/O on, etc. */
+ H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t);
+ io_elmts_left = io_left = MIN(maxelem, (size_t)iter->elmt_left);
+
+ /* Set the offset of the first element iterated on */
+ for(u = 0, loc_off = 0; u < ndims; u++)
+ loc_off += loc_arr[u];
+
+ /* 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 elements to attempt in this span */
+ H5_CHECKED_ASSIGN(span_elmts, size_t, ((curr_span->high - abs_arr[fast_dim]) + 1), hsize_t);
+
+ /* Check number of elements against upper bounds allowed */
+ if(span_elmts > io_elmts_left)
+ span_elmts = io_elmts_left;
+
+ /* Set the span_size, in bytes */
+ span_size = span_elmts * elem_size;
+
+ /* 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_elmts_left -= span_elmts;
+
+ /* Check if we are done */
+ if(io_elmts_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;
+ loc_arr[fast_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[fast_dim])) * slab[fast_dim];
+ ispan[fast_dim] = curr_span;
+ } /* end if */
+ } /* end if */
+ else {
+ /* Advance the hyperslab iterator */
+ abs_arr[fast_dim] += span_elmts;
+
+ /* Check if we are still within the span */
+ if(abs_arr[fast_dim] <= curr_span->high) {
+ /* Sanity check */
+ HDassert(ispan[fast_dim] == curr_span);
+
+ /* Update byte offset */
+ loc_arr[fast_dim] += span_size;
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span = curr_span->next;
+
+ /* 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;
+
+ /* Update location offset */
+ loc_arr[fast_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[fast_dim])) * slab[fast_dim];
+
+ /* Reset the span in the current dimension */
+ ispan[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 = ispan[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) {
+ /* Update location offset */
+ loc_arr[curr_dim] += slab[curr_dim];
+
+ break;
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span = curr_span->next;
+
+ /* Check if we have a valid span in this dimension still */
+ if(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;
+
+ /* Update byte location */
+ loc_arr[curr_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[curr_dim])) * slab[curr_dim];
+
+ break;
+ } /* end if */
+ else
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
+ } /* end while */
+
+ /* Check if we have more spans in the tree */
+ if(curr_dim >= 0) {
+ /* Walk back down the iterator positions, resetting them */
+ while((unsigned)curr_dim < fast_dim) {
+ HDassert(curr_span);
+ HDassert(curr_span->down);
+ HDassert(curr_span->down->head);
+
+ /* 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;
+
+ /* Update the location offset */
+ loc_arr[curr_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[curr_dim])) * slab[curr_dim];
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ HDassert(curr_span == ispan[fast_dim]);
+
+ /* Reset the buffer offset */
+ for(u = 0, loc_off = 0; u < ndims; u++)
+ loc_off += loc_arr[u];
+ } /* end else */
+ else
+ /* We had better be done with I/O or bad things are going to happen... */
+ HDassert(io_elmts_left == 0);
+ } /* end if */
+ } /* end if */
+
+ /* Perform the I/O on the elements, based on the position of the iterator */
+ while(io_elmts_left > 0 && curr_seq < maxseq) {
+ H5S_hyper_span_t *prev_span; /* Previous hyperslab span node */
+
+ /* Sanity check */
+ HDassert(curr_span);
+
+ /* Set to current span, so the first adjustment to loc_off is 0 */
+ prev_span = curr_span;
+
+ /* Loop over all the spans in the fastest changing dimension */
+ while(curr_span != NULL) {
+ hsize_t nelmts; /* # of elements covered by current span */
+
+ /* Move location offset of current span */
+ loc_off += (curr_span->low - prev_span->low) * elem_size;
+
+ /* Compute the number of elements to attempt in this span */
+ nelmts = (curr_span->high - curr_span->low) + 1;
+ H5_CHECKED_ASSIGN(span_elmts, size_t, nelmts, hsize_t);
+
+ /* Check number of elements against upper bounds allowed */
+ if(span_elmts >= io_elmts_left) {
+ /* Trim the number of elements to output */
+ span_elmts = io_elmts_left;
+ span_size = span_elmts * elem_size;
+ io_elmts_left = 0;
+
+/* 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 */
+/* end COMMON */
+
+ /* Break out now, we are finished with I/O */
+ break;
+ } /* end if */
+ else {
+ /* Decrement I/O left to perform */
+ span_size = span_elmts * elem_size;
+ io_elmts_left -= span_elmts;
+
+/* 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 */
+/* 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 */
+
+ /* Set the location of the last span's end */
+ last_span_end = loc_off + span_size;
+
+ /* Move to next span in fastest changing dimension */
+ prev_span = curr_span;
+ curr_span = curr_span->next;
+ } /* end while */
+
+ /* Check if we are done */
+ if(io_elmts_left == 0 || curr_seq >= maxseq) {
+ /* Sanity checks */
+ HDassert(curr_span);
+
+ /* Update absolute position */
+ abs_arr[fast_dim] = curr_span->low + span_elmts;
+
+ /* Check if we are still within the span */
+ if(abs_arr[fast_dim] <= curr_span->high) {
+ /* Reset the span for the fast dimension */
+ ispan[fast_dim] = curr_span;
+
+ /* Update location offset */
+ loc_arr[fast_dim] = ((hsize_t)((hssize_t)curr_span->low + (hssize_t)span_elmts + sel_off[fast_dim])) * slab[fast_dim];
+
+ break;
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span = curr_span->next;
+
+ /* Check if we have a valid span in this dimension still */
+ if(curr_span != NULL) {
+ /* Reset absolute position */
+ abs_arr[fast_dim] = curr_span->low;
+ loc_arr[fast_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[fast_dim])) * slab[fast_dim];
+ ispan[fast_dim] = curr_span;
+
+ break;
+ } /* end if */
+ } /* end else */
+ } /* end 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 = ispan[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) {
+ /* Update location offset */
+ loc_arr[curr_dim] += slab[curr_dim];
+
+ break;
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span = curr_span->next;
+
+ /* Check if we have a valid span in this dimension still */
+ if(curr_span != NULL) {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim] = curr_span;
+
+ /* Reset absolute position */
+ abs_arr[curr_dim] = curr_span->low;
+
+ /* Update location offset */
+ loc_arr[curr_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[curr_dim])) * slab[curr_dim];
+
+ break;
+ } /* end if */
+ else
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
+ } /* end while */
+
+ /* Check if we are finished with the spans in the tree */
+ if(curr_dim < 0) {
+ /* We had better be done with I/O or bad things are going to happen... */
+ HDassert(io_elmts_left == 0);
+ break;
+ } /* end if */
+ else {
+ /* Walk back down the iterator positions, resetting them */
+ while((unsigned)curr_dim < fast_dim) {
+ HDassert(curr_span);
+ HDassert(curr_span->down);
+ HDassert(curr_span->down->head);
+
+ /* Increment current dimension to the next dimension down */
+ curr_dim++;
+
+ /* Set the new span for the next dimension down */
+ ispan[curr_dim] = curr_span->down->head;
+
+ /* Advance span down the tree */
+ curr_span = curr_span->down->head;
+
+ /* Reset the absolute offset for the dim */
+ abs_arr[curr_dim] = curr_span->low;
+
+ /* Update location offset */
+ loc_arr[curr_dim] = ((hsize_t)((hssize_t)curr_span->low + sel_off[curr_dim])) * slab[curr_dim];
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ HDassert(curr_span == ispan[fast_dim]);
+ } /* end else */
+
+ /* Reset the buffer offset */
+ for(u = 0, loc_off = 0; u < ndims; u++)
+ loc_off += loc_arr[u];
+ } /* end while */
+
+ /* Decrement number of elements left in iterator */
+ io_used = io_left - io_elmts_left;
+ iter->elmt_left -= io_used;
+
+ /* Set the number of sequences generated */
+ *nseq = curr_seq;
+
+ /* Set the number of elements used */
+ *nelem = io_used;
FUNC_LEAVE_NOAPI(SUCCEED)
-} /* end H5S__hyper_iter_release() */
+} /* end H5S__hyper_iter_get_seq_list_gen() */
/*--------------------------------------------------------------------------
NAME
- H5S__hyper_new_span
+ H5S__hyper_iter_get_seq_list_opt
PURPOSE
- Make a new hyperslab span node
+ Create a list of offsets & lengths for a selection
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
+ herr_t H5S__hyper_iter_get_seq_list_opt(iter,maxseq,maxelem,nseq,nelem,off,len)
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last
+ position of interest in selection.
+ size_t maxseq; IN: Maximum number of sequences to generate
+ size_t maxelem; IN: Maximum number of elements to include in the
+ generated sequences
+ size_t *nseq; OUT: Actual number of sequences generated
+ size_t *nelem; OUT: Actual number of elements in sequences generated
+ hsize_t *off; OUT: Array of offsets
+ size_t *len; OUT: Array of lengths
RETURNS
- Pointer to next span node on success, NULL on failure
+ Non-negative on success/Negative 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.
+ 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 H5S_hyper_span_t *
-H5S__hyper_new_span(hsize_t low, hsize_t high, H5S_hyper_span_info_t *down, H5S_hyper_span_t *next)
+static herr_t
+H5S__hyper_iter_get_seq_list_opt(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem,
+ size_t *nseq, size_t *nelem, hsize_t *off, size_t *len)
{
- H5S_hyper_span_t *ret_value = NULL; /* Return value */
+ hsize_t *mem_size; /* Size of the source buffer */
+ hsize_t *slab; /* Hyperslab size */
+ const hssize_t *sel_off; /* Selection offset in dataspace */
+ hsize_t offset[H5S_MAX_RANK]; /* Coordinate offset in dataspace */
+ hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary block count */
+ hsize_t tmp_block[H5S_MAX_RANK]; /* Temporary block offset */
+ hsize_t wrap[H5S_MAX_RANK]; /* Bytes to wrap around at the end of a row */
+ hsize_t skip[H5S_MAX_RANK]; /* Bytes to skip between blocks */
+ const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
+ hsize_t fast_dim_start, /* Local copies of fastest changing dimension info */
+ fast_dim_stride,
+ fast_dim_block,
+ fast_dim_offset;
+ size_t fast_dim_buf_off; /* Local copy of amount to move fastest dimension buffer offset */
+ size_t fast_dim_count; /* Number of blocks left in fastest changing dimension */
+ size_t tot_blk_count; /* Total number of blocks left to output */
+ size_t act_blk_count; /* Actual number of blocks to output */
+ size_t total_rows; /* Total number of entire rows to output */
+ size_t curr_rows; /* Current number of entire rows to output */
+ unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ unsigned ndims; /* Number of dimensions of dataset */
+ int temp_dim; /* Temporary rank holder */
+ hsize_t loc; /* Coordinate offset */
+ size_t curr_seq = 0; /* Current sequence being operated on */
+ size_t actual_elem; /* The actual number of elements to count */
+ size_t actual_bytes;/* The actual number of bytes to copy */
+ size_t io_left; /* The number of elements left in I/O operation */
+ size_t start_io_left; /* The initial number of elements left in I/O operation */
+ size_t elem_size; /* Size of each element iterating over */
+ unsigned u; /* Local index variable */
- FUNC_ENTER_STATIC
+ FUNC_ENTER_STATIC_NOERR
- /* 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")
+ /* Check args */
+ HDassert(iter);
+ HDassert(maxseq > 0);
+ HDassert(maxelem > 0);
+ HDassert(nseq);
+ HDassert(nelem);
+ HDassert(off);
+ HDassert(len);
- /* 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;
+ /* Set the local copy of the diminfo pointer */
+ tdiminfo = iter->u.hyp.diminfo;
- /* Increment the reference count of the 'down span' if there is one */
- if(ret_value->down)
- ret_value->down->count++;
+ /* Check if this is a "flattened" regular hyperslab selection */
+ if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank) {
+ /* Set the aliases for a few important dimension ranks */
+ ndims = iter->u.hyp.iter_rank;
-done:
- FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5S__hyper_new_span() */
+ /* Set the local copy of the selection offset */
+ sel_off = iter->u.hyp.sel_off;
+
+ /* Set up the pointer to the size of the memory dataspace */
+ mem_size = iter->u.hyp.size;
+ } /* end if */
+ else {
+ /* Set the aliases for a few important dimension ranks */
+ ndims = iter->rank;
+
+ /* Set the local copy of the selection offset */
+ sel_off = iter->sel_off;
+
+ /* Set up the pointer to the size of the memory dataspace */
+ mem_size = iter->dims;
+ } /* end else */
+
+ /* Set up some local variables */
+ fast_dim = ndims - 1;
+ elem_size = iter->elmt_size;
+ slab = iter->u.hyp.slab;
+
+ /* 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
+ H5_ATTR_FALLTHROUGH
+ case 7:
+ DUFF_GUTS
+ H5_ATTR_FALLTHROUGH
+ case 6:
+ DUFF_GUTS
+ H5_ATTR_FALLTHROUGH
+ case 5:
+ DUFF_GUTS
+ H5_ATTR_FALLTHROUGH
+ case 4:
+ DUFF_GUTS
+ H5_ATTR_FALLTHROUGH
+ case 3:
+ DUFF_GUTS
+ H5_ATTR_FALLTHROUGH
+ case 2:
+ DUFF_GUTS
+ H5_ATTR_FALLTHROUGH
+ case 1:
+ DUFF_GUTS
+ } while (--duffs_index > 0);
+ } /* end switch */
+ }
+#endif /* NO_DUFFS_DEVICE */
+#undef DUFF_GUTS
+
+ /* Increment offset in destination buffer */
+ loc += wrap[fast_dim];
+
+ /* Increment the offset and count for the other dimensions */
+ temp_dim = (int)fast_dim - 1;
+ while(temp_dim >= 0) {
+ /* Move to the next row in the curent dimension */
+ offset[temp_dim]++;
+ tmp_block[temp_dim]++;
+
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(tmp_block[temp_dim] < tdiminfo[temp_dim].block)
+ break;
+ else {
+ /* Move to the next block in the current dimension */
+ offset[temp_dim] += (tdiminfo[temp_dim].stride - tdiminfo[temp_dim].block);
+ loc += skip[temp_dim];
+ tmp_block[temp_dim] = 0;
+ tmp_count[temp_dim]++;
+
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(tmp_count[temp_dim] < tdiminfo[temp_dim].count)
+ break;
+ else {
+ offset[temp_dim] = (hsize_t)((hssize_t)tdiminfo[temp_dim].start + sel_off[temp_dim]);
+ loc += wrap[temp_dim];
+ tmp_count[temp_dim] = 0; /* reset back to the beginning of the line */
+ tmp_block[temp_dim] = 0;
+ } /* end else */
+ } /* end else */
+
+ /* Decrement dimension count */
+ temp_dim--;
+ } /* end while */
+
+ /* Decrement the number of rows left */
+ curr_rows--;
+ } /* end while */
+
+ /* Adjust the number of blocks & elements left to transfer */
+
+ /* Decrement number of elements left */
+ H5_CHECK_OVERFLOW(actual_elem * (total_rows * tdiminfo[fast_dim].count), hsize_t, size_t);
+ io_left -= (size_t)(actual_elem * (total_rows * tdiminfo[fast_dim].count));
+
+ /* Decrement number of blocks left */
+ H5_CHECK_OVERFLOW((total_rows * tdiminfo[fast_dim].count), hsize_t, size_t);
+ tot_blk_count -= (size_t)(total_rows * tdiminfo[fast_dim].count);
+
+ /* Read in partial row of blocks */
+ if(io_left > 0 && curr_seq < maxseq) {
+ /* Get remaining number of blocks left to output */
+ fast_dim_count = tot_blk_count;
+
+ /* Loop over all the blocks in the fastest changing dimension */
+ while(fast_dim_count > 0) {
+ /* Store the sequence information */
+ off[curr_seq] = loc;
+ len[curr_seq] = actual_bytes;
+
+ /* Increment sequence count */
+ curr_seq++;
+
+ /* Increment information to reflect block just processed */
+ loc += fast_dim_buf_off;
+
+ /* Decrement number of blocks */
+ fast_dim_count--;
+ } /* end while */
+
+ /* Decrement number of elements left */
+ io_left -= actual_elem * tot_blk_count;
+
+ /* Increment information to reflect block just processed */
+ offset[fast_dim] += (fast_dim_stride * tot_blk_count); /* move the offset in the fastest dimension */
+
+ /* Handle any leftover, partial blocks in this row */
+ if(io_left > 0 && curr_seq < maxseq) {
+ actual_elem = io_left;
+ actual_bytes = actual_elem * elem_size;
+
+ /* Store the sequence information */
+ off[curr_seq] = loc;
+ len[curr_seq] = actual_bytes;
+
+ /* Increment sequence count */
+ curr_seq++;
+
+ /* Decrement the number of elements left */
+ io_left -= actual_elem;
+
+ /* Increment buffer correctly */
+ offset[fast_dim] += actual_elem;
+ } /* end if */
+
+ /* don't bother checking slower dimensions */
+ HDassert(io_left == 0 || curr_seq == maxseq);
+ } /* end if */
+
+ /* Update the iterator */
+
+ /* Update the iterator with the location we stopped */
+ /* (Subtract out the selection offset) */
+ for(u = 0; u < ndims; u++)
+ iter->u.hyp.off[u] = (hsize_t)((hssize_t)offset[u] - sel_off[u]);
+
+ /* Decrement the number of elements left in selection */
+ iter->elmt_left -= (start_io_left - io_left);
+
+ /* Increment the number of sequences generated */
+ *nseq += curr_seq;
+
+ /* Increment the number of elements used */
+ *nelem += start_io_left - io_left;
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S__hyper_iter_get_seq_list_opt() */
/*--------------------------------------------------------------------------
NAME
- H5S__hyper_span_precompute_helper
+ H5S__hyper_iter_get_seq_list_single
PURPOSE
- Helper routine to precompute the nelem and pstrides in bytes.
+ Create a list of offsets & lengths for a selection
USAGE
- void H5S__hyper_span_precompute_helper(span_info, elmt_size)
- H5S_hyper_span_info_t *span_info; IN/OUT: Span tree to work on
- size_t elmt_size; IN: element size to work with
+ herr_t H5S__hyper_iter_get_seq_list_single(flags, iter, maxseq, maxelem, nseq, nelem, off, len)
+ unsigned flags; IN: Flags for extra information about operation
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last
+ position of interest in selection.
+ size_t maxseq; IN: Maximum number of sequences to generate
+ size_t maxelem; IN: Maximum number of elements to include in the
+ generated sequences
+ size_t *nseq; OUT: Actual number of sequences generated
+ size_t *nelem; OUT: Actual number of elements in sequences generated
+ hsize_t *off; OUT: Array of offsets
+ size_t *len; OUT: Array of lengths
RETURNS
- None
+ 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.
+ 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 void
-H5S__hyper_span_precompute_helper(H5S_hyper_span_info_t *spans, size_t elmt_size)
+static herr_t
+H5S__hyper_iter_get_seq_list_single(H5S_sel_iter_t *iter, size_t maxseq, size_t maxelem,
+ size_t *nseq, size_t *nelem, hsize_t *off, size_t *len)
{
+ const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
+ const hssize_t *sel_off; /* Selection offset in dataspace */
+ hsize_t *mem_size; /* Size of the source buffer */
+ hsize_t base_offset[H5S_MAX_RANK]; /* Base coordinate offset in dataspace */
+ hsize_t offset[H5S_MAX_RANK]; /* Coordinate offset in dataspace */
+ hsize_t *slab; /* Hyperslab size */
+ hsize_t fast_dim_block; /* Local copies of fastest changing dimension info */
+ hsize_t loc; /* Coordinate offset */
+ size_t tot_blk_count; /* Total number of blocks left to output */
+ size_t elem_size; /* Size of each element iterating over */
+ size_t io_left; /* The number of elements left in I/O operation */
+ size_t actual_elem; /* The actual number of elements to count */
+ unsigned ndims; /* Number of dimensions of dataset */
+ unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ unsigned skip_dim; /* Rank of the dimension to skip along */
+ unsigned u; /* Local index variable */
+
FUNC_ENTER_STATIC_NOERR
- /* Sanity checks */
- HDassert(spans);
- HDassert(spans->scratch == (H5S_hyper_span_info_t *)~((size_t)NULL) ||
- spans->scratch == NULL);
+ /* Check args */
+ HDassert(iter);
+ HDassert(maxseq > 0);
+ HDassert(maxelem > 0);
+ HDassert(nseq);
+ HDassert(nelem);
+ HDassert(off);
+ HDassert(len);
- /* Check if we've already set this down span tree */
- if(spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)) {
- H5S_hyper_span_t *span; /* Hyperslab span */
+ /* Set a local copy of the diminfo pointer */
+ tdiminfo = iter->u.hyp.diminfo;
- /* Set the tree's scratch pointer */
- spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL);
+ /* Check if this is a "flattened" regular hyperslab selection */
+ if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank) {
+ /* Set the aliases for a few important dimension ranks */
+ ndims = iter->u.hyp.iter_rank;
- /* Set the scratch pointers in all the nodes */
- span = spans->head;
+ /* Set the local copy of the selection offset */
+ sel_off = iter->u.hyp.sel_off;
- /* Loop over all the spans for this down span tree */
- while(span != NULL) {
- /* If there are down spans, precompute their values also */
- if(span->down != NULL)
- H5S__hyper_span_precompute_helper(span->down, elmt_size);
+ /* Set up the pointer to the size of the memory dataspace */
+ mem_size = iter->u.hyp.size;
+ } /* end if */
+ else {
+ /* Set the aliases for a few important dimension ranks */
+ ndims = iter->rank;
- /* Change the nelem & pstride values into bytes */
- span->nelem *= elmt_size;
- span->pstride *= elmt_size;
+ /* Set the local copy of the selection offset */
+ sel_off = iter->sel_off;
- /* Advance to next span */
- span = span->next;
- } /* end while */
+ /* Set up the pointer to the size of the memory dataspace */
+ mem_size = iter->dims;
+ } /* end else */
+
+ /* Set up some local variables */
+ fast_dim = ndims - 1;
+ elem_size = iter->elmt_size;
+ slab = iter->u.hyp.slab;
+
+ /* Copy the base location of the block */
+ /* (Add in the selection offset) */
+ for(u = 0; u < ndims; u++)
+ base_offset[u] = (hsize_t)((hssize_t)tdiminfo[u].start + sel_off[u]);
+
+ /* Copy the location of the point to get */
+ /* (Add in the selection offset) */
+ for(u = 0; u < ndims; u++)
+ offset[u] = (hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u]);
+
+ /* Compute the initial buffer offset */
+ for(u = 0, loc = 0; u < ndims; u++)
+ loc += offset[u] * slab[u];
+
+ /* Set local copies of information for the fastest changing dimension */
+ fast_dim_block = tdiminfo[fast_dim].block;
+
+ /* Calculate the number of elements to sequence through */
+ H5_CHECK_OVERFLOW(iter->elmt_left, hsize_t, size_t);
+ io_left = MIN((size_t)iter->elmt_left, maxelem);
+
+ /* Compute the number of blocks which would fit into the buffer */
+ H5_CHECK_OVERFLOW(io_left / fast_dim_block, hsize_t, size_t);
+ tot_blk_count = (size_t)(io_left / fast_dim_block);
+
+ /* Don't go over the maximum number of sequences allowed */
+ tot_blk_count = MIN(tot_blk_count, maxseq);
+
+ /* Set the number of elements to write each time */
+ H5_CHECKED_ASSIGN(actual_elem, size_t, fast_dim_block, hsize_t);
+
+ /* Check for blocks to operate on */
+ if(tot_blk_count > 0) {
+ size_t actual_bytes; /* The actual number of bytes to copy */
+
+ /* Set the number of actual bytes */
+ actual_bytes = actual_elem * elem_size;
+
+ /* Check for 1-dim selection */
+ if(0 == fast_dim) {
+ /* Sanity checks */
+ HDassert(1 == tot_blk_count);
+ HDassert(io_left == actual_elem);
+
+ /* Store the sequence information */
+ *off++ = loc;
+ *len++ = actual_bytes;
+ } /* end if */
+ else {
+ hsize_t skip_slab; /* Temporary copy of slab[fast_dim - 1] */
+ size_t blk_count; /* Total number of blocks left to output */
+ int i; /* Local index variable */
+
+ /* Find first dimension w/block >1 */
+ skip_dim = fast_dim;
+ for(i = (int)(fast_dim - 1); i >= 0; i--)
+ if(tdiminfo[i].block > 1) {
+ skip_dim = (unsigned)i;
+ break;
+ } /* end if */
+ skip_slab = slab[skip_dim];
+
+ /* Check for being able to use fast algorithm for 1-D */
+ if(0 == skip_dim) {
+ /* Create sequences until an entire row can't be used */
+ blk_count = tot_blk_count;
+ while(blk_count > 0) {
+ /* Store the sequence information */
+ *off++ = loc;
+ *len++ = actual_bytes;
+
+ /* Increment offset in destination buffer */
+ loc += skip_slab;
+
+ /* Decrement block count */
+ blk_count--;
+ } /* end while */
+
+ /* Move to the next location */
+ offset[skip_dim] += tot_blk_count;
+ } /* end if */
+ else {
+ hsize_t tmp_block[H5S_MAX_RANK]; /* Temporary block offset */
+ hsize_t skip[H5S_MAX_RANK]; /* Bytes to skip between blocks */
+ int temp_dim; /* Temporary rank holder */
+
+ /* Set the starting block location */
+ for(u = 0; u < ndims; u++)
+ tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start;
+
+ /* Compute the amount to skip between sequences */
+ for(u = 0; u < ndims; u++)
+ skip[u] = (mem_size[u] - tdiminfo[u].block) * slab[u];
+
+ /* Create sequences until an entire row can't be used */
+ blk_count = tot_blk_count;
+ while(blk_count > 0) {
+ /* Store the sequence information */
+ *off++ = loc;
+ *len++ = actual_bytes;
+
+ /* Set temporary dimension for advancing offsets */
+ temp_dim = (int)skip_dim;
+
+ /* Increment offset in destination buffer */
+ loc += skip_slab;
+
+ /* Increment the offset and count for the other dimensions */
+ while(temp_dim >= 0) {
+ /* Move to the next row in the curent dimension */
+ offset[temp_dim]++;
+ tmp_block[temp_dim]++;
+
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(tmp_block[temp_dim] < tdiminfo[temp_dim].block)
+ break;
+ else {
+ offset[temp_dim] = base_offset[temp_dim];
+ loc += skip[temp_dim];
+ tmp_block[temp_dim] = 0;
+ } /* end else */
+
+ /* Decrement dimension count */
+ temp_dim--;
+ } /* end while */
+
+ /* Decrement block count */
+ blk_count--;
+ } /* end while */
+ } /* end else */
+ } /* end else */
+
+ /* Update the iterator, if there were any blocks used */
+
+ /* Decrement the number of elements left in selection */
+ iter->elmt_left -= tot_blk_count * actual_elem;
+
+ /* Check if there are elements left in iterator */
+ if(iter->elmt_left > 0) {
+ /* Update the iterator with the location we stopped */
+ /* (Subtract out the selection offset) */
+ for(u = 0; u < ndims; u++)
+ iter->u.hyp.off[u] = (hsize_t)((hssize_t)offset[u] - sel_off[u]);
+ } /* end if */
+
+ /* Increment the number of sequences generated */
+ *nseq += tot_blk_count;
+
+ /* Increment the number of elements used */
+ *nelem += tot_blk_count * actual_elem;
} /* end if */
- FUNC_LEAVE_NOAPI_VOID
-} /* end H5S__hyper_span_precompute_helper() */
+ /* Check for partial block, with room for another sequence */
+ if(io_left > (tot_blk_count * actual_elem) && tot_blk_count < maxseq) {
+ size_t elmt_remainder; /* Elements remaining */
+
+ /* Compute elements left */
+ elmt_remainder = io_left - (tot_blk_count * actual_elem);
+ HDassert(elmt_remainder < fast_dim_block);
+ HDassert(elmt_remainder > 0);
+
+ /* Store the sequence information */
+ *off++ = loc;
+ *len++ = elmt_remainder * elem_size;
+
+ /* Update the iterator with the location we stopped */
+ iter->u.hyp.off[fast_dim] += (hsize_t)elmt_remainder;
+
+ /* Decrement the number of elements left in selection */
+ iter->elmt_left -= elmt_remainder;
+
+ /* Increment the number of sequences generated */
+ (*nseq)++;
+
+ /* Increment the number of elements used */
+ *nelem += elmt_remainder;
+ } /* end if */
+
+ /* Sanity check */
+ HDassert(*nseq > 0);
+ HDassert(*nelem > 0);
+
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S__hyper_iter_get_seq_list_single() */
/*--------------------------------------------------------------------------
NAME
- H5S__hyper_span_precompute
+ H5S__hyper_iter_get_seq_list
PURPOSE
- Precompute the nelem and pstrides in bytes.
+ Create a list of offsets & lengths for a selection
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
+ herr_t H5S__hyper_iter_get_seq_list(iter,maxseq,maxelem,nseq,nelem,off,len)
+ H5S_t *space; IN: Dataspace containing selection to use.
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator describing last
+ position of interest in selection.
+ size_t maxseq; IN: Maximum number of sequences to generate
+ size_t maxelem; IN: Maximum number of elements to include in the
+ generated sequences
+ size_t *nseq; OUT: Actual number of sequences generated
+ size_t *nelem; OUT: Actual number of elements in sequences generated
+ hsize_t *off; OUT: Array of offsets (in bytes)
+ size_t *len; OUT: Array of lengths (in bytes)
RETURNS
- Non-negative on success, negative on failure
+ 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.
+ Use the selection in the dataspace to generate a list of byte offsets and
+ lengths for the region(s) selected. Start/Restart from the position in the
+ ITER parameter. The number of sequences generated is limited by the MAXSEQ
+ parameter and the number of sequences actually generated is stored in the
+ NSEQ parameter.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
static herr_t
-H5S__hyper_span_precompute(H5S_hyper_span_info_t *spans, size_t elmt_size)
+H5S__hyper_iter_get_seq_list(H5S_sel_iter_t *iter, size_t maxseq,
+ size_t maxelem, size_t *nseq, size_t *nelem, hsize_t *off, size_t *len)
{
+ herr_t ret_value = FAIL; /* return value */
+
FUNC_ENTER_STATIC_NOERR
- HDassert(spans);
+ /* Check args */
+ HDassert(iter);
+ HDassert(iter->elmt_left > 0);
+ HDassert(maxseq > 0);
+ HDassert(maxelem > 0);
+ HDassert(nseq);
+ HDassert(nelem);
+ HDassert(off);
+ HDassert(len);
- /* Call the helper routine to actually do the work */
- H5S__hyper_span_precompute_helper(spans, elmt_size);
+ /* Check for the special case of just one H5Sselect_hyperslab call made */
+ if(iter->u.hyp.diminfo_valid) {
+ const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
+ const hssize_t *sel_off; /* Selection offset in dataspace */
+ unsigned ndims; /* Number of dimensions of dataset */
+ unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ hbool_t single_block; /* Whether the selection is a single block */
+ unsigned u; /* Local index variable */
- /* Reset the scratch pointers for the next routine which needs them */
- H5S__hyper_span_scratch(spans);
+ /* Set a local copy of the diminfo pointer */
+ tdiminfo = iter->u.hyp.diminfo;
- FUNC_LEAVE_NOAPI(SUCCEED)
-} /* end H5S__hyper_span_precompute() */
+ /* Check if this is a "flattened" regular hyperslab selection */
+ if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < iter->rank) {
+ /* Set the aliases for a few important dimension ranks */
+ ndims = iter->u.hyp.iter_rank;
+
+ /* Set the local copy of the selection offset */
+ sel_off = iter->u.hyp.sel_off;
+ } /* end if */
+ else {
+ /* Set the aliases for a few important dimension ranks */
+ ndims = iter->rank;
+
+ /* Set the local copy of the selection offset */
+ sel_off = iter->sel_off;
+ } /* end else */
+ fast_dim = ndims - 1;
+
+ /* Check if we stopped in the middle of a sequence of elements */
+ if((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride != 0 ||
+ ((iter->u.hyp.off[fast_dim] != tdiminfo[fast_dim].start) && tdiminfo[fast_dim].count == 1)) {
+ hsize_t *slab; /* Hyperslab size */
+ hsize_t loc; /* Coordinate offset */
+ size_t leftover; /* The number of elements left over from the last sequence */
+ size_t actual_elem; /* The actual number of elements to count */
+ size_t elem_size; /* Size of each element iterating over */
+
+ /* Calculate the number of elements left in the sequence */
+ if(tdiminfo[fast_dim].count == 1) {
+ H5_CHECKED_ASSIGN(leftover, size_t, tdiminfo[fast_dim].block - (iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start), hsize_t);
+ } /* end if */
+ else {
+ H5_CHECKED_ASSIGN(leftover, size_t, tdiminfo[fast_dim].block - ((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride), hsize_t);
+ } /* end else */
+
+ /* Make certain that we don't write too many */
+ actual_elem = MIN3(leftover, (size_t)iter->elmt_left, maxelem);
+
+ /* Set up some local variables */
+ elem_size = iter->elmt_size;
+ slab = iter->u.hyp.slab;
+
+ /* Compute the initial buffer offset */
+ for(u = 0, loc = 0; u < ndims; u++)
+ loc += ((hsize_t)((hssize_t)iter->u.hyp.off[u] + sel_off[u])) * slab[u];
+
+ /* Add a new sequence */
+ off[0] = loc;
+ H5_CHECKED_ASSIGN(len[0], size_t, actual_elem * elem_size, hsize_t);
+
+ /* Increment sequence array locations */
+ off++;
+ len++;
+
+ /* Advance the hyperslab iterator */
+ H5S__hyper_iter_next(iter, actual_elem);
+
+ /* Decrement the number of elements left in selection */
+ iter->elmt_left -= actual_elem;
+
+ /* Decrement element/sequence limits */
+ maxelem -= actual_elem;
+ maxseq--;
+
+ /* Set the number of sequences generated and elements used */
+ *nseq = 1;
+ *nelem = actual_elem;
+
+ /* Check for using up all the sequences/elements */
+ if(0 == iter->elmt_left || 0 == maxelem || 0 == maxseq)
+ return(SUCCEED);
+ } /* end if */
+ else {
+ /* Reset the number of sequences generated and elements used */
+ *nseq = 0;
+ *nelem = 0;
+ } /* end else */
+
+ /* Check for a single block selected */
+ single_block = TRUE;
+ for(u = 0; u < ndims; u++)
+ if(1 != tdiminfo[u].count) {
+ single_block = FALSE;
+ break;
+ } /* end if */
+
+ /* Check for single block selection */
+ if(single_block)
+ /* Use single-block optimized call to generate sequence list */
+ ret_value = H5S__hyper_iter_get_seq_list_single(iter, maxseq, maxelem, nseq, nelem, off, len);
+ else
+ /* Use optimized call to generate sequence list */
+ ret_value = H5S__hyper_iter_get_seq_list_opt(iter, maxseq, maxelem, nseq, nelem, off, len);
+ } /* end if */
+ else
+ /* Call the general sequence generator routine */
+ ret_value = H5S__hyper_iter_get_seq_list_gen(iter, maxseq, maxelem, nseq, nelem, off, len);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__hyper_iter_get_seq_list() */
/*--------------------------------------------------------------------------
NAME
- H5S__hyper_span_scratch
+ H5S__hyper_iter_release
PURPOSE
- Reset the scratch pointers on hyperslab span trees
+ Release hyperslab selection iterator information for a dataspace
USAGE
- void H5S__hyper_span_scratch(span_info)
- H5S_hyper_span_info_t *span_info; IN: Span tree to reset
+ herr_t H5S__hyper_iter_release(iter)
+ H5S_sel_iter_t *iter; IN: Pointer to selection iterator
RETURNS
- <none>
+ Non-negative on success/Negative on failure
DESCRIPTION
- Reset the scratch pointers on a hyperslab span tree to NULL.
+ Releases all information for a dataspace hyperslab selection iterator
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-static void
-H5S__hyper_span_scratch(H5S_hyper_span_info_t *spans)
+static herr_t
+H5S__hyper_iter_release(H5S_sel_iter_t *iter)
{
FUNC_ENTER_STATIC_NOERR
- HDassert(spans);
+ /* Check args */
+ HDassert(iter);
- /* Check if we've already set this down span tree */
- if(spans->scratch != NULL) {
- H5S_hyper_span_t *span; /* Hyperslab span */
+ /* Free the copy of the hyperslab selection span tree */
+ if(iter->u.hyp.spans != NULL)
+ H5S__hyper_free_span_info(iter->u.hyp.spans);
- /* Reset the tree's scratch pointer */
- spans->scratch = NULL;
+ FUNC_LEAVE_NOAPI(SUCCEED)
+} /* end H5S__hyper_iter_release() */
- /* 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);
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_new_span
+ PURPOSE
+ Make a new hyperslab span node
+ USAGE
+ H5S_hyper_span_t *H5S__hyper_new_span(low, high, down, next)
+ hsize_t low, high; IN: Low and high bounds for new span node
+ H5S_hyper_span_info_t *down; IN: Down span tree for new node
+ H5S_hyper_span_t *next; IN: Next span for new node
+ RETURNS
+ Pointer to new span node on success, NULL on failure
+ DESCRIPTION
+ Allocate and initialize a new hyperslab span node, filling in the low &
+ high bounds, the down span and next span pointers also. Increment the
+ reference count of the 'down span' if applicable.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5S_hyper_span_t *
+H5S__hyper_new_span(hsize_t low, hsize_t high, H5S_hyper_span_info_t *down,
+ H5S_hyper_span_t *next)
+{
+ H5S_hyper_span_t *ret_value = NULL; /* Return value */
- /* Advance to next span */
- span = span->next;
- } /* end while */
- } /* end if */
+ FUNC_ENTER_STATIC
- FUNC_LEAVE_NOAPI_VOID
-} /* end H5S__hyper_span_scratch() */
+ /* Allocate a new span node */
+ if(NULL == (ret_value = H5FL_MALLOC(H5S_hyper_span_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span")
+
+ /* Copy the span's basic information */
+ ret_value->low = low;
+ ret_value->high = high;
+ ret_value->down = down;
+ ret_value->next = next;
+
+ /* Increment the reference count of the 'down span' if there is one */
+ if(ret_value->down)
+ ret_value->down->count++;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__hyper_new_span() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_new_span_info
+ PURPOSE
+ Make a new hyperslab span info node
+ USAGE
+ H5S_hyper_span_info_t *H5S__hyper_new_span_info(rank)
+ unsigned rank; IN: Rank of span info, in selection
+ RETURNS
+ Pointer to new span node info on success, NULL on failure
+ DESCRIPTION
+ Allocate and initialize a new hyperslab span info node of a given rank,
+ setting up the low & high bound array pointers.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Note that this uses the C99 "flexible array member" feature.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5S_hyper_span_info_t *
+H5S__hyper_new_span_info(unsigned rank)
+{
+ H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(rank > 0);
+ HDassert(rank <= H5S_MAX_RANK);
+
+ /* Allocate a new span info node */
+ if(NULL == (ret_value = (H5S_hyper_span_info_t *)H5FL_ARR_CALLOC(hbounds_t, rank * 2)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span info")
+
+ /* Set low & high bound pointers into the 'bounds' array */
+ ret_value->low_bounds = ret_value->bounds;
+ ret_value->high_bounds = &ret_value->bounds[rank];
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__hyper_new_span_info() */
/*--------------------------------------------------------------------------
@@ -1305,8 +2855,11 @@ H5S__hyper_span_scratch(H5S_hyper_span_info_t *spans)
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 * H5S__hyper_copy_span_helper(spans, rank, op_info_i, op_gen)
H5S_hyper_span_info_t *spans; IN: Span tree to copy
+ unsigned rank; IN: Rank of span tree
+ unsigned op_info_i; IN: Index of op info to use
+ uint64_t op_gen; IN: Operation generation
RETURNS
Pointer to the copied span tree on success, NULL on failure
DESCRIPTION
@@ -1317,7 +2870,8 @@ H5S__hyper_span_scratch(H5S_hyper_span_info_t *spans)
REVISION LOG
--------------------------------------------------------------------------*/
static H5S_hyper_span_info_t *
-H5S__hyper_copy_span_helper(H5S_hyper_span_info_t *spans)
+H5S__hyper_copy_span_helper(H5S_hyper_span_info_t *spans, unsigned rank,
+ unsigned op_info_i, uint64_t op_gen)
{
H5S_hyper_span_t *span; /* Hyperslab span */
H5S_hyper_span_t *new_span; /* Temporary hyperslab span */
@@ -1329,26 +2883,30 @@ H5S__hyper_copy_span_helper(H5S_hyper_span_info_t *spans)
/* Sanity checks */
HDassert(spans);
- HDassert(spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL));
/* Check if the span tree was already copied */
- if(spans->scratch != NULL) {
+ if(spans->op_info[op_info_i].op_gen == op_gen) {
/* Just return the value of the already copied span tree */
- ret_value = spans->scratch;
+ ret_value = spans->op_info[op_info_i].u.copied;
/* Increment the reference count of the span tree */
ret_value->count++;
} /* end if */
else {
/* Allocate a new span_info node */
- if(NULL == (ret_value = H5FL_CALLOC(H5S_hyper_span_info_t)))
+ if(NULL == (ret_value = H5S__hyper_new_span_info(rank)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span info")
- /* Copy the span_info information */
+ /* Set the non-zero span_info information */
+ H5MM_memcpy(ret_value->low_bounds, spans->low_bounds, rank * sizeof(hsize_t));
+ H5MM_memcpy(ret_value->high_bounds, spans->high_bounds, rank * sizeof(hsize_t));
ret_value->count = 1;
- /* Set the scratch pointer in the node being copied to the newly allocated node */
- spans->scratch = ret_value;
+ /* Set the operation generation for the span info, to avoid future copies */
+ spans->op_info[op_info_i].op_gen = op_gen;
+
+ /* Set the 'copied' pointer in the node being copied to the newly allocated node */
+ spans->op_info[op_info_i].u.copied = ret_value;
/* Copy over the nodes in the span list */
span = spans->head;
@@ -1364,12 +2922,9 @@ H5S__hyper_copy_span_helper(H5S_hyper_span_info_t *spans)
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)))
+ if(NULL == (new_down = H5S__hyper_copy_span_helper(span->down, rank - 1, op_info_i, op_gen)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy hyperslab spans")
new_span->down = new_down;
} /* end if */
@@ -1380,6 +2935,9 @@ H5S__hyper_copy_span_helper(H5S_hyper_span_info_t *spans)
/* Advance to next span */
span = span->next;
} /* end while */
+
+ /* Retain a pointer to the last span */
+ ret_value->tail = prev_span;
} /* end else */
done:
@@ -1393,8 +2951,9 @@ done:
PURPOSE
Copy a hyperslab span tree
USAGE
- H5S_hyper_span_info_t * H5S__hyper_copy_span(span_info)
+ H5S_hyper_span_info_t * H5S__hyper_copy_span(span_info, rank)
H5S_hyper_span_info_t *span_info; IN: Span tree to copy
+ unsigned rank; IN: Rank of span tree
RETURNS
Pointer to the copied span tree on success, NULL on failure
DESCRIPTION
@@ -1407,21 +2966,25 @@ done:
REVISION LOG
--------------------------------------------------------------------------*/
static H5S_hyper_span_info_t *
-H5S__hyper_copy_span(H5S_hyper_span_info_t *spans)
+H5S__hyper_copy_span(H5S_hyper_span_info_t *spans, unsigned rank)
{
+ uint64_t op_gen; /* Operation generation value */
H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
FUNC_ENTER_STATIC
+ /* Sanity check */
HDassert(spans);
+ /* Acquire an operation generation value for this operation */
+ op_gen = H5S__hyper_get_op_gen();
+
/* Copy the hyperslab span tree */
- if(NULL == (ret_value = H5S__hyper_copy_span_helper(spans)))
+ /* Always use op_info[0] since we own this op_info, so there can be no
+ * simultaneous operations */
+ if(NULL == (ret_value = H5S__hyper_copy_span_helper(spans, rank, 0, op_gen)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree")
- /* Reset the scratch pointers for the next routine which needs them */
- H5S__hyper_span_scratch(spans);
-
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5S__hyper_copy_span() */
@@ -1449,25 +3012,28 @@ done:
static H5_ATTR_PURE hbool_t
H5S__hyper_cmp_spans(const H5S_hyper_span_info_t *span_info1, const H5S_hyper_span_info_t *span_info2)
{
- hbool_t ret_value = FALSE; /* Return value */
+ hbool_t ret_value = TRUE; /* Return value */
FUNC_ENTER_STATIC_NOERR
- /* Check for redundant comparison */
- if(span_info1 == span_info2)
- ret_value = TRUE;
- else {
- const H5S_hyper_span_t *span1;
- const H5S_hyper_span_t *span2;
-
- /* Check for both spans being NULL */
- if(span_info1 == NULL && span_info2 == NULL)
- ret_value = TRUE;
+ /* Check for redundant comparison (or both spans being NULL) */
+ if(span_info1 != span_info2) {
+ /* Check for one span being NULL */
+ if(span_info1 == NULL || span_info2 == NULL)
+ HGOTO_DONE(FALSE)
else {
- /* Check for one span being NULL */
- if(span_info1 == NULL || span_info2 == NULL)
- ret_value = FALSE;
+ /* Compare low & high bounds for this span list */
+ /* (Could compare lower dimensions also, but not certain if
+ * that's worth it. - QAK, 2019/01/23)
+ */
+ if(span_info1->low_bounds[0] != span_info2->low_bounds[0])
+ HGOTO_DONE(FALSE)
+ else if(span_info1->high_bounds[0] != span_info2->high_bounds[0])
+ HGOTO_DONE(FALSE)
else {
+ const H5S_hyper_span_t *span1;
+ const H5S_hyper_span_t *span2;
+
/* Get the pointers to the actual lists of spans */
span1 = span_info1->head;
span2 = span_info2->head;
@@ -1479,28 +3045,20 @@ H5S__hyper_cmp_spans(const H5S_hyper_span_info_t *span_info1, const H5S_hyper_sp
/* 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 */
+ if(span1 == NULL && span2 == NULL)
+ HGOTO_DONE(TRUE)
else {
/* Check for one span being NULL */
- if(span1 == NULL || span2 == NULL) {
- ret_value = FALSE;
- break;
- } /* end if */
+ if(span1 == NULL || span2 == NULL)
+ HGOTO_DONE(FALSE)
else {
/* Check if the actual low & high span information is the same */
- if(span1->low != span2->low || span1->high != span2->high) {
- ret_value = FALSE;
- break;
- } /* end if */
+ if(span1->low != span2->low || span1->high != span2->high)
+ HGOTO_DONE(FALSE)
else {
- if(span1->down != NULL || span2 != NULL) {
- if(!H5S__hyper_cmp_spans(span1->down, span2->down)) {
- ret_value = FALSE;
- break;
- } /* end if */
+ if(span1->down != NULL || span2->down != NULL) {
+ if(!H5S__hyper_cmp_spans(span1->down, span2->down))
+ HGOTO_DONE(FALSE)
else {
/* Keep going... */
} /* end else */
@@ -1518,8 +3076,11 @@ H5S__hyper_cmp_spans(const H5S_hyper_span_info_t *span_info1, const H5S_hyper_sp
} /* end while */
} /* end else */
} /* end else */
- } /* end else */
+ } /* end if */
+ /* Fall through, with default return value of 'TRUE' if spans were already visited */
+
+done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5S__hyper_cmp_spans() */
@@ -1530,10 +3091,10 @@ H5S__hyper_cmp_spans(const H5S_hyper_span_info_t *span_info1, const H5S_hyper_sp
PURPOSE
Free a hyperslab span info node
USAGE
- herr_t H5S__hyper_free_span_info(span_info)
+ void 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
+ None
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
@@ -1543,13 +3104,10 @@ H5S__hyper_cmp_spans(const H5S_hyper_span_info_t *span_info1, const H5S_hyper_sp
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-static herr_t
+static void
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_STATIC
+ FUNC_ENTER_STATIC_NOERR
/* Sanity check */
HDassert(span_info);
@@ -1559,22 +3117,28 @@ H5S__hyper_free_span_info(H5S_hyper_span_info_t *span_info)
/* Free the span tree if the reference count drops to zero */
if(span_info->count == 0) {
+ H5S_hyper_span_t *span; /* Pointer to spans to iterate over */
/* Work through the list of spans pointed to by this 'info' node */
span = span_info->head;
while(span != NULL) {
+ H5S_hyper_span_t *next_span; /* Pointer to next span to iterate over */
+
+ /* Keep a pointer to the next span */
next_span = span->next;
- if(H5S__hyper_free_span(span) < 0)
- HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab span")
+
+ /* Free the current span */
+ H5S__hyper_free_span(span);
+
+ /* Advance to next span */
span = next_span;
} /* end while */
/* Free this span info */
- span_info = H5FL_FREE(H5S_hyper_span_info_t, span_info);
+ span_info = (H5S_hyper_span_info_t *)H5FL_ARR_FREE(hbounds_t, span_info);
} /* end if */
-done:
- FUNC_LEAVE_NOAPI(ret_value)
+ FUNC_LEAVE_NOAPI_VOID
} /* end H5S__hyper_free_span_info() */
@@ -1584,10 +3148,10 @@ done:
PURPOSE
Free a hyperslab span node
USAGE
- herr_t H5S__hyper_free_span(span)
+ void H5S__hyper_free_span(span)
H5S_hyper_span_t *span; IN: Span node to free
RETURNS
- Non-negative on success, negative on failure
+ None
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
@@ -1597,26 +3161,22 @@ done:
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-static herr_t
+static void
H5S__hyper_free_span(H5S_hyper_span_t *span)
{
- herr_t ret_value = SUCCEED;
-
- FUNC_ENTER_STATIC
+ FUNC_ENTER_STATIC_NOERR
/* Sanity check */
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")
+ H5S__hyper_free_span_info(span->down);
/* Free this span */
span = H5FL_FREE(H5S_hyper_span_t, span);
-done:
- FUNC_LEAVE_NOAPI(ret_value)
+ FUNC_LEAVE_NOAPI_VOID
} /* end H5S__hyper_free_span() */
@@ -1668,15 +3228,8 @@ H5S__hyper_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection)
/* Copy the hyperslab information */
dst_hslab->diminfo_valid = src_hslab->diminfo_valid;
- if(src_hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
- size_t u; /* Local index variable */
-
- for(u=0; u<src->extent.rank; u++) {
- dst_hslab->diminfo.opt[u]=src_hslab->diminfo.opt[u];
- dst_hslab->diminfo.app[u]=src_hslab->diminfo.app[u];
- } /* end for */
- } /* end if */
- dst->select.sel_info.hslab->span_lst = src->select.sel_info.hslab->span_lst;
+ if(src_hslab->diminfo_valid == H5S_DIMINFO_VALID_YES)
+ H5MM_memcpy(&dst_hslab->diminfo, &src_hslab->diminfo, sizeof(H5S_hyper_diminfo_t));
/* Check if there is hyperslab span information to copy */
/* (Regular hyperslab information is copied with the selection structure) */
@@ -1688,7 +3241,7 @@ H5S__hyper_copy(H5S_t *dst, const H5S_t *src, hbool_t share_selection)
} /* 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);
+ dst->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(src->select.sel_info.hslab->span_lst, src->extent.rank);
} /* end if */
else
dst->select.sel_info.hslab->span_lst = NULL;
@@ -1704,18 +3257,16 @@ done:
/*--------------------------------------------------------------------------
NAME
- H5S__hyper_is_valid_helper
+ H5S__hyper_is_valid
PURPOSE
Check whether the selection fits within the extent, with the current
offset defined.
USAGE
- hbool_t H5S__hyper_is_valid_helper(spans, offset, rank);
- const H5S_hyper_span_info_t *spans; IN: Pointer to current hyperslab span tree
- const hssize_t *offset; IN: Pointer to offset array
- const hsize_t *size; IN: Pointer to size array
- hsize_t rank; IN: Current rank looking at
+ 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
+ TRUE if the selection fits within the extent, FALSE if it does not and
+ Negative on an error.
DESCRIPTION
Determines if the current selection at the current offset fits within the
extent for the dataspace.
@@ -1724,109 +3275,111 @@ done:
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-static hbool_t
-H5S__hyper_is_valid_helper(const H5S_hyper_span_info_t *spans, const hssize_t *offset,
- const hsize_t *size)
+static htri_t
+H5S__hyper_is_valid(const H5S_t *space)
{
- H5S_hyper_span_t *curr; /* Hyperslab information nodes */
- hbool_t ret_value = TRUE; /* Return value */
+ const hsize_t *low_bounds, *high_bounds; /* Pointers to the correct pair of low & high bounds */
+ unsigned u; /* Counter */
+ htri_t ret_value = TRUE; /* return value */
FUNC_ENTER_STATIC_NOERR
- HDassert(spans);
- HDassert(offset);
- HDassert(size);
+ HDassert(space);
- /* Check each point to determine whether selection + offset is within extent */
- curr = spans->head;
- while(curr != NULL) {
- /* Check if an offset has been defined */
- /* Bounds check the selected point + offset against the extent */
- if((((hssize_t)curr->low + *offset) >= (hssize_t)*size)
- || (((hssize_t)curr->low + *offset) < 0)
- || (((hssize_t)curr->high + *offset) >= (hssize_t)*size)
- || (((hssize_t)curr->high + *offset) < 0))
- HGOTO_DONE(FALSE)
+ /* Check for unlimited selection */
+ if(space->select.sel_info.hslab->unlim_dim >= 0)
+ HGOTO_DONE(FALSE)
- /* Recurse if this node has down spans */
- if(curr->down != NULL)
- if(!H5S__hyper_is_valid_helper(curr->down, offset + 1, size + 1))
- HGOTO_DONE(FALSE)
+ /* Check which set of low & high bounds we should be using */
+ if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
+ low_bounds = space->select.sel_info.hslab->diminfo.low_bounds;
+ high_bounds = space->select.sel_info.hslab->diminfo.high_bounds;
+ } /* end if */
+ else {
+ low_bounds = space->select.sel_info.hslab->span_lst->low_bounds;
+ high_bounds = space->select.sel_info.hslab->span_lst->high_bounds;
+ } /* end else */
- /* Advance to next node */
- curr = curr->next;
- } /* end while */
+ /* Check each dimension */
+ for(u = 0; u < space->extent.rank; u++) {
+ /* Bounds check the selected point + offset against the extent */
+ if(((hssize_t)low_bounds[u] + space->select.offset[u]) < 0)
+ HGOTO_DONE(FALSE)
+ if((high_bounds[u] + (hsize_t)space->select.offset[u]) >= space->extent.size[u])
+ HGOTO_DONE(FALSE)
+ } /* end for */
done:
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5S__hyper_is_valid_helper() */
+} /* end H5S__hyper_is_valid() */
/*--------------------------------------------------------------------------
NAME
- H5S__hyper_is_valid
+ H5S__hyper_span_nblocks_helper
PURPOSE
- Check whether the selection fits within the extent, with the current
- offset defined.
+ Helper routine to count the number of blocks in a span tree
USAGE
- htri_t H5S__hyper_is_valid(space);
- H5S_t *space; IN: Dataspace pointer to query
+ hsize_t H5S__hyper_span_nblocks_helper(spans, op_info_i, op_gen)
+ H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to count blocks of
+ unsigned op_info_i; IN: Index of op info to use
+ uint64_t op_gen; IN: Operation generation
RETURNS
- TRUE if the selection fits within the extent, FALSE if it does not and
- Negative on an error.
+ Number of blocks in span tree on success; negative on failure
DESCRIPTION
- Determines if the current selection at the current offset fits within the
- extent for the dataspace.
+ Counts the number of blocks described by the spans in a span tree.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-static htri_t
-H5S__hyper_is_valid(const H5S_t *space)
+static hsize_t
+H5S__hyper_span_nblocks_helper(H5S_hyper_span_info_t *spans, unsigned op_info_i,
+ uint64_t op_gen)
{
- htri_t ret_value = TRUE; /* return value */
+ hsize_t ret_value = 0; /* Return value */
FUNC_ENTER_STATIC_NOERR
- HDassert(space);
+ /* Sanity check */
+ HDassert(spans);
- /* Check for unlimited selection */
- if(space->select.sel_info.hslab->unlim_dim >= 0)
- HGOTO_DONE(FALSE)
+ /* Check if the span tree was already counted */
+ if(spans->op_info[op_info_i].op_gen == op_gen)
+ /* Just return the # of blocks in the already counted span tree */
+ ret_value = spans->op_info[op_info_i].u.nblocks;
+ else { /* Count the number of elements in the span tree */
+ H5S_hyper_span_t *span; /* Hyperslab span */
- /* Check for a "regular" hyperslab selection */
- if(H5S_DIMINFO_VALID_YES == space->select.sel_info.hslab->diminfo_valid) {
- const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->diminfo.opt; /* local alias for diminfo */
- hssize_t end; /* The high bound of a region in a dimension */
- unsigned u; /* Counter */
+ span = spans->head;
+ if(span->down) {
+ while(span) {
+ /* If there are down spans, add the total down span blocks */
+ ret_value += H5S__hyper_span_nblocks_helper(span->down, op_info_i, op_gen);
- /* 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)
+ /* Advance to next span */
+ span = span->next;
+ } /* end while */
+ } /* end if */
+ else {
+ while(span) {
+ /* If there are no down spans, just count the block in this span */
+ ret_value++;
+
+ /* Advance to next span */
+ span = span->next;
+ } /* end while */
+ } /* end else */
- /* 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];
+ /* Set the operation generation for this span tree, to avoid re-computing */
+ spans->op_info[op_info_i].op_gen = op_gen;
- /* 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);
+ /* Hold a copy of the # of blocks */
+ spans->op_info[op_info_i].u.nblocks = ret_value;
+ } /* end else */
-done:
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5S__hyper_is_valid() */
+} /* end H5S__hyper_span_nblocks_helper() */
/*--------------------------------------------------------------------------
@@ -1836,7 +3389,7 @@ done:
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
+ H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to count blocks of
RETURNS
Number of blocks in span tree on success; negative on failure
DESCRIPTION
@@ -1847,7 +3400,7 @@ done:
REVISION LOG
--------------------------------------------------------------------------*/
static hsize_t
-H5S__hyper_span_nblocks(const H5S_hyper_span_info_t *spans)
+H5S__hyper_span_nblocks(H5S_hyper_span_info_t *spans)
{
hsize_t ret_value = 0; /* Return value */
@@ -1855,21 +3408,16 @@ H5S__hyper_span_nblocks(const H5S_hyper_span_info_t *spans)
/* Count the number of elements in the span tree */
if(spans != NULL) {
- H5S_hyper_span_t *span; /* Hyperslab span */
+ uint64_t op_gen; /* Operation generation value */
- 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++;
+ /* Acquire an operation generation value for this operation */
+ op_gen = H5S__hyper_get_op_gen();
- /* Advance to next span */
- span = span->next;
- } /* end while */
- } /* end else */
+ /* Count the blocks */
+ /* Always use op_info[0] since we own this op_info, so there can be no
+ * simultaneous operations */
+ ret_value = H5S__hyper_span_nblocks_helper(spans, 0, op_gen);
+ } /* end if */
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5S__hyper_span_nblocks() */
@@ -1904,6 +3452,7 @@ H5S__get_select_hyper_nblocks(const H5S_t *space, hbool_t app_ref)
HDassert(space->select.sel_info.hslab->unlim_dim < 0);
/* Check for a "regular" hyperslab selection */
+ /* (No need to rebuild the dimension info yet -QAK) */
if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
unsigned u; /* Local index variable */
@@ -1962,10 +3511,43 @@ done:
/*--------------------------------------------------------------------------
NAME
+ H5S__hyper_get_enc_size_real
+ PURPOSE
+ Determine the size to encode the hyperslab selection info
+ USAGE
+ hssize_t H5S__hyper_get_enc_size_real(max_size, enc_size)
+ hsize_t max_size: IN: The maximum size of the hyperslab selection info
+ unint8_t *enc_size: OUT:The encoding size
+ RETURNS
+ The size to encode hyperslab selection info
+ DESCRIPTION
+ Determine the size by comparing "max_size" with (2^32 - 1) and (2^16 - 1).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static uint8_t
+H5S__hyper_get_enc_size_real(hsize_t max_size)
+{
+ uint8_t ret_value;
+
+ FUNC_ENTER_STATIC_NOERR
+
+ if(max_size > H5S_UINT32_MAX)
+ ret_value = H5S_SELECT_INFO_ENC_SIZE_8;
+ else
+ ret_value = H5S_SELECT_INFO_ENC_SIZE_4;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5S__hyper_get_enc_size_real() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
H5S__hyper_get_version_enc_size
PURPOSE
Determine the version and encoded size to use for encoding hyperslab selection info
- See tables 2 & 3 in the RFC: H5Sencode/H5Sdecode Format Change
USAGE
hssize_t H5S__hyper_get_version_enc_size(space, block_count, version, enc_size)
const H5S_t *space: IN: The dataspace
@@ -1977,8 +3559,10 @@ done:
The version and the size to encode hyperslab selection info
DESCRIPTION
Determine the version to use for encoding hyperslab selection info based
- on whether the number of blocks or the selection high bounds exceeds (2^32 - 1).
- Then determine the encoded size based on version.
+ on the following:
+ (1) the file format setting in fapl
+ (2) whether the number of blocks or selection high bounds exceeds H5S_UINT32_MAX or not
+
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
@@ -2144,12 +3728,13 @@ done:
PURPOSE
Serialize the current selection into a user-provided buffer.
USAGE
- void H5S__hyper_serialize_helper(spans, start, end, rank, buf)
+ void H5S__hyper_serialize_helper(spans, start, end, rank, enc_size, buf)
H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to serialize
hssize_t start[]; IN/OUT: Accumulated start points
hssize_t end[]; IN/OUT: Accumulated end points
hsize_t rank; IN: Current rank looking at
- uint8 *buf; OUT: Buffer to put serialized selection into
+ uint8_t enc_size IN: Encoded size of hyperslab selection info
+ uint8_t *buf; OUT: Buffer to put serialized selection into
RETURNS
None
DESCRIPTION
@@ -2162,7 +3747,7 @@ done:
--------------------------------------------------------------------------*/
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)
+ hsize_t *start, hsize_t *end, hsize_t rank, uint8_t enc_size, uint8_t **p)
{
H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */
uint8_t *pp = (*p); /* Local pointer for decoding */
@@ -2186,26 +3771,49 @@ H5S__hyper_serialize_helper(const H5S_hyper_span_info_t *spans,
end[rank] = curr->high;
/* Recurse down to the next dimension */
- H5S__hyper_serialize_helper(curr->down, start, end, rank + 1, &pp);
+ H5S__hyper_serialize_helper(curr->down, start, end, rank + 1, enc_size, &pp);
} /* end if */
else {
hsize_t u; /* Index variable */
/* Encode all the previous dimensions starting & ending points */
+ switch(enc_size) {
+ case H5S_SELECT_INFO_ENC_SIZE_4:
+ /* Encode previous starting points */
+ for(u=0; u<rank; u++)
+ UINT32ENCODE(pp, (uint32_t)start[u]);
- /* 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 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 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);
+ break;
+
+ case H5S_SELECT_INFO_ENC_SIZE_8:
+ /* Encode previous starting points */
+ for(u=0; u<rank; u++)
+ UINT64ENCODE(pp, (uint64_t)start[u]);
- /* Encode starting point for this span */
- UINT32ENCODE(pp, (uint32_t)curr->high);
+ /* Encode starting point for this span */
+ UINT64ENCODE(pp, (uint64_t)curr->low);
+
+ /* Encode previous ending points */
+ for(u=0; u<rank; u++)
+ UINT64ENCODE(pp, (uint64_t)end[u]);
+
+ /* Encode starting point for this span */
+ UINT64ENCODE(pp, (uint64_t)curr->high);
+ break;
+
+ default:
+ HDassert(0 && "Unknown enc size?!?");
+
+ } /* end switch */
} /* end else */
/* Advance to next node */
@@ -2256,8 +3864,8 @@ H5S__hyper_serialize(const H5S_t *space, uint8_t **p)
hsize_t block_count = 0; /* block counter for regular hyperslabs */
unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
unsigned ndims; /* Rank of the dataspace */
- unsigned i, u; /* Local counting variable */
- int done; /* Whether we are done with the iteration */
+ unsigned u; /* Local counting variable */
+ hbool_t complete = FALSE; /* Whether we are done with the iteration */
hbool_t is_regular; /* Whether selection is regular */
uint8_t enc_size; /* Encoded size */
herr_t ret_value = SUCCEED; /* return value */
@@ -2302,27 +3910,37 @@ H5S__hyper_serialize(const H5S_t *space, uint8_t **p)
/* Encode number of dimensions */
UINT32ENCODE(pp, (uint32_t)ndims);
- /* Check for a "regular" hyperslab selection */
if(is_regular) {
-
- /* If flags indicates a regular hyperslab or unlimited dimension, encode diminfo.opt */
if(version == H5S_HYPER_VERSION_2) {
-
HDassert(H5S_UNLIMITED == HSIZE_UNDEF);
- HDassert(enc_size == H5S_SELECT_INFO_ENC_SIZE_8);
/* Iterate over dimensions */
/* Encode start/stride/block/count */
- for(i = 0; i < space->extent.rank; i++) {
- UINT64ENCODE(pp, diminfo[i].start);
- UINT64ENCODE(pp, diminfo[i].stride);
- UINT64ENCODE(pp, diminfo[i].count);
- UINT64ENCODE(pp, diminfo[i].block);
- } /* end for */
- len += (4 * space->extent.rank * 8);
- } else {
+ switch(enc_size) {
+ case H5S_SELECT_INFO_ENC_SIZE_8:
+ HDassert(version == H5S_HYPER_VERSION_2);
+ for(u = 0; u < space->extent.rank; u++) {
+ UINT64ENCODE(pp, diminfo[u].start);
+ UINT64ENCODE(pp, diminfo[u].stride);
+ if(diminfo[u].count == H5S_UNLIMITED)
+ UINT64ENCODE(pp, H5S_UINT64_MAX)
+ else
+ UINT64ENCODE(pp, diminfo[u].count)
+ if(diminfo[u].block == H5S_UNLIMITED)
+ UINT64ENCODE(pp, H5S_UINT64_MAX)
+ else
+ UINT64ENCODE(pp, diminfo[u].block)
+ } /* end for */
+ if(version == H5S_HYPER_VERSION_2)
+ len += (4 * space->extent.rank * 8);
+ break;
+ default:
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab")
+ break;
+ } /* end switch */
+ } /* end if */
+ else {
HDassert(version == H5S_HYPER_VERSION_1);
- HDassert(enc_size == H5S_SELECT_INFO_ENC_SIZE_4);
/* Set some convienence values */
fast_dim = ndims - 1;
@@ -2340,11 +3958,8 @@ H5S__hyper_serialize(const H5S_t *space, uint8_t **p)
offset[u] = diminfo[u].start;
} /* end for */
- /* We're not done with the iteration */
- done = FALSE;
-
/* Go iterate over the hyperslabs */
- while(done == FALSE) {
+ while(complete == FALSE) {
/* Iterate over the blocks in the fastest dimension */
while(tmp_count[fast_dim] > 0) {
/* Add 8 bytes times the rank for each hyperslab selected */
@@ -2374,7 +3989,7 @@ H5S__hyper_serialize(const H5S_t *space, uint8_t **p)
/* Bubble up the decrement to the slower changing dimensions */
temp_dim = (int)fast_dim - 1;
- while(temp_dim >= 0 && done == FALSE) {
+ while(temp_dim >= 0 && complete == FALSE) {
/* Decrement the block count */
tmp_count[temp_dim]--;
@@ -2384,7 +3999,7 @@ H5S__hyper_serialize(const H5S_t *space, uint8_t **p)
/* Check for getting out of iterator */
if(temp_dim == 0)
- done = TRUE;
+ complete = TRUE;
/* Reset the block count in this dimension */
tmp_count[temp_dim] = diminfo[temp_dim].count;
@@ -2400,24 +4015,31 @@ H5S__hyper_serialize(const H5S_t *space, uint8_t **p)
for(u = 0; u < ndims; u++)
offset[u] = diminfo[u].start + diminfo[u].stride * (diminfo[u].count - tmp_count[u]);
} /* end while */
- } /* end if */
- }
+ } /* end else */
+ } /* end if */
else { /* irregular */
- HDassert(version == H5S_HYPER_VERSION_1);
- HDassert(enc_size == H5S_SELECT_INFO_ENC_SIZE_4);
-
/* Encode number of hyperslabs */
- H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t);
- UINT32ENCODE(pp, (uint32_t)block_count);
+ switch(enc_size) {
+ case H5S_SELECT_INFO_ENC_SIZE_4:
+ HDassert(version == H5S_HYPER_VERSION_1);
+ H5_CHECK_OVERFLOW(block_count, hsize_t, uint32_t);
+ UINT32ENCODE(pp, (uint32_t)block_count);
+ break;
- len+=4; /* block_count */
+ default:
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab")
+ break;
+ } /* end switch */
- /* Add 8 bytes times the rank for each hyperslab selected */
- H5_CHECK_OVERFLOW((8 * ndims * block_count), hsize_t, size_t);
- len += (uint32_t)(8 * ndims * block_count);
+ if(version == H5S_HYPER_VERSION_1) {
+ len += 4; /* block_count */
- /* Encode each hyperslab in selection */
- H5S__hyper_serialize_helper(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, &pp);
+ /* Add 8 bytes times the rank for each hyperslab selected */
+ H5_CHECK_OVERFLOW((8 * ndims * block_count), hsize_t, size_t);
+ len += (uint32_t)(8 * ndims * block_count);
+ } /* end if */
+
+ H5S__hyper_serialize_helper(space->select.sel_info.hslab->span_lst, start, end, (hsize_t)0, enc_size, &pp);
} /* end else */
/* Encode length */
@@ -2459,14 +4081,15 @@ H5S__hyper_deserialize(H5S_t **space, const uint8_t **p)
H5S_t *tmp_space = NULL; /* Pointer to actual dataspace to use,
either *space or a newly allocated one */
hsize_t dims[H5S_MAX_RANK]; /* Dimenion sizes */
- hsize_t start[H5S_MAX_RANK]; /* Hyperslab start information */
- hsize_t block[H5S_MAX_RANK]; /* Hyperslab block information */
- uint32_t version; /* Version number */ /* Encoded size */
+ hsize_t start[H5S_MAX_RANK]; /* hyperslab start information */
+ hsize_t block[H5S_MAX_RANK]; /* hyperslab block information */
+ uint32_t version; /* Version number */
uint8_t flags = 0; /* Flags */
- unsigned rank; /* Rank of points */
+ uint8_t enc_size = 0; /* Encoded size of selection info */
+ unsigned rank; /* rank of points */
const uint8_t *pp; /* Local pointer for decoding */
unsigned u; /* Local counting variable */
- herr_t ret_value = FAIL; /* Return value */
+ herr_t ret_value=FAIL; /* return value */
FUNC_ENTER_STATIC
@@ -2499,10 +4122,21 @@ H5S__hyper_deserialize(H5S_t **space, const uint8_t **p)
/* Skip over the remainder of the header */
pp += 4;
+ enc_size = H5S_SELECT_INFO_ENC_SIZE_8;
+
+ /* Check for unknown flags */
+ if(flags & ~H5S_SELECT_FLAG_BITS)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTLOAD, FAIL, "unknown flag for selection")
}
- else
+ else {
/* Skip over the remainder of the header */
pp += 8;
+ enc_size = H5S_SELECT_INFO_ENC_SIZE_4;
+ } /* end else */
+
+ /* Check encoded */
+ if(enc_size & ~H5S_SELECT_INFO_ENC_SIZE_BITS)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTLOAD, FAIL, "unknown size of point/offset info for selection")
/* Decode the rank of the point selection */
UINT32DECODE(pp,rank);
@@ -2526,14 +4160,42 @@ H5S__hyper_deserialize(H5S_t **space, const uint8_t **p)
HDassert(H5S_UNLIMITED == HSIZE_UNDEF);
HDassert(version >= H5S_HYPER_VERSION_2);
- /* Iterate over dimensions */
- for(u = 0; u < rank; u++) {
- /* Decode start/stride/block/count */
- UINT64DECODE(pp, start[u]);
- UINT64DECODE(pp, stride[u]);
- UINT64DECODE(pp, count[u]);
- UINT64DECODE(pp, block[u]);
- } /* end for */
+ /* Decode start/stride/block/count */
+ switch(enc_size) {
+ case H5S_SELECT_INFO_ENC_SIZE_4:
+ for(u = 0; u < tmp_space->extent.rank; u++) {
+ UINT32DECODE(pp, start[u]);
+ UINT32DECODE(pp, stride[u]);
+
+ UINT32DECODE(pp, count[u]);
+ if((uint32_t)count[u] == H5S_UINT32_MAX)
+ count[u] = H5S_UNLIMITED;
+
+ UINT32DECODE(pp, block[u]);
+ if((uint32_t)block[u] == H5S_UINT32_MAX)
+ block[u] = H5S_UNLIMITED;
+ } /* end for */
+ break;
+
+ case H5S_SELECT_INFO_ENC_SIZE_8:
+ for(u = 0; u < tmp_space->extent.rank; u++) {
+ UINT64DECODE(pp, start[u]);
+ UINT64DECODE(pp, stride[u]);
+
+ UINT64DECODE(pp, count[u]);
+ if((uint64_t)count[u] == H5S_UINT64_MAX)
+ count[u] = H5S_UNLIMITED;
+
+ UINT64DECODE(pp, block[u]);
+ if((uint64_t)block[u] == H5S_UINT64_MAX)
+ block[u] = H5S_UNLIMITED;
+ } /* end for */
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab")
+ break;
+ } /* end switch */
/* Select the hyperslab to the current selection */
if((ret_value = H5S_select_hyperslab(tmp_space, H5S_SELECT_SET, start, stride, count, block)) < 0)
@@ -2549,21 +4211,46 @@ H5S__hyper_deserialize(H5S_t **space, const uint8_t **p)
size_t num_elem; /* Number of elements in selection */
unsigned v; /* Local counting variable */
- /* Decode the number of points */
- UINT32DECODE(pp, num_elem);
+ /* Decode the number of blocks */
+ switch(enc_size) {
+ case H5S_SELECT_INFO_ENC_SIZE_4:
+ UINT32DECODE(pp, num_elem);
+ break;
+
+ case H5S_SELECT_INFO_ENC_SIZE_8:
+ UINT64DECODE(pp, num_elem);
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab")
+ break;
+ } /* end switch */
/* Set the count & stride for all blocks */
stride = count = H5S_hyper_ones_g;
/* Retrieve the coordinates from the buffer */
for(u = 0; u < num_elem; u++) {
- /* Decode the starting points */
- for(tstart = start, v = 0; v < rank; v++, tstart++)
- UINT32DECODE(pp, *tstart);
+ /* Decode the starting and ending points */
+ switch(enc_size) {
+ case H5S_SELECT_INFO_ENC_SIZE_4:
+ for(tstart = start,v = 0; v < rank; v++, tstart++)
+ UINT32DECODE(pp, *tstart);
+ for(tend = end, v = 0; v < rank; v++, tend++)
+ UINT32DECODE(pp, *tend);
+ break;
- /* Decode the ending points */
- for(tend = end, v = 0; v < rank; v++, tend++)
- UINT32DECODE(pp, *tend);
+ case H5S_SELECT_INFO_ENC_SIZE_8:
+ for(tstart = start, v = 0; v < rank; v++, tstart++)
+ UINT64DECODE(pp, *tstart);
+ for(tend = end, v = 0; v < rank; v++, tend++)
+ UINT64DECODE(pp, *tend);
+ break;
+
+ default:
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unknown offset info size for hyperslab")
+ break;
+ } /* end switch */
/* Change the ending points into blocks */
for(tblock = block, tstart = start, tend = end, v = 0; v < rank; v++, tstart++, tend++, tblock++)
@@ -2631,7 +4318,6 @@ H5S__hyper_span_blocklist(const H5S_hyper_span_info_t *spans, hsize_t start[],
hsize_t **buf)
{
const H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */
- hsize_t u; /* Index variable */
herr_t ret_value = SUCCEED; /* return value */
FUNC_ENTER_STATIC
@@ -2669,19 +4355,19 @@ H5S__hyper_span_blocklist(const H5S_hyper_span_info_t *spans, hsize_t start[],
/* Encode all the previous dimensions starting & ending points */
/* Copy previous starting points */
- for(u = 0; u < rank; u++, (*buf)++)
- H5MM_memcpy(*buf, &start[u], sizeof(hsize_t));
+ H5MM_memcpy(*buf, start, rank * sizeof(hsize_t));
+ (*buf) += rank;
/* Copy starting point for this span */
- H5MM_memcpy(*buf, &curr->low, sizeof(hsize_t));
+ **buf = curr->low;
(*buf)++;
/* Copy previous ending points */
- for(u = 0; u < rank; u++, (*buf)++)
- H5MM_memcpy(*buf, &end[u], sizeof(hsize_t));
+ H5MM_memcpy(*buf, end, rank * sizeof(hsize_t));
+ (*buf) += rank;
- /* Copy starting point for this span */
- H5MM_memcpy(*buf, &curr->high, sizeof(hsize_t));
+ /* Copy ending point for this span */
+ **buf = curr->high;
(*buf)++;
/* Decrement the number of blocks processed */
@@ -2729,7 +4415,8 @@ done:
REVISION LOG
--------------------------------------------------------------------------*/
static herr_t
-H5S__get_select_hyper_blocklist(H5S_t *space, hbool_t internal, hsize_t startblock, hsize_t numblocks, hsize_t *buf)
+H5S__get_select_hyper_blocklist(H5S_t *space, hsize_t startblock,
+ hsize_t numblocks, hsize_t *buf)
{
herr_t ret_value = SUCCEED; /* Return value */
@@ -2739,11 +4426,18 @@ H5S__get_select_hyper_blocklist(H5S_t *space, hbool_t internal, hsize_t startblo
HDassert(buf);
HDassert(space->select.sel_info.hslab->unlim_dim < 0);
+ /* Attempt to rebuild diminfo if it is invalid and has not been confirmed
+ * to be impossible.
+ */
+ if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
+ H5S__hyper_rebuild(space);
+
/* Check for a "regular" hyperslab selection */
if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
const H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */
hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary hyperslab counts */
hsize_t offset[H5S_MAX_RANK]; /* Offset of element in dataspace */
+ hsize_t end[H5S_MAX_RANK]; /* End of elements in dataspace */
unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
unsigned ndims; /* Rank of the dataspace */
hbool_t done; /* Whether we are done with the iteration */
@@ -2754,31 +4448,25 @@ H5S__get_select_hyper_blocklist(H5S_t *space, hbool_t internal, hsize_t startblo
fast_dim = ndims - 1;
/* Check which set of dimension information to use */
- if(internal)
+ if(space->select.sel_info.hslab->unlim_dim >= 0)
/*
- * Use the "optimized dimension information" to pass back information
- * on the blocks set, not the "application information".
+ * There is an unlimited dimension so we must use diminfo.opt as
+ * it has been "clipped" to the current extent.
*/
diminfo = space->select.sel_info.hslab->diminfo.opt;
else
- if(space->select.sel_info.hslab->unlim_dim >= 0)
- /*
- * There is an unlimited dimension so we must use diminfo.opt as
- * it has been "clipped" to the current extent.
- */
- diminfo = space->select.sel_info.hslab->diminfo.opt;
- else
- /*
- * Use the "application dimension information" to pass back to
- * the user the blocks they set, not the optimized, internal
- * information.
- */
- diminfo = space->select.sel_info.hslab->diminfo.app;
+ /*
+ * Use the "application dimension information" to pass back to
+ * the user the blocks they set, not the optimized, internal
+ * information.
+ */
+ diminfo = space->select.sel_info.hslab->diminfo.app;
/* Build the tables of count sizes as well as the initial offset */
for(u = 0; u < ndims; u++) {
tmp_count[u] = diminfo[u].count;
offset[u] = diminfo[u].start;
+ end[u] = diminfo[u].start + (diminfo[u].block - 1);
} /* end for */
/* We're not done with the iteration */
@@ -2786,31 +4474,45 @@ H5S__get_select_hyper_blocklist(H5S_t *space, hbool_t internal, hsize_t startblo
/* Go iterate over the hyperslabs */
while(!done && numblocks > 0) {
- hsize_t temp_off; /* Offset in a given dimension */
+ /* Skip over initial blocks */
+ if(startblock > 0) {
+ /* Skip all blocks in row */
+ if(startblock >= tmp_count[fast_dim]) {
+ startblock -= tmp_count[fast_dim];
+ tmp_count[fast_dim] = 0;
+ } /* end if */
+ else {
+ /* Move the offset to the next sequence to start */
+ offset[fast_dim] += diminfo[fast_dim].stride * startblock;
+ end[fast_dim] += diminfo[fast_dim].stride * startblock;
+
+ /* Decrement the block count */
+ tmp_count[fast_dim] -= startblock;
+
+ /* Done with starting blocks */
+ startblock = 0;
+ } /* end else */
+ } /* end if */
/* Iterate over the blocks in the fastest dimension */
while(tmp_count[fast_dim] > 0 && numblocks > 0) {
+ /* Sanity check */
+ HDassert(startblock == 0);
- /* Check if we should copy this block information */
- if(startblock == 0) {
- /* Copy the starting location */
- H5MM_memcpy(buf, offset, sizeof(hsize_t) * ndims);
- buf += ndims;
+ /* Copy the starting location */
+ H5MM_memcpy(buf, offset, sizeof(hsize_t) * ndims);
+ buf += ndims;
- /* Compute the ending location */
- H5MM_memcpy(buf, offset, sizeof(hsize_t) * ndims);
- for(u = 0; u < ndims; u++)
- buf[u] += (diminfo[u].block - 1);
- buf += ndims;
+ /* Compute the ending location */
+ H5MM_memcpy(buf, end, sizeof(hsize_t) * ndims);
+ buf += ndims;
- /* Decrement the number of blocks to retrieve */
- numblocks--;
- } /* end if */
- else
- startblock--;
+ /* Decrement the number of blocks to retrieve */
+ numblocks--;
/* Move the offset to the next sequence to start */
offset[fast_dim] += diminfo[fast_dim].stride;
+ end[fast_dim] += diminfo[fast_dim].stride;
/* Decrement the block count */
tmp_count[fast_dim]--;
@@ -2833,23 +4535,24 @@ H5S__get_select_hyper_blocklist(H5S_t *space, hbool_t internal, hsize_t startblo
if(tmp_count[temp_dim] > 0)
break;
+ /* Reset the block count in this dimension */
+ tmp_count[temp_dim] = diminfo[temp_dim].count;
+
/* Check for getting out of iterator */
if(temp_dim == 0)
done = TRUE;
- /* 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 */
+ /* Re-compute offset & end arrays */
+ if(!done)
+ for(u = 0; u < ndims; u++) {
+ offset[u] = diminfo[u].start + diminfo[u].stride * (diminfo[u].count - tmp_count[u]);
+ end[u] = offset[u] + (diminfo[u].block - 1);
+ } /* end for */
} /* end while */
} /* end if */
else {
@@ -2915,7 +4618,7 @@ H5Sget_select_hyper_blocklist(hid_t spaceid, hsize_t startblock,
/* Go get the correct number of blocks */
if(numblocks > 0)
- ret_value = H5S__get_select_hyper_blocklist(space, 0, startblock, numblocks, buf);
+ ret_value = H5S__get_select_hyper_blocklist(space, startblock, numblocks, buf);
else
ret_value = SUCCEED; /* Successfully got 0 blocks... */
@@ -2926,76 +4629,6 @@ done:
/*--------------------------------------------------------------------------
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 < H5S_MAX_RANK);
- HDassert(start);
- HDassert(end);
-
- /* Check each point to determine whether selection+offset is within extent */
- curr=spans->head;
- while(curr!=NULL) {
- /* Check for offset moving selection negative */
- if(((hssize_t)curr->low + offset[rank]) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_BADRANGE, FAIL, "offset moves selection out of bounds")
-
- /* Check if the current span extends the bounding box */
- if((curr->low + (hsize_t)offset[rank]) < start[rank])
- start[rank] = curr->low + (hsize_t)offset[rank];
- if((curr->high + (hsize_t)offset[rank]) > end[rank])
- end[rank] = curr->high + (hsize_t)offset[rank];
-
- /* 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.
@@ -3023,8 +4656,7 @@ done:
static herr_t
H5S__hyper_bounds(const H5S_t *space, hsize_t *start, hsize_t *end)
{
- unsigned rank; /* Dataspace rank */
- unsigned i; /* index variable */
+ const hsize_t *low_bounds, *high_bounds; /* Pointers to the correct pair of low & high bounds */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_STATIC
@@ -3034,37 +4666,42 @@ H5S__hyper_bounds(const H5S_t *space, hsize_t *start, hsize_t *end)
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 */
+ /* Check which set of low & high bounds we should be using */
if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
- const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->diminfo.opt; /* local alias for diminfo */
+ low_bounds = space->select.sel_info.hslab->diminfo.low_bounds;
+ high_bounds = space->select.sel_info.hslab->diminfo.high_bounds;
+ } /* end if */
+ else {
+ low_bounds = space->select.sel_info.hslab->span_lst->low_bounds;
+ high_bounds = space->select.sel_info.hslab->span_lst->high_bounds;
+ } /* end else */
+
+ /* Check for offset set */
+ if(space->select.offset_changed) {
+ unsigned u; /* Local index variable */
+
+ /* Loop over dimensions */
+ for(u = 0; u < space->extent.rank; u++) {
+ /* Sanity check */
+ HDassert(low_bounds[u] <= high_bounds[u]);
- /* 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)
+ if(((hssize_t)low_bounds[u] + space->select.offset[u]) < 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;
+ /* Set the low & high bounds in this dimension */
+ start[u] = (hsize_t)((hssize_t)low_bounds[u] + space->select.offset[u]);
+ if((int)u == space->select.sel_info.hslab->unlim_dim)
+ end[u] = H5S_UNLIMITED;
else
- end[i] = diminfo[i].start + diminfo[i].stride * (diminfo[i].count - 1) + (diminfo[i].block - 1) + (hsize_t)space->select.offset[i];
+ end[u] = (hsize_t)((hssize_t)high_bounds[u] + space->select.offset[u]);
} /* 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 */
+ /* Offset vector is still zeros, just copy low & high bounds */
+ H5MM_memcpy(start, low_bounds, sizeof(hsize_t) * space->extent.rank);
+ H5MM_memcpy(end, high_bounds, sizeof(hsize_t) * space->extent.rank);
+ } /* end else */
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -3115,6 +4752,7 @@ H5S__hyper_offset(const H5S_t *space, hsize_t *offset)
dim_size = space->extent.size;
/* Check for a "regular" hyperslab selection */
+ /* (No need to rebuild the dimension info yet -QAK) */
if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->diminfo.opt; /* Local alias for diminfo */
@@ -3279,6 +4917,7 @@ H5S__hyper_is_contiguous(const H5S_t *space)
HDassert(space);
/* Check for a "regular" hyperslab selection */
+ /* (No need to rebuild the dimension info yet -QAK) */
if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
const H5S_hyper_dim_t *diminfo=space->select.sel_info.hslab->diminfo.opt; /* local alias for diminfo */
@@ -3297,7 +4936,7 @@ H5S__hyper_is_contiguous(const H5S_t *space)
/* Initialize flags */
large_contiguous = TRUE; /* assume true and reset if the dimensions don't match */
- small_contiguous = FALSE; /* assume false initially */
+ small_contiguous = FALSE; /* assume false initially */
/* Check for a "large contigous" block */
for(u = 0; u < space->extent.rank; u++) {
@@ -3343,7 +4982,7 @@ H5S__hyper_is_contiguous(const H5S_t *space)
*/
/* Initialize flags */
large_contiguous = TRUE; /* assume true and reset if the dimensions don't match */
- small_contiguous = FALSE; /* assume false initially */
+ small_contiguous = FALSE; /* assume false initially */
/* Get information for slowest changing information */
spans = space->select.sel_info.hslab->span_lst;
@@ -3461,6 +5100,9 @@ H5S__hyper_is_single(const H5S_t *space)
HDassert(space);
/* Check for a "single" hyperslab selection */
+ /* (No need to rebuild the dimension info yet, since the span-tree
+ * algorithm is fast -QAK)
+ */
if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
unsigned u; /* index variable */
@@ -3519,7 +5161,6 @@ done:
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
--------------------------------------------------------------------------*/
@@ -3533,6 +5174,12 @@ H5S__hyper_is_regular(const H5S_t *space)
/* Check args */
HDassert(space);
+ /* Attempt to rebuild diminfo if it is invalid and has not been confirmed
+ * to be impossible.
+ */
+ if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
+ H5S__hyper_rebuild((H5S_t *)space); /* Casting away const OK -NAF */
+
/* Only simple check for regular hyperslabs for now... */
if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES)
ret_value = TRUE;
@@ -3545,88 +5192,395 @@ H5S__hyper_is_regular(const H5S_t *space)
/*--------------------------------------------------------------------------
NAME
- H5S__hyper_release
+ H5S__hyper_spans_shape_same_helper
PURPOSE
- Release hyperslab selection information for a dataspace
+ Helper routine to check if two hyperslab span trees are the same shape
USAGE
- herr_t H5S__hyper_release(space)
- H5S_t *space; IN: Pointer to dataspace
+ hbool_t H5S__hyper_spans_shape_same_helper(span1, span2, offset, rest_zeros)
+ H5S_hyper_span_info_t *span_info1; IN: First span tree to compare
+ H5S_hyper_span_info_t *span_info2; IN: Second span tree to compare
+ hssize_t offset[]; IN: Offset between the span trees
+ hbool_t rest_zeros[]; IN: Array of flags which indicate
+ the rest of the offset[] array
+ is zero values.
RETURNS
- Non-negative on success/Negative on failure
+ TRUE (1) or FALSE (0) on success, can't fail
DESCRIPTION
- Releases all hyperslab selection information for a dataspace
+ Compare two hyperslab span trees to determine if they refer to a selection
+ with the same shape, with a possible (constant) offset between their
+ elements. Very similar to H5S__hyper_cmp_spans, except the selected
+ elements can be offset by a vector.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-static herr_t
-H5S__hyper_release(H5S_t *space)
+static H5_ATTR_PURE hbool_t
+H5S__hyper_spans_shape_same_helper(const H5S_hyper_span_info_t *span_info1,
+ const H5S_hyper_span_info_t *span_info2, hssize_t offset[],
+ hbool_t rest_zeros[])
{
- herr_t ret_value = SUCCEED;
+ hbool_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Sanity checks */
+ HDassert(span_info1);
+ HDassert(span_info2);
+ HDassert(offset);
+ HDassert(rest_zeros);
+
+ /* Compare low & high bounds for this span list */
+ /* (Could compare lower dimensions also, but not certain if
+ * that's worth it. - QAK, 2019/01/23)
+ */
+ if((hsize_t)((hssize_t)span_info1->low_bounds[0] + offset[0]) != span_info2->low_bounds[0])
+ HGOTO_DONE(FALSE)
+ else if((hsize_t)((hssize_t)span_info1->high_bounds[0] + offset[0]) != span_info2->high_bounds[0])
+ HGOTO_DONE(FALSE)
+ else {
+ const H5S_hyper_span_t *span1;
+ const H5S_hyper_span_t *span2;
+
+ /* Get the pointers to the actual lists of spans */
+ span1 = span_info1->head;
+ span2 = span_info2->head;
+
+ /* Sanity checking */
+ HDassert(span1);
+ HDassert(span2);
+
+ /* infinite loop which must be broken out of */
+ while(1) {
+ /* Check for both spans being NULL */
+ if(span1 == NULL && span2 == NULL)
+ HGOTO_DONE(TRUE)
+
+ /* Check for one span being NULL */
+ if(span1 == NULL || span2 == NULL)
+ HGOTO_DONE(FALSE)
+
+ /* Check if the actual low & high span information is the same */
+ if((hsize_t)((hssize_t)span1->low + offset[0]) != span2->low || (hsize_t)((hssize_t)span1->high + offset[0]) != span2->high)
+ HGOTO_DONE(FALSE)
+
+ /* Check for down tree for this span */
+ if(span1->down != NULL || span2->down != NULL) {
+ /* If the rest of the span trees have a zero offset, use the faster comparison routine */
+ if(rest_zeros[0]) {
+ if(!H5S__hyper_cmp_spans(span1->down, span2->down))
+ HGOTO_DONE(FALSE)
+ else {
+ /* Keep going... */
+ } /* end else */
+ } /* end if */
+ else {
+ if(!H5S__hyper_spans_shape_same_helper(span1->down, span2->down, &offset[1], &rest_zeros[1]))
+ HGOTO_DONE(FALSE)
+ else {
+ /* Keep going... */
+ } /* end else */
+ } /* end else */
+ } /* end if */
+ else {
+ /* Keep going... */
+ } /* end else */
+
+ /* Advance to the next nodes in the span list */
+ span1 = span1->next;
+ span2 = span2->next;
+ } /* end while */
+ } /* end else */
+
+ /* Fall through, with default return value of 'TRUE' if spans were already visited */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__hyper_spans_shape_same_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_spans_shape_same
+ PURPOSE
+ Check if two hyperslab span trees are the same shape
+ USAGE
+ hbool_t H5S__hyper_spans_shape_same(span1, span2)
+ H5S_hyper_span_info_t *span_info1; IN: First span tree to compare
+ H5S_hyper_span_info_t *span_info2; IN: Second span tree to compare
+ RETURNS
+ TRUE (1) or FALSE (0) on success, can't fail
+ DESCRIPTION
+ Compare two hyperslab span trees to determine if they refer to a selection
+ with the same shape. Very similar to H5S__hyper_cmp_spans, except the
+ selected elements can be offset by a vector.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5_ATTR_PURE hbool_t
+H5S__hyper_spans_shape_same(const H5S_hyper_span_info_t *span_info1,
+ const H5S_hyper_span_info_t *span_info2, unsigned ndims)
+{
+ const H5S_hyper_span_t *span1; /* Pointer to spans in first span tree */
+ const H5S_hyper_span_t *span2; /* Pointer to spans in second span tree */
+ hssize_t offset[H5S_MAX_RANK]; /* Offset vector for selections */
+ hbool_t rest_zeros[H5S_MAX_RANK]; /* Vector of flags to indicate when remaining offset is all zero */
+ hbool_t zero_offset; /* Whether the two selections have a non-zero offset */
+ unsigned u; /* Local index variable */
+ hbool_t ret_value = TRUE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(span_info1);
+ HDassert(span_info2);
+ HDassert(ndims > 0);
+
+ /* Initialize arrays */
+ HDmemset(offset, 0, sizeof(offset));
+ HDmemset(rest_zeros, 0, sizeof(rest_zeros));
+
+ /* Check for an offset between the two selections */
+ span1 = span_info1->head;
+ span2 = span_info2->head;
+ zero_offset = TRUE;
+ for(u = 0; u < ndims; u++) {
+ /* Check for offset in this dimension */
+ if(span1->low != span2->low) {
+ offset[u] = (hssize_t)span2->low - (hssize_t)span1->low;
+
+ /* Indicate that the offset vector is not all zeros */
+ if(zero_offset)
+ zero_offset = FALSE;
+ } /* end if */
+
+ /* Sanity check */
+ /* (Both span trees must have the same depth) */
+ HDassert((span1->down && span2->down) || (NULL == span1->down && NULL == span2->down));
+
+ /* Advance to next dimension */
+ if(span1->down) {
+ span1 = span1->down->head;
+ span2 = span2->down->head;
+ } /* end if */
+ } /* end for */
+
+ /* Check if there's a "tail" of all zeros in a non-zero offset vector */
+ if(!zero_offset) {
+ int i; /* Local index variable */
+
+ /* Find first non-zero offset, from the fastest dimension up */
+ for(i = (int)(ndims - 1); i >= 0; i--)
+ if(offset[i]) {
+ rest_zeros[i] = TRUE;
+ break;
+ } /* end if */
+
+ /* Sanity check */
+ /* (Must eventually have found a non-zero offset) */
+ HDassert(i >= 0);
+ } /* end if */
+
+ /* If the offset vector is all zero, we can use the faster span tree
+ * comparison routine. Otherwise, use a generalized version of that
+ * routine.
+ */
+ if(zero_offset)
+ ret_value = H5S__hyper_cmp_spans(span_info1, span_info2);
+ else
+ ret_value = H5S__hyper_spans_shape_same_helper(span_info1, span_info2, offset, rest_zeros);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__hyper_spans_shape_same() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_shape_same
+ PURPOSE
+ Check if a two hyperslab selections are the same shape
+ USAGE
+ htri_t H5S__hyper_shape_same(space1, space2)
+ const H5S_t *space1; IN: First dataspace to check
+ const H5S_t *space2; IN: Second dataspace to check
+ RETURNS
+ TRUE / FALSE / FAIL
+ DESCRIPTION
+ Checks to see if the current selection in each dataspace are the same
+ shape.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ Handles when both are regular in an efficient way, otherwise converts
+ both to span tree form (if necessary) and compares efficiently them in
+ that form.
+
+ Rank of space1 must always be >= to rank of space2.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S__hyper_shape_same(const H5S_t *space1, const H5S_t *space2)
+{
+ unsigned space1_rank; /* Number of dimensions of first dataspace */
+ unsigned space2_rank; /* Number of dimensions of second dataspace */
+ htri_t ret_value = TRUE; /* Return value */
FUNC_ENTER_STATIC
/* Check args */
- HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
+ HDassert(space1);
+ HDassert(space2);
- /* Reset the number of points selected */
- space->select.num_elem = 0;
+ /* Get dataspace ranks */
+ space1_rank = space1->extent.rank;
+ space2_rank = space2->extent.rank;
- /* 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")
+ /* Sanity check */
+ HDassert(space1_rank >= space2_rank);
+ HDassert(space2_rank > 0);
+
+ /* Rebuild diminfo if it is invalid and has not been confirmed to be
+ * impossible */
+ if(space1->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
+ H5S__hyper_rebuild((H5S_t *)space1); /* Casting away const OK -QAK */
+ if(space2->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
+ H5S__hyper_rebuild((H5S_t *)space2); /* Casting away const OK -QAK */
+
+ /* If both are regular hyperslabs, compare their diminfo values */
+ if(space1->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES
+ && space2->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
+ int space1_dim; /* Current dimension in first dataspace */
+ int space2_dim; /* Current dimension in second dataspace */
+
+ /* Initialize dimensions */
+ space1_dim = (int)space1_rank - 1;
+ space2_dim = (int)space2_rank - 1;
+
+ /* Check that the shapes are the same in the common dimensions, and that
+ * block == 1 in all dimensions that appear only in space1.
+ */
+ while(space2_dim >= 0) {
+ if(space1->select.sel_info.hslab->diminfo.opt[space1_dim].stride !=
+ space2->select.sel_info.hslab->diminfo.opt[space2_dim].stride)
+ HGOTO_DONE(FALSE)
- /* Release space for the hyperslab selection information */
- space->select.sel_info.hslab = H5FL_FREE(H5S_hyper_sel_t, space->select.sel_info.hslab);
+ if(space1->select.sel_info.hslab->diminfo.opt[space1_dim].count !=
+ space2->select.sel_info.hslab->diminfo.opt[space2_dim].count)
+ HGOTO_DONE(FALSE)
+
+ if(space1->select.sel_info.hslab->diminfo.opt[space1_dim].block !=
+ space2->select.sel_info.hslab->diminfo.opt[space2_dim].block)
+ HGOTO_DONE(FALSE)
+
+ space1_dim--;
+ space2_dim--;
+ } /* end while */
+
+ while(space1_dim >= 0) {
+ if(space1->select.sel_info.hslab->diminfo.opt[space1_dim].block != 1)
+ HGOTO_DONE(FALSE)
+
+ space1_dim--;
+ } /* end while */
} /* end if */
+ /* If both aren't regular, use fast irregular comparison */
+ else {
+ H5S_hyper_span_info_t *spans1; /* Hyperslab spans for first dataspace */
+
+ /* Make certain that both selections have span trees */
+ if(NULL == space1->select.sel_info.hslab->span_lst)
+ if(H5S__hyper_generate_spans((H5S_t *)space1) < 0) /* Casting away const OK -QAK */
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "can't construct span tree for hyperslab selection")
+ if(NULL == space2->select.sel_info.hslab->span_lst)
+ if(H5S__hyper_generate_spans((H5S_t *)space2) < 0) /* Casting away const OK -QAK */
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "can't construct span tree for hyperslab selection")
+
+ /* If rank of space A is different (guaranteed greater) than
+ * rank of space B, walk down the span tree, verifying
+ * that the block size is 1 on the way down.
+ */
+ if(space1_rank > space2_rank) {
+ unsigned diff_rank = space1_rank - space2_rank; /* Difference in ranks */
+
+ /* Walk down the dimensions */
+ spans1 = space1->select.sel_info.hslab->span_lst;
+ while(diff_rank > 0) {
+ H5S_hyper_span_t *span; /* Span for this dimension */
+
+ /* Get pointer to first span in tree */
+ span = spans1->head;
+
+ /* Check for more spans in this dimension */
+ if(span->next)
+ HGOTO_DONE(FALSE)
+
+ /* Check for span size > 1 element */
+ if(span->low != span->high)
+ HGOTO_DONE(FALSE)
+
+ /* Walk down to the next dimension */
+ spans1 = span->down;
+ diff_rank--;
+ } /* end while */
+
+ /* Sanity check */
+ HDassert(spans1);
+ } /* end if */
+ else
+ spans1 = space1->select.sel_info.hslab->span_lst;
+
+ /* Compare the span trees */
+ ret_value = H5S__hyper_spans_shape_same(spans1, space2->select.sel_info.hslab->span_lst, space2_rank);
+ } /* end else */
+
+ /* Fall through with 'TRUE' value, if not set earlier */
done:
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5S__hyper_release() */
+} /* end H5S__hyper_shape_same() */
/*--------------------------------------------------------------------------
NAME
- H5S__hyper_recover_span
+ H5S__hyper_release
PURPOSE
- Recover a generated span, if appropriate
+ Release hyperslab selection information for a dataspace
USAGE
- herr_t H5S__hyper_recover_span(recover, curr_span, next_span)
- unsigned *recover; IN/OUT: Pointer recover flag
- H5S_hyper_span_t **curr_span; IN/OUT: Pointer to current span in list
- H5S_hyper_span_t *next_span; IN: Pointer to next span
+ herr_t H5S__hyper_release(space)
+ H5S_t *space; IN: Pointer to dataspace
RETURNS
- Non-negative on success, negative on failure
+ 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.
+ Releases all hyperslab selection information for a dataspace
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
static herr_t
-H5S__hyper_recover_span(hbool_t *recover, H5S_hyper_span_t **curr_span, H5S_hyper_span_t *next_span)
+H5S__hyper_release(H5S_t *space)
{
FUNC_ENTER_STATIC_NOERR
- HDassert(recover);
- HDassert(curr_span);
+ /* Check args */
+ HDassert(space && H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(space));
- /* Check if the span should be recovered */
- if(*recover) {
- H5S__hyper_free_span(*curr_span);
- *recover = FALSE;
- } /* end if */
+ /* 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)
+ H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst);
- /* Set the current span to next span */
- *curr_span = next_span;
+ /* 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 */
FUNC_LEAVE_NOAPI(SUCCEED)
-} /* end H5S__hyper_recover_span() */
+} /* end H5S__hyper_release() */
/*--------------------------------------------------------------------------
@@ -3639,7 +5593,7 @@ H5S__hyper_recover_span(hbool_t *recover, H5S_hyper_span_t **curr_span, H5S_hype
unsigned rank; IN: Number of dimensions of coordinate
hsize_t *coords; IN: Location of element
RETURNS
- Non-negative on success, negative on failure
+ Non-NULL pointer to new span tree on success, NULL on failure
DESCRIPTION
Create a span tree for a single element
GLOBAL VARIABLES
@@ -3661,14 +5615,20 @@ H5S__hyper_coord_to_span(unsigned rank, const hsize_t *coords)
/* Search for location to insert new element in tree */
if(rank > 1) {
- /* Allocate a span info node */
- if(NULL == (down = H5FL_CALLOC(H5S_hyper_span_info_t)))
+ /* Allocate a span info node for coordinates below this one */
+ if(NULL == (down = H5S__hyper_new_span_info(rank - 1)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span")
+ /* Set the low & high bounds for this span info node */
+ H5MM_memcpy(down->low_bounds, &coords[1], (rank - 1) * sizeof(hsize_t));
+ H5MM_memcpy(down->high_bounds, &coords[1], (rank - 1) * sizeof(hsize_t));
/* Build span tree for coordinates below this one */
if(NULL == (down->head = H5S__hyper_coord_to_span(rank - 1, &coords[1])))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span")
+
+ /* Update the tail pointer of the down dimension, and it's a single span element */
+ down->tail = down->head;
} /* end if */
/* Build span for this coordinate */
@@ -3690,12 +5650,13 @@ done:
NAME
H5S__hyper_add_span_element_helper
PURPOSE
- Add a single element to a span tree
+ Helper routine to add a single element to a span tree
USAGE
- herr_t H5S_hyper_add_span_element_helper(prev_span, span_tree, rank, coords)
+ herr_t H5S__hyper_add_span_element_helper(span_tree, rank, coords, first_dim_modified)
H5S_hyper_span_info_t *span_tree; IN/OUT: Pointer to span tree to append to
unsigned rank; IN: Number of dimensions of coordinates
- hsize_t *coords; IN: Location of element to add to span tree
+ hsize_t *coords; IN: Location of element to add to span tree
+ int *first_dim_modified; IN: Index of the first dimension modified
RETURNS
Non-negative on success, negative on failure
DESCRIPTION
@@ -3708,13 +5669,9 @@ done:
--------------------------------------------------------------------------*/
static herr_t
H5S__hyper_add_span_element_helper(H5S_hyper_span_info_t *span_tree,
- unsigned rank, const hsize_t *coords)
+ unsigned rank, const hsize_t *coords, int *first_dim_modified)
{
- 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 */
+ H5S_hyper_span_t *tail_span; /* Pointer to the tail span of one dimension */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_STATIC
@@ -3723,166 +5680,196 @@ H5S__hyper_add_span_element_helper(H5S_hyper_span_info_t *span_tree,
HDassert(span_tree);
HDassert(rank > 0);
HDassert(coords);
+ HDassert(first_dim_modified);
/* 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;
+ tail_span = span_tree->tail;
+
+ /* Determine if tail span includes a portion of the coordinate */
+ /* (Should never happen with the lowest level in the span tree) */
+ if(coords[0] >= tail_span->low && coords[0] <= tail_span->high) {
+ H5S_hyper_span_t *prev_down_tail_span; /* Pointer to previous down spans' tail pointer */
+ hsize_t prev_down_tail_span_high; /* Value of previous down spans' tail's high value */
+
+ /* Retain into about down spans' tail */
+ prev_down_tail_span = tail_span->down->tail;
+ prev_down_tail_span_high = tail_span->down->tail->high;
+
+ /* Drop down a dimension */
+ HDassert(rank > 1);
+ if(H5S__hyper_add_span_element_helper(tail_span->down, rank - 1, &coords[1], first_dim_modified) < 0)
+ HGOTO_ERROR(H5E_DATASET, H5E_CANTINSERT, FAIL, "can't insert coordinate into span tree")
+
+ /* Check & update high bounds for lower dimensions */
+ if(*first_dim_modified >= 0) {
+ unsigned first_dim; /* First dimension modified, relative to this span tree */
+ hbool_t first_dim_set = FALSE; /* Whether first dimension modified is set */
+ unsigned u; /* Local index variable */
- /* 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 */
+ /* Adjust first dimension modified to be relative to this span tree */
+ first_dim = (unsigned)(*first_dim_modified + 1);
- /* 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);
+ /* Reset modified dimension, in case no bounds in this span tree change */
+ *first_dim_modified = -1;
- /* Increase size of previous span */
- tmp2_span->high++;
- tmp2_span->nelem++;
+ /* Iterate through coordinates */
+ for(u = first_dim; u < rank; u++) {
+ /* Check if coordinate is outside the bounds for this span tree */
+ if(coords[u] > span_tree->high_bounds[u]) {
+ /* Update high bounds for this tree */
+ span_tree->high_bounds[u] = coords[u];
- /* Reset the 'tmp_span' for the rest of this block's algorithm */
- tmp_span=tmp2_span;
+ /* Need to signal to higher dimensions if high bounds changed */
+ if(!first_dim_set) {
+ *first_dim_modified = (int)u;
+ first_dim_set = TRUE;
+ } /* end if */
} /* end if */
- /* Span is disjoint, but has the same "down tree" selection */
- else {
- /* Release "down tree" information */
- H5S__hyper_free_span_info(tmp_span->down);
+ } /* end for */
+ } /* end if */
- /* Point at earlier span's "down tree" */
- tmp_span->down=tmp2_span->down;
+ /* Check if previous tail span in down spans is different than current
+ * tail span, or if its high value changed, in which case we should
+ * check if the updated node can share down spans with other nodes.
+ */
+ if(tail_span->down->tail != prev_down_tail_span ||
+ prev_down_tail_span_high != tail_span->down->tail->high) {
+ H5S_hyper_span_t *stop_span; /* Pointer to span to stop at */
+ H5S_hyper_span_t *tmp_span; /* Temporary pointer to a span */
+ uint64_t op_gen; /* Operation generation value */
+
+ /* Determine which span to stop at */
+ if(tail_span->down->tail != prev_down_tail_span) {
+ /* Sanity check */
+ HDassert(prev_down_tail_span->next == tail_span->down->tail);
+
+ /* Set the span to stop at */
+ stop_span = prev_down_tail_span;
+ } /* end if */
+ else {
+ /* Sanity check */
+ HDassert(prev_down_tail_span_high != tail_span->down->tail->high);
- /* Increment reference count on shared "down tree" */
- tmp_span->down->count++;
- } /* end else */
+ /* Set the span to stop at */
+ stop_span = tail_span->down->tail;
+ } /* end else */
- /* Found span to merge into, break out now */
- break;
- } /* end if */
+ /* Acquire an operation generation value for this operation */
+ op_gen = H5S__hyper_get_op_gen();
- /* Advance to next span to check */
- tmp2_span=tmp2_span->next;
- } /* end while */
+ /* Check if the 'stop' span in the "down tree" is equal to any other
+ * spans in the list of spans in the span tree.
+ *
+ * If so, release last span information and make last span merge into
+ * previous span (if possible), or at least share their "down tree"
+ * information.
+ */
+ tmp_span = tail_span->down->head;
+ while(tmp_span != stop_span) {
+ hbool_t attempt_merge_spans = FALSE; /* Whether to merge spans */
- /* Make span tree for current coordinates */
- if(NULL == (new_span = H5S__hyper_coord_to_span(rank, coords)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+ /* Different tests for when to run the 'merge' algorithm,
+ * depending whether there's "down trees" or not.
+ */
+ if(NULL == tmp_span->down) {
+ /* Spin through spans until we find the one before the 'stop' span */
+ if(tmp_span->next == stop_span)
+ attempt_merge_spans = TRUE;
+ } /* end if */
+ else {
+ /* Check if we've compared the 'stop' span's "down tree" to
+ * this span's "down tree" already.
+ */
+ if(tmp_span->down->op_info[0].op_gen != op_gen) {
+ if(H5S__hyper_cmp_spans(tmp_span->down, stop_span->down))
+ attempt_merge_spans = TRUE;
+
+ /* Remember that we visited this span's "down tree" already */
+ /* (Because it wasn't the same as the 'stop' span's down tree
+ * and we don't need to compare it again)
+ */
+ tmp_span->down->op_info[0].op_gen = op_gen;
+ } /* end if */
+ } /* end else */
- /* Add new span tree as span */
- HDassert(tmp_span);
- tmp_span->next=new_span;
+ /* Check for merging into previous span */
+ if(attempt_merge_spans) {
+ if(tmp_span->high + 1 == stop_span->low) {
+ /* Increase size of previous span */
+ tmp_span->high++;
- /* Make scratch pointer point to last span in list */
- HDassert(tspan_info);
- tspan_info->scratch=(H5S_hyper_span_info_t *)new_span;
+ /* Update pointers appropriately */
+ if(stop_span == prev_down_tail_span) {
+ /* Sanity check */
+ HDassert(stop_span->next == tail_span->down->tail);
- /* 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;
+ tmp_span->next = stop_span->next;
} /* 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);
+ /* Sanity check */
+ HDassert(tmp_span->next == tail_span->down->tail);
- /* Point at earlier span's "down tree" */
- tmp_span->down=tmp2_span->down;
-
- /* Increment reference count on shared "down tree" */
- tmp_span->down->count++;
+ tmp_span->next = NULL;
+ tail_span->down->tail = tmp_span;
} /* end else */
- /* Found span to merge into, break out now */
- break;
+ /* Release last span created */
+ H5S__hyper_free_span(stop_span);
} /* end if */
+ /* Span is disjoint, but has the same "down tree" selection */
+ /* (If it has a "down tree") */
+ else if(stop_span->down) {
+ /* Release "down tree" information */
+ H5S__hyper_free_span_info(stop_span->down);
- /* Advance to next span to check */
- tmp2_span=tmp2_span->next;
- } /* end while */
- } /* end if */
+ /* Point at earlier span's "down tree" */
+ stop_span->down = tmp_span->down;
+
+ /* Increment reference count on shared "down tree" */
+ stop_span->down->count++;
+ } /* end else */
+
+ /* Found span to merge into, break out now */
+ break;
+ } /* end if */
+
+ /* Advance to next span to check */
+ tmp_span = tmp_span->next;
+ } /* end while */
} /* end if */
- else {
- if(NULL == (new_span = H5S__hyper_new_span(coords[0], coords[0], NULL, NULL)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+ } /* end if */
+ else {
+ unsigned u; /* Local index variable */
- /* Add new span tree as span */
- HDassert(tmp_span);
- tmp_span->next=new_span;
+ /* Check if we made it all the way to the bottom span list in the tree
+ * and the new coordinate adjoins the current tail span.
+ */
+ if(rank == 1 && (tail_span->high + 1) == coords[0])
+ /* Append element to current tail span */
+ tail_span->high++;
+ else {
+ H5S_hyper_span_t *new_span; /* New span created for element */
- /* Make scratch pointer point to last span in list */
- tspan_info->scratch=(H5S_hyper_span_info_t *)new_span;
+ /* Make span tree for current coordinate(s) */
+ if(NULL == (new_span = H5S__hyper_coord_to_span(rank, coords)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab spans for coordinate")
- /* Set the proper 'pstride' for new span */
- new_span->pstride = new_span->low - tmp_span->low;
+ /* Add new span to span tree list */
+ tail_span->next = new_span;
+ span_tree->tail = new_span;
} /* end else */
+
+ /* Update high bound for current span tree */
+ HDassert(coords[0] > span_tree->high_bounds[0]);
+ span_tree->high_bounds[0] = coords[0];
+
+ /* Update high bounds for dimensions below this one */
+ for(u = 1; u < rank; u++)
+ if(coords[u] > span_tree->high_bounds[u])
+ span_tree->high_bounds[u] = coords[u];
+
+ /* Need to signal to higher dimensions that high bounds changed */
+ *first_dim_modified = 0;
} /* end else */
done:
@@ -3907,6 +5894,24 @@ done:
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
Assumes that the element is not already in the dataspace's selection
+
+ NOTE: There's also an assumption about the context of this function call -
+ This function is only called is only being called from H5D_chunk_mem_cb
+ in src/H5Dchunk.c, when the library is iterating over a memory
+ selection, so the coordinates passed to H5S_hyper_add_span_element will
+ always be in increasing order (according to a row-major (i.e. C, not
+ FORTRAN) scan) over the dataset. Therefore, for every input of
+ coordinates, only the last span element (i.e., the tail pointer) in
+ one dimension is checked against the input.
+
+ NOTE: This algorithm is definitely "correct" and tries to conserve memory
+ as much as possible, but it's doing a _lot_ of work that might be
+ better spent running a similar algorithm to "condense" the span tree
+ (possibly even back into a regular selection) just before the selection
+ is used for I/O on the chunk. I'm not going to spend the time on this
+ currently, but it does sound like a good direction to explore.
+ QAK, 2019/01/24
+
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
@@ -3926,9 +5931,13 @@ H5S_hyper_add_span_element(H5S_t *space, unsigned rank, const hsize_t *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_CALLOC(H5S_hyper_span_info_t)))
+ if(NULL == (head = H5S__hyper_new_span_info(rank)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span info")
+ /* Set the low & high bounds for this span info node */
+ H5MM_memcpy(head->low_bounds, coords, rank * sizeof(hsize_t));
+ H5MM_memcpy(head->high_bounds, coords, rank * sizeof(hsize_t));
+
/* Set the reference count */
head->count = 1;
@@ -3936,6 +5945,9 @@ H5S_hyper_add_span_element(H5S_t *space, unsigned rank, const hsize_t *coords)
if(NULL == (head->head = H5S__hyper_coord_to_span(rank, coords)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab spans for coordinate")
+ /* Update the tail pointer of this newly created span in dimension "rank" */
+ head->tail = head->head;
+
/* Allocate selection info */
if(NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab selection")
@@ -3956,7 +5968,10 @@ H5S_hyper_add_span_element(H5S_t *space, unsigned rank, const hsize_t *coords)
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)
+ int first_dim_modified = -1; /* Index of first dimension modified */
+
+ /* Add the element to the current set of spans */
+ if(H5S__hyper_add_span_element_helper(space->select.sel_info.hslab->span_lst, rank, coords, &first_dim_modified) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert coordinate into span tree")
/* Increment # of elements in selection */
@@ -3974,120 +5989,19 @@ done:
/*--------------------------------------------------------------------------
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)
-{
- herr_t ret_value = SUCCEED; /* Return value */
-
- FUNC_ENTER_NOAPI(FAIL)
-
- 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);
-
-done:
- FUNC_LEAVE_NOAPI(ret_value)
-} /* end 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(FAIL)
-
- HDassert(space);
-
- /* Check the type of selection */
- switch(H5S_GET_SELECT_TYPE(space)) {
- case H5S_SEL_ALL: /* All elements selected in dataspace */
- /* Convert current "all" selection to "real" hyperslab selection */
- {
- const hsize_t *tmp_start; /* Temporary start information */
- const hsize_t *tmp_stride; /* Temporary stride information */
- const hsize_t *tmp_count; /* Temporary count information */
- const hsize_t *tmp_block; /* Temporary block information */
-
- /* Set up temporary information for the dimensions */
- tmp_start = H5S_hyper_zeros_g;
- tmp_stride = tmp_count = H5S_hyper_ones_g;
- tmp_block = space->extent.size;
-
- /* Convert to hyperslab selection */
- if(H5S_select_hyperslab(space,H5S_SELECT_SET,tmp_start,tmp_stride,tmp_count,tmp_block)<0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't convert selection")
- } /* end case */
- break;
-
- 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)
-} /* end H5S_hyper_convert() */
-
-
-/*--------------------------------------------------------------------------
- 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)
+ hbool_t H5S__hyper_intersect_block_helper(spans, rank, start, end, op_info_i, op_gen)
H5S_hyper_span_info_t *spans; IN: First span tree to operate with
- hssize_t *offset; IN: Selection offset coordinate
+ unsigned rank; IN: Number of dimensions for span tree
hsize_t *start; IN: Starting coordinate for block
hsize_t *end; IN: Ending coordinate for block
+ unsigned op_info_i; IN: Index of op info to use
+ uint64_t op_gen; IN: Operation generation
RETURN
- Non-negative on success, negative on failure
+ Non-negative (TRUE/FALSE) on success, can't fail
DESCRIPTION
Quickly detect intersections between span tree and block
GLOBAL VARIABLES
@@ -4096,10 +6010,10 @@ done:
REVISION LOG
--------------------------------------------------------------------------*/
static hbool_t
-H5S__hyper_intersect_block_helper(const H5S_hyper_span_info_t *spans,
- const hsize_t *start, const hsize_t *end)
+H5S__hyper_intersect_block_helper(H5S_hyper_span_info_t *spans,
+ unsigned rank, const hsize_t *start, const hsize_t *end, unsigned op_info_i,
+ uint64_t op_gen)
{
- H5S_hyper_span_t *curr; /* Pointer to current span in 1st span tree */
hbool_t ret_value = FALSE; /* Return value */
FUNC_ENTER_STATIC_NOERR
@@ -4109,37 +6023,52 @@ H5S__hyper_intersect_block_helper(const H5S_hyper_span_info_t *spans,
HDassert(start);
HDassert(end);
- /* Get the span list for spans in this tree */
- curr = spans->head;
-
- /* Iterate over the spans in the tree */
- while(curr != NULL) {
- /* Check for span entirely before block */
- if(curr->high < *start)
- /* Advance to next span in this dimension */
- curr = curr->next;
- /* If this span is past the end of the block, then we're done in this dimension */
- else if(curr->low > *end)
- HGOTO_DONE(FALSE)
- /* block & span overlap */
- else {
- if(curr->down == NULL)
- HGOTO_DONE(TRUE)
- else {
- hbool_t status; /* Status from recursive call */
+ /* Check if we've already visited this span tree */
+ if(spans->op_info[op_info_i].op_gen != op_gen) {
+ H5S_hyper_span_t *curr; /* Pointer to current span in 1st span tree */
+ unsigned u; /* Local index variable */
- /* Recursively check spans in next dimension down */
- status = H5S__hyper_intersect_block_helper(curr->down, start + 1, end + 1);
+ /* Verify that there is a possibility of an overlap by checking the block
+ * against the low & high bounds for the span tree.
+ */
+ for(u = 0; u < rank; u++)
+ if(start[u] > spans->high_bounds[u] || end[u] < spans->low_bounds[u])
+ HGOTO_DONE(FALSE)
- /* If there is a span intersection in the down dimensions, the span trees overlap */
- if(status == TRUE)
- HGOTO_DONE(TRUE);
+ /* Get the span list for spans in this tree */
+ curr = spans->head;
- /* No intersection in down dimensions, advance to next span */
+ /* Iterate over the spans in the tree */
+ while(curr != NULL) {
+ /* Check for span entirely before block */
+ if(curr->high < *start)
+ /* Advance to next span in this dimension */
curr = curr->next;
+ /* If this span is past the end of the block, then we're done in this dimension */
+ else if(curr->low > *end)
+ HGOTO_DONE(FALSE)
+ /* block & span overlap */
+ else {
+ /* If this is the bottom dimension, then the span tree overlaps the block */
+ if(curr->down == NULL)
+ HGOTO_DONE(TRUE)
+ /* Recursively check spans in next dimension down */
+ else {
+ /* If there is an intersection in the "down" dimensions,
+ * the span trees overlap.
+ */
+ if(H5S__hyper_intersect_block_helper(curr->down, rank - 1, start + 1, end + 1, op_info_i, op_gen))
+ HGOTO_DONE(TRUE)
+
+ /* No intersection in down dimensions, advance to next span */
+ curr = curr->next;
+ } /* end else */
} /* end else */
- } /* end else */
- } /* end while */
+ } /* end while */
+
+ /* Set the tree's operation generation */
+ spans->op_info[op_info_i].op_gen = op_gen;
+ } /* end if */
/* Fall through with 'FALSE' return value */
@@ -4150,51 +6079,134 @@ done:
/*--------------------------------------------------------------------------
NAME
- H5S_hyper_intersect_block
+ H5S__hyper_intersect_block
PURPOSE
- Detect intersections in span trees
+ Detect intersections of selection with block
USAGE
- htri_t H5S_hyper_intersect_block(space, start, end)
- H5S_t *space; IN: First dataspace to operate on span tree
- hssize_t *start; IN: Starting coordinate for block
- hssize_t *end; IN: Ending coordinate for block
+ htri_t H5S__hyper_intersect_block(space, start, end)
+ const H5S_t *space; IN: Dataspace with selection to use
+ const hsize_t *start; IN: Starting coordinate for block
+ const hsize_t *end; IN: Ending coordinate for block
RETURNS
- Non-negative on success, negative on failure
+ Non-negative TRUE / FALSE on success, negative on failure
DESCRIPTION
- Quickly detect intersections between span tree and block
+ Quickly detect intersections between both regular hyperslabs and span trees
+ with a block
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
+ Does not use selection offset.
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-htri_t
-H5S_hyper_intersect_block(H5S_t *space, const hsize_t *start, const hsize_t *end)
+static htri_t
+H5S__hyper_intersect_block(const H5S_t *space, const hsize_t *start, const hsize_t *end)
{
htri_t ret_value = FAIL; /* Return value */
- FUNC_ENTER_NOAPI(FAIL)
+ FUNC_ENTER_STATIC_NOERR
/* Sanity check */
HDassert(space);
+ HDassert(H5S_SEL_HYPERSLABS == H5S_GET_SELECT_TYPE(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);
+ /* Attempt to rebuild diminfo if it is invalid and has not been confirmed
+ * to be impossible.
+ */
+ if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_NO)
+ H5S__hyper_rebuild((H5S_t *)space); /* Casting away const OK -QAK */
- /* Check that the space selection has a span tree */
- if(NULL == space->select.sel_info.hslab->span_lst)
- if(H5S__hyper_generate_spans(space) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
+ /* Check for regular hyperslab intersection */
+ if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
+ hbool_t single_block; /* Whether the regular selection is a single block */
+ unsigned u; /* Local index variable */
- /* Perform the span-by-span intersection check */
- ret_value = H5S__hyper_intersect_block_helper(space->select.sel_info.hslab->span_lst, start, end);
+ /* Check for a single block */
+ /* For a regular hyperslab to be single, it must have only one block
+ * (i.e. count == 1 in all dimensions).
+ */
+ single_block = TRUE;
+ for(u = 0; u < space->extent.rank; u++)
+ if(space->select.sel_info.hslab->diminfo.opt[u].count > 1)
+ single_block = FALSE;
+
+ /* Single blocks have already been "compared" above, in the low / high
+ * bound checking, so just return TRUE if we've reached here - they
+ * would have been rejected earlier, if they didn't intersect.
+ */
+ if(single_block)
+ HGOTO_DONE(TRUE)
+ else {
+ /* Loop over the dimensions, checking for an intersection */
+ for(u = 0; u < space->extent.rank; u++) {
+ /* If the block's start is <= the hyperslab start, they intersect */
+ /* (So, if the start is > the hyperslab start, check more conditions) */
+ if(start[u] > space->select.sel_info.hslab->diminfo.opt[u].start) {
+ hsize_t adj_start; /* Start coord, adjusted for hyperslab selection parameters */
+ hsize_t nstride; /* Number of strides into the selection */
+
+ /* Adjust start coord for selection's 'start' offset */
+ adj_start = start[u] - space->select.sel_info.hslab->diminfo.opt[u].start;
+
+ /* Compute # of strides into the selection */
+ if(space->select.sel_info.hslab->diminfo.opt[u].count > 1)
+ nstride = adj_start / space->select.sel_info.hslab->diminfo.opt[u].stride;
+ else
+ nstride = 0;
+
+ /* Sanity check */
+ HDassert(nstride <= space->select.sel_info.hslab->diminfo.opt[u].count);
+
+ /* "Rebase" the adjusted start coord into the same range
+ * range of values as the selections's first block.
+ */
+ adj_start -= nstride * space->select.sel_info.hslab->diminfo.opt[u].stride;
+
+ /* If the adjusted start doesn't fall within the first hyperslab
+ * span, check for the block overlapping with the next one.
+ */
+ if(adj_start >= space->select.sel_info.hslab->diminfo.opt[u].block) {
+ hsize_t adj_end; /* End coord, adjusted for hyperslab selection parameters */
+
+ /* Adjust end coord for selection's 'start' offset */
+ adj_end = end[u] - space->select.sel_info.hslab->diminfo.opt[u].start;
+
+ /* "Rebase" the adjusted end coord into the same range
+ * range of values as the selections's first block.
+ */
+ adj_end -= nstride * space->select.sel_info.hslab->diminfo.opt[u].stride;
+
+ /* If block doesn't extend over beginning of next span,
+ * it doesn't intersect.
+ */
+ if(adj_end < space->select.sel_info.hslab->diminfo.opt[u].stride)
+ HGOTO_DONE(FALSE)
+ } /* end if */
+ } /* end if */
+ } /* end for */
+
+ /* If we've looped through all dimensions and none of them didn't
+ * overlap, then all of them do, so we report TRUE.
+ */
+ HGOTO_DONE(TRUE)
+ } /* end else */
+ } /* end if */
+ else {
+ uint64_t op_gen; /* Operation generation value */
+
+ /* Acquire an operation generation value for this operation */
+ op_gen = H5S__hyper_get_op_gen();
+
+ /* Perform the span-by-span intersection check */
+ /* Always use op_info[0] since we own this op_info, so there can be no
+ * simultaneous operations */
+ ret_value = H5S__hyper_intersect_block_helper(space->select.sel_info.hslab->span_lst, space->extent.rank, start, end, 0, op_gen);
+ } /* end else */
done:
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5S_hyper_intersect_block() */
+} /* end H5S__hyper_intersect_block() */
/*--------------------------------------------------------------------------
@@ -4203,9 +6215,12 @@ done:
PURPOSE
Helper routine to adjust offsets in span trees
USAGE
- void H5S__hyper_adjust_u_helper(spans, offset)
+ void H5S__hyper_adjust_u_helper(spans, rank, offset, op_info_i, op_gen)
H5S_hyper_span_info_t *spans; IN: Span tree to operate with
+ unsigned rank; IN: Number of dimensions for span tree
const hsize_t *offset; IN: Offset to subtract
+ unsigned op_info_i; IN: Index of op info to use
+ uint64_t op_gen; IN: Operation generation
RETURNS
None
DESCRIPTION
@@ -4216,23 +6231,26 @@ done:
REVISION LOG
--------------------------------------------------------------------------*/
static void
-H5S__hyper_adjust_u_helper(H5S_hyper_span_info_t *spans,
- const hsize_t *offset)
+H5S__hyper_adjust_u_helper(H5S_hyper_span_info_t *spans, unsigned rank,
+ const hsize_t *offset, unsigned op_info_i, uint64_t op_gen)
{
FUNC_ENTER_STATIC_NOERR
/* Sanity checks */
HDassert(spans);
- HDassert(spans->scratch == (H5S_hyper_span_info_t *)~((size_t)NULL) ||
- spans->scratch == NULL);
HDassert(offset);
- /* Check if we've already set this down span tree */
- if(spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)) {
+ /* Check if we've already set this span tree */
+ if(spans->op_info[op_info_i].op_gen != op_gen) {
H5S_hyper_span_t *span; /* Pointer to current span in span tree */
+ unsigned u; /* Local index variable */
- /* Set the tree's scratch pointer */
- spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL);
+ /* Adjust the span tree's low & high bounds */
+ for(u = 0; u < rank; u++) {
+ HDassert(spans->low_bounds[u] >= offset[u]);
+ spans->low_bounds[u] -= offset[u];
+ spans->high_bounds[u] -= offset[u];
+ } /* end for */
/* Iterate over the spans in tree */
span = spans->head;
@@ -4244,11 +6262,14 @@ H5S__hyper_adjust_u_helper(H5S_hyper_span_info_t *spans,
/* Recursively adjust spans in next dimension down */
if(span->down != NULL)
- H5S__hyper_adjust_u_helper(span->down, offset + 1);
+ H5S__hyper_adjust_u_helper(span->down, rank - 1, offset + 1, op_info_i, op_gen);
/* Advance to next span in this dimension */
span = span->next;
} /* end while */
+
+ /* Set the tree's operation generation */
+ spans->op_info[op_info_i].op_gen = op_gen;
} /* end if */
FUNC_LEAVE_NOAPI_VOID
@@ -4295,19 +6316,30 @@ H5S__hyper_adjust_u(H5S_t *space, const hsize_t *offset)
/* Only perform operation if the offset is non-zero */
if(non_zero_offset) {
/* Subtract the offset from the "regular" coordinates, if they exist */
+ /* (No need to rebuild the dimension info yet -QAK) */
if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
for(u = 0; u < space->extent.rank; u++) {
HDassert(space->select.sel_info.hslab->diminfo.opt[u].start >= offset[u]);
space->select.sel_info.hslab->diminfo.opt[u].start -= offset[u];
+
+ /* Adjust the low & high bounds */
+ HDassert(space->select.sel_info.hslab->diminfo.low_bounds[u] >= offset[u]);
+ space->select.sel_info.hslab->diminfo.low_bounds[u] -= offset[u];
+ space->select.sel_info.hslab->diminfo.high_bounds[u] -= offset[u];
} /* end for */
} /* end if */
/* Subtract the offset from the span tree coordinates, if they exist */
if(space->select.sel_info.hslab->span_lst) {
- H5S__hyper_adjust_u_helper(space->select.sel_info.hslab->span_lst, offset);
+ uint64_t op_gen; /* Operation generation value */
- /* Reset the scratch pointers for the next routine which needs them */
- H5S__hyper_span_scratch(space->select.sel_info.hslab->span_lst);
+ /* Acquire an operation generation value for this operation */
+ op_gen = H5S__hyper_get_op_gen();
+
+ /* Perform adjustment */
+ /* Always use op_info[0] since we own this op_info, so there can be no
+ * simultaneous operations */
+ H5S__hyper_adjust_u_helper(space->select.sel_info.hslab->span_lst, space->extent.rank, offset, 0, op_gen);
} /* end if */
} /* end if */
@@ -4316,14 +6348,14 @@ H5S__hyper_adjust_u(H5S_t *space, const hsize_t *offset)
/*-------------------------------------------------------------------------
- * Function: H5S__hyper_project_scalar
+ * Function: H5S__hyper_project_scalar
*
- * Purpose: Projects a single element hyperslab selection into a scalar
+ * Purpose: Projects a single element hyperslab selection into a scalar
* dataspace
*
- * Return: non-negative on success, negative on failure.
+ * Return: Non-negative on success, negative on failure.
*
- * Programmer: Quincey Koziol
+ * Programmer: Quincey Koziol
* Sunday, July 18, 2010
*
*-------------------------------------------------------------------------
@@ -4340,12 +6372,20 @@ H5S__hyper_project_scalar(const H5S_t *space, hsize_t *offset)
HDassert(offset);
/* Check for a "regular" hyperslab selection */
+ /* (No need to rebuild the dimension info yet -QAK) */
if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
const H5S_hyper_dim_t *diminfo = space->select.sel_info.hslab->diminfo.opt; /* Alias for dataspace's diminfo information */
unsigned u; /* Counter */
/* Build the table of the initial offset */
for(u = 0; u < space->extent.rank; u++) {
+ /* Sanity check diminfo */
+ HDassert(1 == diminfo[u].count);
+ HDassert(1 == diminfo[u].block);
+
+ /* Sanity check bounds, while we're here */
+ HDassert(diminfo[u].start == space->select.sel_info.hslab->diminfo.low_bounds[u]);
+
/* Keep the offset for later */
block[u] = diminfo[u].start;
} /* end for */
@@ -4357,17 +6397,22 @@ H5S__hyper_project_scalar(const H5S_t *space, hsize_t *offset)
/* Advance down selected spans */
curr = space->select.sel_info.hslab->span_lst->head;
curr_dim = 0;
- while(curr) {
- /* Sanity check for more than one span */
+ while(1) {
+ /* Sanity checks */
HDassert(NULL == curr->next);
HDassert(curr->low == curr->high);
+ HDassert(curr_dim < 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++;
+ if(curr->down) {
+ curr = curr->down->head;
+ curr_dim++;
+ } /* end if */
+ else
+ break;
} /* end while */
} /* end else */
@@ -4379,14 +6424,14 @@ H5S__hyper_project_scalar(const H5S_t *space, hsize_t *offset)
/*-------------------------------------------------------------------------
- * Function: H5S__hyper_project_simple_lower
+ * Function: H5S__hyper_project_simple_lower
*
- * Purpose: Projects a hyperslab selection onto/into a simple dataspace
+ * Purpose: Projects a hyperslab selection onto/into a simple dataspace
* of a lower rank
*
- * Return: non-negative on success, negative on failure.
+ * Return: Non-negative on success, negative on failure.
*
- * Programmer: Quincey Koziol
+ * Programmer: Quincey Koziol
* Sunday, July 18, 2010
*
*-------------------------------------------------------------------------
@@ -4426,14 +6471,14 @@ H5S__hyper_project_simple_lower(const H5S_t *base_space, H5S_t *new_space)
/*-------------------------------------------------------------------------
- * Function: H5S__hyper_project_simple_higher
+ * Function: H5S__hyper_project_simple_higher
*
- * Purpose: Projects a hyperslab selection onto/into a simple dataspace
+ * Purpose: Projects a hyperslab selection onto/into a simple dataspace
* of a higher rank
*
- * Return: non-negative on success, negative on failure.
+ * Return: Non-negative on success, negative on failure.
*
- * Programmer: Quincey Koziol
+ * Programmer: Quincey Koziol
* Sunday, July 18, 2010
*
*-------------------------------------------------------------------------
@@ -4442,7 +6487,9 @@ static herr_t
H5S__hyper_project_simple_higher(const H5S_t *base_space, H5S_t *new_space)
{
H5S_hyper_span_t *prev_span = NULL; /* Pointer to previous list of spans */
+ unsigned delta_rank; /* Difference in dataspace ranks */
unsigned curr_dim; /* Current dimension being operated on */
+ unsigned u; /* Local index variable */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_STATIC
@@ -4455,15 +6502,15 @@ H5S__hyper_project_simple_higher(const H5S_t *base_space, H5S_t *new_space)
/* 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)) {
+ delta_rank = (new_space->extent.rank - base_space->extent.rank);
+ while(curr_dim < delta_rank) {
H5S_hyper_span_info_t *new_span_info; /* Pointer to list of spans */
H5S_hyper_span_t *new_span; /* Temporary hyperslab span */
/* Allocate a new span_info node */
- if(NULL == (new_span_info = H5FL_CALLOC(H5S_hyper_span_info_t))) {
+ if(NULL == (new_span_info = H5S__hyper_new_span_info(new_space->extent.rank))) {
if(prev_span)
- if(H5S__hyper_free_span(prev_span) < 0)
- HERROR(H5E_DATASPACE, H5E_CANTFREE, "can't free hyperslab span");
+ H5S__hyper_free_span(prev_span);
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span info")
} /* end if */
@@ -4475,13 +6522,24 @@ H5S__hyper_project_simple_higher(const H5S_t *base_space, H5S_t *new_space)
if(NULL == (new_span = H5S__hyper_new_span((hsize_t)0, (hsize_t)0, NULL, NULL))) {
HDassert(new_span_info);
if(!prev_span)
- (void)H5FL_FREE(H5S_hyper_span_info_t, new_span_info);
+ (void)H5FL_ARR_FREE(hbounds_t, new_span_info);
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span")
} /* end if */
/* Set the span_info information */
new_span_info->count = 1;
new_span_info->head = new_span;
+ new_span_info->tail = new_span;
+
+ /* Set the bounding box */
+ for(u = 0; u < delta_rank; u++) {
+ new_span_info->low_bounds[u] = 0;
+ new_span_info->high_bounds[u] = 0;
+ } /* end for */
+ for(; u < new_space->extent.rank; u++) {
+ new_span_info->low_bounds[u] = base_space->select.sel_info.hslab->span_lst->low_bounds[u - delta_rank];
+ new_span_info->high_bounds[u] = base_space->select.sel_info.hslab->span_lst->high_bounds[u - delta_rank];
+ } /* end for */
/* Attach to new space, if top span info */
if(NULL == new_space->select.sel_info.hslab->span_lst)
@@ -4503,10 +6561,9 @@ H5S__hyper_project_simple_higher(const H5S_t *base_space, H5S_t *new_space)
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")
+ H5S__hyper_free_span(new_space->select.sel_info.hslab->span_lst->head);
- new_space->select.sel_info.hslab->span_lst = H5FL_FREE(H5S_hyper_span_info_t, new_space->select.sel_info.hslab->span_lst);
+ new_space->select.sel_info.hslab->span_lst = (H5S_hyper_span_info_t *)H5FL_ARR_FREE(hbounds_t, new_space->select.sel_info.hslab->span_lst);
} /* end if */
FUNC_LEAVE_NOAPI(ret_value)
@@ -4514,20 +6571,21 @@ done:
/*-------------------------------------------------------------------------
- * Function: H5S__hyper_project_simple
+ * Function: H5S__hyper_project_simple
*
- * Purpose: Projects a hyperslab selection onto/into a simple dataspace
+ * Purpose: Projects a hyperslab selection onto/into a simple dataspace
* of a different rank
*
- * Return: non-negative on success, negative on failure.
+ * Return: Non-negative on success, negative on failure.
*
- * Programmer: Quincey Koziol
+ * Programmer: Quincey Koziol
* Sunday, July 18, 2010
*
*-------------------------------------------------------------------------
*/
static herr_t
-H5S__hyper_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *offset)
+H5S__hyper_project_simple(const H5S_t *base_space, H5S_t *new_space,
+ hsize_t *offset)
{
herr_t ret_value = SUCCEED; /* Return value */
@@ -4550,15 +6608,16 @@ H5S__hyper_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *of
new_space->select.sel_info.hslab->unlim_dim = -1;
/* Check for a "regular" hyperslab selection */
+ /* (No need to rebuild the dimension info yet -QAK) */
if(base_space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
unsigned base_space_dim; /* Current dimension in the base dataspace */
unsigned new_space_dim; /* Current dimension in the new dataspace */
+ unsigned u; /* Local index variable */
/* Check if the new space's rank is < or > base space's rank */
if(new_space->extent.rank < base_space->extent.rank) {
const H5S_hyper_dim_t *opt_diminfo = base_space->select.sel_info.hslab->diminfo.opt; /* Alias for dataspace's diminfo information */
hsize_t block[H5S_MAX_RANK]; /* Block selected in base dataspace */
- unsigned u; /* Local index variable */
/* Compute the offset for the down-projection */
HDmemset(block, 0, sizeof(block));
@@ -4618,6 +6677,12 @@ H5S__hyper_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *of
new_space_dim++;
} /* end for */
+ /* Update the bounding box */
+ for(u = 0; u < new_space->extent.rank; u++) {
+ new_space->select.sel_info.hslab->diminfo.low_bounds[u] = new_space->select.sel_info.hslab->diminfo.opt[u].start;
+ new_space->select.sel_info.hslab->diminfo.high_bounds[u] = new_space->select.sel_info.hslab->diminfo.low_bounds[u] + new_space->select.sel_info.hslab->diminfo.opt[u].stride * (new_space->select.sel_info.hslab->diminfo.opt[u].count - 1) + (new_space->select.sel_info.hslab->diminfo.opt[u].block - 1);
+ } /* end for */
+
/* Indicate that the dimension information is valid */
new_space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
@@ -4664,8 +6729,8 @@ H5S__hyper_project_simple(const H5S_t *base_space, H5S_t *new_space, hsize_t *of
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 = H5S_DIMINFO_VALID_NO;
+ /* Copy the status of the dimension information */
+ new_space->select.sel_info.hslab->diminfo_valid = base_space->select.sel_info.hslab->diminfo_valid;
} /* end else */
/* Number of elements selected will be the same */
@@ -4685,9 +6750,12 @@ done:
PURPOSE
Helper routine to adjust offsets in span trees
USAGE
- void H5S__hyper_adjust_s_helper(spans, offset)
+ void H5S__hyper_adjust_s_helper(spans, rank, offset, op_info_i, op_gen)
H5S_hyper_span_info_t *spans; IN: Span tree to operate with
+ unsigned rank; IN: Number of dimensions for span tree
const hssize_t *offset; IN: Offset to subtract
+ unsigned op_info_i; IN: Index of op info to use
+ uint64_t op_gen; IN: Operation generation
RETURNS
None
DESCRIPTION
@@ -4698,23 +6766,26 @@ done:
REVISION LOG
--------------------------------------------------------------------------*/
static void
-H5S__hyper_adjust_s_helper(H5S_hyper_span_info_t *spans,
- const hssize_t *offset)
+H5S__hyper_adjust_s_helper(H5S_hyper_span_info_t *spans, unsigned rank,
+ const hssize_t *offset, unsigned op_info_i, uint64_t op_gen)
{
FUNC_ENTER_STATIC_NOERR
/* Sanity checks */
HDassert(spans);
- HDassert(spans->scratch == (H5S_hyper_span_info_t *)~((size_t)NULL) ||
- spans->scratch == NULL);
HDassert(offset);
- /* Check if we've already set this down span tree */
- if(spans->scratch != (H5S_hyper_span_info_t *)~((size_t)NULL)) {
+ /* Check if we've already set this span tree */
+ if(spans->op_info[op_info_i].op_gen != op_gen) {
H5S_hyper_span_t *span; /* Pointer to current span in span tree */
+ unsigned u; /* Local index variable */
- /* Set the tree's scratch pointer */
- spans->scratch = (H5S_hyper_span_info_t *)~((size_t)NULL);
+ /* Adjust the span tree's low & high bounds */
+ for(u = 0; u < rank; u++) {
+ HDassert((hssize_t)spans->low_bounds[u] >= offset[u]);
+ spans->low_bounds[u] = (hsize_t)((hssize_t)spans->low_bounds[u] - offset[u]);
+ spans->high_bounds[u] = (hsize_t)((hssize_t)spans->high_bounds[u] - offset[u]);
+ } /* end for */
/* Iterate over the spans in tree */
span = spans->head;
@@ -4726,11 +6797,14 @@ H5S__hyper_adjust_s_helper(H5S_hyper_span_info_t *spans,
/* Recursively adjust spans in next dimension down */
if(span->down != NULL)
- H5S__hyper_adjust_s_helper(span->down, offset + 1);
+ H5S__hyper_adjust_s_helper(span->down, rank - 1, offset + 1, op_info_i, op_gen);
/* Advance to next span in this dimension */
span = span->next;
} /* end while */
+
+ /* Set the tree's operation generation */
+ spans->op_info[op_info_i].op_gen = op_gen;
} /* end if */
FUNC_LEAVE_NOAPI_VOID
@@ -4739,11 +6813,11 @@ H5S__hyper_adjust_s_helper(H5S_hyper_span_info_t *spans,
/*--------------------------------------------------------------------------
NAME
- H5S_hyper_adjust_s
+ H5S__hyper_adjust_s
PURPOSE
Adjust a hyperslab selection by subtracting an offset
USAGE
- herr_t H5S_hyper_adjust_s(space,offset)
+ 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
@@ -4755,8 +6829,8 @@ H5S__hyper_adjust_s_helper(H5S_hyper_span_info_t *spans,
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-herr_t
-H5S_hyper_adjust_s(H5S_t *space, const hssize_t *offset)
+static herr_t
+H5S__hyper_adjust_s(H5S_t *space, const hssize_t *offset)
{
hbool_t non_zero_offset = FALSE; /* Whether any offset is non-zero */
unsigned u; /* Local index variable */
@@ -4778,25 +6852,36 @@ H5S_hyper_adjust_s(H5S_t *space, const hssize_t *offset)
/* Only perform operation if the offset is non-zero */
if(non_zero_offset) {
/* Subtract the offset from the "regular" coordinates, if they exist */
+ /* (No need to rebuild the dimension info yet -QAK) */
if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
for(u = 0; u < space->extent.rank; u++) {
HDassert((hssize_t)space->select.sel_info.hslab->diminfo.opt[u].start >= offset[u]);
space->select.sel_info.hslab->diminfo.opt[u].start = (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.opt[u].start - offset[u]);
+
+ /* Adjust the low & high bounds */
+ HDassert((hssize_t)space->select.sel_info.hslab->diminfo.low_bounds[u] >= offset[u]);
+ space->select.sel_info.hslab->diminfo.low_bounds[u] = (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.low_bounds[u] - offset[u]);
+ space->select.sel_info.hslab->diminfo.high_bounds[u] = (hsize_t)((hssize_t)space->select.sel_info.hslab->diminfo.high_bounds[u] - offset[u]);
} /* end for */
} /* end if */
/* Subtract the offset from the span tree coordinates, if they exist */
if(space->select.sel_info.hslab->span_lst) {
- H5S__hyper_adjust_s_helper(space->select.sel_info.hslab->span_lst, offset);
+ uint64_t op_gen; /* Operation generation value */
+
+ /* Acquire an operation generation value for this operation */
+ op_gen = H5S__hyper_get_op_gen();
- /* Reset the scratch pointers for the next routine which needs them */
- H5S__hyper_span_scratch(space->select.sel_info.hslab->span_lst);
+ /* Perform the adjustment */
+ /* Always use op_info[0] since we own this op_info, so there can be no
+ * simultaneous operations */
+ H5S__hyper_adjust_s_helper(space->select.sel_info.hslab->span_lst, space->extent.rank, offset, 0, op_gen);
} /* end if */
}
done:
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5S_hyper_adjust_s() */
+} /* end H5S__hyper_adjust_s() */
/*--------------------------------------------------------------------------
@@ -4806,11 +6891,11 @@ done:
"Normalize" a hyperslab selection by adjusting it's coordinates by the
amount of the selection offset.
USAGE
- hbool_t H5S_hyper_normalize_offset(space, old_offset)
+ htri_t H5S_hyper_normalize_offset(space, old_offset)
H5S_t *space; IN/OUT: Pointer to dataspace to move
hssize_t *old_offset; OUT: Pointer to space to store old offset
RETURNS
- TRUE if space has been normalized, FALSE if not
+ TRUE/FALSE for hyperslab selection, FAIL on error
DESCRIPTION
Copies the current selection offset into the array provided, then
inverts the selection offset, subtracts the offset from the hyperslab
@@ -4823,7 +6908,7 @@ done:
htri_t
H5S_hyper_normalize_offset(H5S_t *space, hssize_t *old_offset)
{
- htri_t ret_value = FALSE; /* Return value */
+ htri_t ret_value = FALSE; /* Return value */
FUNC_ENTER_NOAPI(FAIL)
@@ -4842,7 +6927,7 @@ H5S_hyper_normalize_offset(H5S_t *space, hssize_t *old_offset)
} /* end for */
/* Call the 'adjust' routine */
- if(H5S_hyper_adjust_s(space, space->select.offset) < 0)
+ if(H5S__hyper_adjust_s(space, space->select.offset) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection")
/* Zero out the selection offset */
@@ -4890,7 +6975,7 @@ H5S_hyper_denormalize_offset(H5S_t *space, const hssize_t *old_offset)
HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS);
/* Call the 'adjust' routine */
- if(H5S_hyper_adjust_s(space, old_offset) < 0)
+ if(H5S__hyper_adjust_s(space, old_offset) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't adjust selection")
/* Copy the selection offset over */
@@ -4907,12 +6992,11 @@ done:
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
+ herr_t H5S__hyper_append_span(span_tree, ndims, low, high, down)
H5S_hyper_span_info_t **span_tree; IN/OUT: Pointer to span tree to append to
- hsize_t low, high; IN: Low and high bounds for new span node
+ unsigned ndims; IN: Number of dimension for span
+ hsize_t low, high; IN: Low and high bounds for new span node
H5S_hyper_span_info_t *down; IN: Down span tree for new node
- H5S_hyper_span_t *next; IN: Next span for new node
RETURNS
Non-negative on success, negative on failure
DESCRIPTION
@@ -4924,8 +7008,8 @@ done:
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_append_span(H5S_hyper_span_info_t **span_tree, unsigned ndims,
+ hsize_t low, hsize_t high, H5S_hyper_span_info_t *down)
{
H5S_hyper_span_t *new_span = NULL;
herr_t ret_value = SUCCEED; /* Return value */
@@ -4933,73 +7017,108 @@ H5S__hyper_append_span(H5S_hyper_span_t **prev_span,
FUNC_ENTER_STATIC
/* Sanity checks */
- HDassert(prev_span);
HDassert(span_tree);
/* Check for adding first node to merged spans */
- if(*prev_span == NULL) {
+ if(*span_tree == NULL) {
/* Allocate new span node to append to list */
- if(NULL == (new_span = H5S__hyper_new_span(low, high, down, next)))
+ if(NULL == (new_span = H5S__hyper_new_span(low, high, down, NULL)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, 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);
+ /* Make new span the first node in span list */
/* Allocate a new span_info node */
- if(NULL == (*span_tree = H5FL_CALLOC(H5S_hyper_span_info_t)))
+ if(NULL == (*span_tree = H5S__hyper_new_span_info(ndims)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span")
/* Set the span tree's basic information */
(*span_tree)->count = 1;
(*span_tree)->head = new_span;
+ (*span_tree)->tail = new_span;
+
+ /* Set low & high bounds for new span tree */
+ (*span_tree)->low_bounds[0] = low;
+ (*span_tree)->high_bounds[0] = high;
+ if(down) {
+ /* Sanity check */
+ HDassert(ndims > 1);
- /* Update previous merged span */
- *prev_span = new_span;
+ H5MM_memcpy(&((*span_tree)->low_bounds[1]), down->low_bounds, sizeof(hsize_t) * (ndims - 1));
+ H5MM_memcpy(&((*span_tree)->high_bounds[1]), down->high_bounds, sizeof(hsize_t) * (ndims - 1));
+ } /* end if */
} /* end if */
/* Merge or append to existing merged spans list */
else {
+ htri_t down_cmp = (-1); /* Comparison value for down spans */
+
/* 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) {
+ if((((*span_tree)->tail->high + 1) == low) &&
+ (down_cmp = H5S__hyper_cmp_spans(down, (*span_tree)->tail->down))) {
/* Extend previous merged span to include new high bound */
- (*prev_span)->high = high;
- (*prev_span)->nelem += (high - low) + 1;
+ (*span_tree)->tail->high = high;
+
+ /* Extend span tree's high bound in this dimension */
+ /* (No need to update lower dimensions, since this span shares them with previous span) */
+ (*span_tree)->high_bounds[0] = high;
} /* end if */
else {
- /* Allocate new span node to append to list */
- if(NULL == (new_span = H5S__hyper_new_span(low, high, down, next)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+ H5S_hyper_span_info_t *new_down; /* Down pointer for new span node */
+
+ /* Sanity check */
+ /* (If down_cmp was set to TRUE above, we won't be in this branch) */
+ HDassert(down_cmp != TRUE);
/* Check if there is actually a down span */
- if(new_span->down) {
+ if(down) {
/* Check if the down spans for the new span node are the same as the previous span node */
- if(H5S__hyper_cmp_spans(new_span->down, (*prev_span)->down)) {
- /* Release the down span for the new node */
- H5S__hyper_free_span_info(new_span->down);
-
- /* Point the new node's down span at the previous node's down span */
- new_span->down = (*prev_span)->down;
+ /* (Uses the 'down span comparison' from earlier, if already computed) */
+ if(down_cmp < 0 && (down_cmp = H5S__hyper_cmp_spans(down, (*span_tree)->tail->down)))
+ /* Share the previous span's down span tree */
+ new_down = (*span_tree)->tail->down;
+ else
+ new_down = down;
+ } /* end if */
+ else
+ new_down = NULL;
- /* Increment the reference count to the shared down span */
- new_span->down->count++;
+ /* Allocate new span node to append to list */
+ if(NULL == (new_span = H5S__hyper_new_span(low, high, new_down, NULL)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span")
+
+ /* Update the high bounds for current dimension */
+ (*span_tree)->high_bounds[0] = high;
+
+ /* Update low & high bounds in lower dimensions, if there are any */
+ if(down) {
+ /* Sanity checks */
+ HDassert(ndims > 1);
+ HDassert(down_cmp >= 0);
+
+ /* Check if we are sharing down spans with a previous node */
+ /* (Only need to check for bounds changing if down spans aren't shared) */
+ if(down_cmp == FALSE) {
+ unsigned u; /* Local index variable */
+
+ /* Loop over lower dimensions, checking & updating low & high bounds */
+ for(u = 0; u < (ndims - 1); u++) {
+ if(down->low_bounds[u] < (*span_tree)->low_bounds[u + 1])
+ (*span_tree)->low_bounds[u + 1] = down->low_bounds[u];
+ if(down->high_bounds[u] > (*span_tree)->high_bounds[u + 1])
+ (*span_tree)->high_bounds[u + 1] = down->high_bounds[u];
+ } /* end for */
} /* end if */
} /* end if */
- /* 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;
+ (*span_tree)->tail->next = new_span;
+ (*span_tree)->tail = new_span;
} /* end else */
} /* end else */
done:
if(ret_value < 0)
- if(new_span && H5S__hyper_free_span(new_span) < 0)
- HDONE_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "failed to release new hyperslab span")
+ if(new_span)
+ H5S__hyper_free_span(new_span);
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5S__hyper_append_span() */
@@ -5011,9 +7130,18 @@ done:
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)
+ herr_t H5S__hyper_clip_spans(span_a, span_b, selector, curr_dim, dim_size,
+ span_a_b_bounds[4], all_clips_bound,
+ a_not_b, a_and_b, b_not_a)
H5S_hyper_span_t *a_spans; IN: Span tree 'a' to clip with.
H5S_hyper_span_t *b_spans; IN: Span tree 'b' to clip with.
+ unsigned selector; IN: The parameter deciding which output is needed
+ (only considering the last three bits ABC:
+ If A is set, then a_not_b is needed;
+ If B is set, then a_and_b is needed;
+ If C is set, then b_not_a is needed;
+ )
+ unsigned ndims; IN: Number of dimensions of this span tree
H5S_hyper_span_t **a_not_b; OUT: Span tree of 'a' hyperslab spans which
doesn't overlap with 'b' hyperslab
spans.
@@ -5027,9 +7155,10 @@ done:
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.
+ 'b' span tree ("a not b"), the area defined by the overlap of the 'a'
+ hyperslab span tree and the 'b' span tree ("a and b"), and the area defined
+ by the 'b' hyperslab span tree which does not overlap the 'a' span
+ tree ("b not a").
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
@@ -5037,20 +7166,14 @@ done:
--------------------------------------------------------------------------*/
static herr_t
H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans,
+ unsigned selector, unsigned ndims,
H5S_hyper_span_info_t **a_not_b, H5S_hyper_span_info_t **a_and_b,
H5S_hyper_span_info_t **b_not_a)
{
- H5S_hyper_span_t *span_a; /* Pointer to a node in span tree 'a' */
- H5S_hyper_span_t *span_b; /* Pointer to a node in span tree 'b' */
- H5S_hyper_span_t *tmp_span; /* Temporary pointer to new span */
- H5S_hyper_span_t *last_a_not_b; /* Pointer to previous node in span tree 'a_not_b' */
- H5S_hyper_span_t *last_a_and_b; /* Pointer to previous node in span tree 'a_and_b' */
- H5S_hyper_span_t *last_b_not_a; /* Pointer to previous node in span tree 'b_not_a' */
- H5S_hyper_span_info_t *down_a_not_b; /* Temporary pointer to a_not_b span tree of down spans for overlapping nodes */
- H5S_hyper_span_info_t *down_a_and_b; /* Temporary pointer to a_and_b span tree of down spans for overlapping nodes */
- H5S_hyper_span_info_t *down_b_not_a; /* Temporary pointer to b_and_a span tree of down spans for overlapping nodes */
- hbool_t recover_a, recover_b; /* Flags to indicate when to recover temporary spans */
- herr_t ret_value = SUCCEED; /* Return value */
+ hbool_t need_a_not_b; /* Whether to generate a_not_b list */
+ hbool_t need_a_and_b; /* Whether to generate a_and_b list */
+ hbool_t need_b_not_a; /* Whether to generate b_not_a list */
+ herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_STATIC
@@ -5061,6 +7184,11 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
HDassert(a_and_b);
HDassert(b_not_a);
+ /* Set which list(s) to be generated, based on selector */
+ need_a_not_b = ((selector & H5S_HYPER_COMPUTE_A_NOT_B) != 0);
+ need_a_and_b = ((selector & H5S_HYPER_COMPUTE_A_AND_B) != 0);
+ need_b_not_a = ((selector & H5S_HYPER_COMPUTE_B_NOT_A) != 0);
+
/* Check if both span trees are not defined */
if(a_spans == NULL && b_spans == NULL) {
*a_not_b = NULL;
@@ -5071,38 +7199,56 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
else if(a_spans == NULL) {
*a_not_b = NULL;
*a_and_b = NULL;
- if(NULL == (*b_not_a = H5S__hyper_copy_span(b_spans)))
- HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree")
+ if(need_b_not_a) {
+ if(NULL == (*b_not_a = H5S__hyper_copy_span(b_spans, ndims)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree")
+ } /* end if */
+ else
+ *b_not_a = NULL;
} /* end if */
/* If span 'b' is not defined, but 'a' is, copy 'a' and set the other return span trees to empty */
else if(b_spans == NULL) {
- if(NULL == (*a_not_b = H5S__hyper_copy_span(a_spans)) )
- HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree")
*a_and_b = NULL;
*b_not_a = NULL;
+ if(need_a_not_b) {
+ if(NULL == (*a_not_b = H5S__hyper_copy_span(a_spans, ndims)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree")
+ } /* end if */
+ else
+ *a_not_b = NULL;
} /* end if */
/* If span 'a' and 'b' are both defined, calculate the proper span trees */
else {
/* Check if both span trees completely overlap */
if(H5S__hyper_cmp_spans(a_spans, b_spans)) {
*a_not_b = NULL;
- if(NULL == (*a_and_b = H5S__hyper_copy_span(a_spans)))
- HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree")
*b_not_a = NULL;
+ if(need_a_and_b) {
+ if(NULL == (*a_and_b = H5S__hyper_copy_span(a_spans, ndims)))
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree")
+ } /* end if */
+ else
+ *a_and_b = NULL;
} /* end if */
else {
+ H5S_hyper_span_t *span_a; /* Pointer to a node in span tree 'a' */
+ H5S_hyper_span_t *span_b; /* Pointer to a node in span tree 'b' */
+ hbool_t recover_a, recover_b; /* Flags to indicate when to recover temporary spans */
+
/* Get the pointers to the new and old span lists */
span_a = a_spans->head;
span_b = b_spans->head;
- /* Reset the pointers to the previous spans */
- last_a_not_b = last_a_and_b = last_b_not_a = NULL;
-
/* No spans to recover yet */
recover_a = recover_b = FALSE;
/* Work through the list of spans in the new list */
while(span_a != NULL && span_b != NULL) {
+ H5S_hyper_span_info_t *down_a_not_b; /* Temporary pointer to a_not_b span tree of down spans for overlapping nodes */
+ H5S_hyper_span_info_t *down_a_and_b; /* Temporary pointer to a_and_b span tree of down spans for overlapping nodes */
+ H5S_hyper_span_info_t *down_b_not_a; /* Temporary pointer to b_and_a span tree of down spans for overlapping nodes */
+ H5S_hyper_span_t *tmp_span; /* Temporary pointer to new span */
+
/* Check if span 'a' is completely before span 'b' */
/* AAAAAAA */
/* <-----------------------------------> */
@@ -5111,11 +7257,12 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* 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) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ if(need_a_not_b)
+ if(H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_a->high, span_a->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Advance span 'a', leave span 'b' */
- H5S__hyper_recover_span(&recover_a, &span_a, span_a->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next);
} /* end if */
/* Check if span 'a' overlaps only the lower bound */
/* of span 'b' , up to the upper bound of span 'b' */
@@ -5126,8 +7273,9 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* 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) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ if(need_a_not_b)
+ if(H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_b->low - 1, span_a->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Check for overlaps between upper part of span 'a' and lower part of span 'b' */
@@ -5137,8 +7285,9 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* If there are no down spans, just add the overlapping area to the a_and_b list */
if(span_a->down == NULL) {
/* Merge/add overlapped part with/to a_and_b list */
- if(H5S__hyper_append_span(&last_a_and_b, a_and_b, span_b->low, span_a->high, NULL, NULL) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ if(need_a_and_b)
+ if(H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_a->high, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
} /* end if */
/* If there are down spans, check for the overlap in them and add to each appropriate list */
else {
@@ -5148,14 +7297,20 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
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)
+ /** Note: since the bound box of remaining dimensions
+ * has been updated in the following clip function (via
+ * all_clips_bounds), there's no need updating the bound box
+ * after each append call in the following codes */
+ if(H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1, &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
/* Check for additions to the a_not_b list */
if(down_a_not_b) {
+ HDassert(need_a_not_b == TRUE);
+
/* Merge/add overlapped part with/to a_not_b list */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(a_not_b, ndims, span_b->low, span_a->high, down_a_not_b) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Release the down span tree generated */
H5S__hyper_free_span_info(down_a_not_b);
@@ -5163,9 +7318,11 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* Check for additions to the a_and_b list */
if(down_a_and_b) {
+ HDassert(need_a_and_b == TRUE);
+
/* Merge/add overlapped part with/to a_and_b list */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_a->high, down_a_and_b) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Release the down span tree generated */
H5S__hyper_free_span_info(down_a_and_b);
@@ -5173,9 +7330,11 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* Check for additions to the b_not_a list */
if(down_b_not_a) {
+ HDassert(need_b_not_a == TRUE);
+
/* Merge/add overlapped part with/to b_not_a list */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_a->high, down_b_not_a) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Release the down span tree generated */
H5S__hyper_free_span_info(down_b_not_a);
@@ -5185,23 +7344,23 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* 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) {
+ if(span_a->high < span_b->high) {
/* Allocate new span node for upper part of span 'b' */
if(NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down, span_b->next)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+ HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
/* Advance span 'a' */
- H5S__hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_HYPER_ADVANCE_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);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span);
recover_b = TRUE;
} /* end if */
/* No upper part of span 'b' to split */
else {
/* Advance both 'a' and 'b' */
- H5S__hyper_recover_span(&recover_a,&span_a,span_a->next);
- H5S__hyper_recover_span(&recover_b,&span_b,span_b->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next);
} /* end else */
} /* end if */
/* Check if span 'a' overlaps the lower & upper bound */
@@ -5213,8 +7372,9 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* 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")
+ if(need_a_not_b)
+ if(H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_b->low - 1, span_a->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Check for overlaps between middle part of span 'a' and span 'b' */
@@ -5224,8 +7384,9 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* 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")
+ if(need_a_and_b)
+ if(H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_b->high, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
} /* end if */
/* If there are down spans, check for the overlap in them and add to each appropriate list */
else {
@@ -5235,14 +7396,16 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
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)
+ if(H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1, &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
/* Check for additions to the a_not_b list */
if(down_a_not_b) {
+ HDassert(need_a_not_b == TRUE);
+
/* Merge/add overlapped part with/to a_not_b list */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(a_not_b, ndims, span_b->low, span_b->high, down_a_not_b) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Release the down span tree generated */
H5S__hyper_free_span_info(down_a_not_b);
@@ -5250,9 +7413,11 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* Check for additions to the a_and_b list */
if(down_a_and_b) {
+ HDassert(need_a_and_b == TRUE);
+
/* Merge/add overlapped part with/to a_and_b list */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(a_and_b, ndims, span_b->low, span_b->high, down_a_and_b) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Release the down span tree generated */
H5S__hyper_free_span_info(down_a_and_b);
@@ -5260,9 +7425,11 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* Check for additions to the b_not_a list */
if(down_b_not_a) {
+ HDassert(need_b_not_a == TRUE);
+
/* Merge/add overlapped part with/to b_not_a list */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_b->high, down_b_not_a) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Release the down span tree generated */
H5S__hyper_free_span_info(down_b_not_a);
@@ -5276,11 +7443,11 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
/* Make upper part of span 'a' the new span 'a' */
- H5S__hyper_recover_span(&recover_a,&span_a,tmp_span);
+ H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span);
recover_a = TRUE;
/* Advance span 'b' */
- H5S__hyper_recover_span(&recover_b,&span_b,span_b->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next);
} /* end if */
/* Check if span 'a' is entirely within span 'b' */
/* AAAAA */
@@ -5292,8 +7459,9 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* 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")
+ if(need_b_not_a)
+ if(H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_a->low - 1, span_b->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
} /* end if */
else {
/* Keep going, nothing to split off */
@@ -5307,8 +7475,9 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* 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")
+ if(need_a_and_b)
+ if(H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_a->high, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
} /* end if */
/* If there are down spans, check for the overlap in them and add to each appropriate list */
else {
@@ -5318,34 +7487,40 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
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)
+ if(H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1, &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
/* Check for additions to the a_not_b list */
if(down_a_not_b) {
+ HDassert(need_a_not_b == TRUE);
+
/* Merge/add overlapped part with/to a_not_b list */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_a->high, down_a_not_b) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* 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) {
+ if(down_a_and_b) {
+ HDassert(need_a_and_b == TRUE);
+
/* Merge/add overlapped part with/to a_and_b list */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_a->high, down_a_and_b) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* 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) {
+ if(down_b_not_a) {
+ HDassert(need_b_not_a == TRUE);
+
/* Merge/add overlapped part with/to b_not_a list */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(b_not_a, ndims, span_a->low, span_a->high, down_b_not_a) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Release the down span tree generated */
H5S__hyper_free_span_info(down_b_not_a);
@@ -5353,24 +7528,24 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
} /* end else */
/* Check if there is actually an upper part of span 'b' to split off */
- if(span_a->high<span_b->high) {
+ if(span_a->high < span_b->high) {
/* Split off upper part of span 'b' at upper span of span 'a' */
/* Allocate new span node for upper part of spans 'a' */
if(NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down, span_b->next)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span")
/* And advance span 'a' */
- H5S__hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_HYPER_ADVANCE_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;
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span);
+ recover_b = TRUE;
} /* 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);
+ H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next);
} /* end else */
} /* end if */
/* Check if span 'a' overlaps only the upper bound */
@@ -5378,14 +7553,15 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* AAAAAAAAAA */
/* <-----------------------------------> */
/* BBBBBBBBBB */
- else if((span_a->low>=span_b->low && span_a->low<=span_b->high) && span_a->high>span_b->high) {
+ 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) {
+ 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")
+ if(need_b_not_a)
+ if(H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_a->low - 1, span_b->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
} /* end if */
else {
/* Keep going, nothing to split off */
@@ -5399,8 +7575,9 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* 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")
+ if(need_a_and_b)
+ if(H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_b->high, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
} /* end if */
/* If there are down spans, check for the overlap in them and add to each appropriate list */
else {
@@ -5410,24 +7587,28 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
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)
+ if(H5S__hyper_clip_spans(span_a->down, span_b->down, selector, ndims - 1, &down_a_not_b, &down_a_and_b, &down_b_not_a) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
/* Check for additions to the a_not_b list */
if(down_a_not_b) {
+ HDassert(need_a_not_b == TRUE);
+
/* Merge/add overlapped part with/to a_not_b list */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_b->high, down_a_not_b) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* 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) {
+ if(down_a_and_b) {
+ HDassert(need_a_and_b == TRUE);
+
/* Merge/add overlapped part with/to a_and_b list */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(a_and_b, ndims, span_a->low, span_b->high, down_a_and_b) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Release the down span tree generated */
H5S__hyper_free_span_info(down_a_and_b);
@@ -5435,9 +7616,11 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* Check for additions to the b_not_a list */
if(down_b_not_a) {
+ HDassert(need_b_not_a == TRUE);
+
/* Merge/add overlapped part with/to b_not_a list */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(b_not_a, ndims, span_a->low, span_b->high, down_b_not_a) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Release the down span tree generated */
H5S__hyper_free_span_info(down_b_not_a);
@@ -5448,14 +7631,14 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* Allocate new span node for upper part of span 'a' */
if(NULL == (tmp_span = H5S__hyper_new_span(span_b->high + 1, span_a->high, span_a->down, span_a->next)))
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span")
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span")
/* Make upper part of span 'a' into new span 'a' */
- H5S__hyper_recover_span(&recover_a,&span_a,tmp_span);
- recover_a=1;
+ H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span);
+ recover_a = TRUE;
/* Advance span 'b' */
- H5S__hyper_recover_span(&recover_b,&span_b,span_b->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next);
} /* end if */
/* span 'a' must be entirely above span 'b' */
/* AAAAA */
@@ -5465,40 +7648,70 @@ H5S__hyper_clip_spans(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_s
/* 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")
+ if(need_b_not_a)
+ if(H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_b->high, span_b->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
/* Advance span 'b', leave span 'a' */
- H5S__hyper_recover_span(&recover_b,&span_b,span_b->next);
+ H5S_HYPER_ADVANCE_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")
+ /* Check if need to merge/add 'a' spans with/to a_not_b list */
+ if(need_a_not_b) {
+ /* (This loop, and the similar one below for 'b' spans,
+ * could be replaced with an optimized routine that quickly
+ * appended the remaining spans to the 'not' list, but
+ * until it looks like it's taking a lot of time for an
+ * important use case, it's been left generic, and similar
+ * to other code above. -QAK, 2019/02/01)
+ */
+ while(span_a != NULL) {
+ /* Copy span 'a' and add to a_not_b list */
+ if(H5S__hyper_append_span(a_not_b, ndims, span_a->low, span_a->high, span_a->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
- /* Advance to the next 'a' span */
- H5S__hyper_recover_span(&recover_a,&span_a,span_a->next);
- } /* end while */
+ /* Advance to the next 'a' span */
+ H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next);
+ } /* end while */
+ } /* end if */
+ else {
+ /* Free the span, if it's generated */
+ if(recover_a)
+ H5S__hyper_free_span(span_a);
+ } /* end else */
} /* end if */
/* Clean up 'b' spans which haven't been covered yet */
else if(span_a == NULL && span_b != NULL) {
- 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")
+ /* Check if need to merge/add 'b' spans with/to b_not_a list */
+ if(need_b_not_a) {
+ /* (This loop, and the similar one above for 'a' spans,
+ * could be replaced with an optimized routine that quickly
+ * appended the remaining spans to the 'not' list, but
+ * until it looks like it's taking a lot of time for an
+ * important use case, it's been left generic, and similar
+ * to other code above. -QAK, 2019/02/01)
+ */
+ while(span_b != NULL) {
+ /* Copy span 'b' and add to b_not_a list */
+ if(H5S__hyper_append_span(b_not_a, ndims, span_b->low, span_b->high, span_b->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
- /* Advance to the next 'b' span */
- H5S__hyper_recover_span(&recover_b,&span_b,span_b->next);
- } /* end while */
+ /* Advance to the next 'b' span */
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next);
+ } /* end while */
+ } /* end if */
+ else {
+ /* Free the span, if it's generated */
+ if(recover_b)
+ H5S__hyper_free_span(span_b);
+ } /* end else */
} /* end if */
+ else
+ /* Sanity check */
+ HDassert(span_a == NULL && span_b == NULL);
} /* end else */
} /* end else */
@@ -5518,6 +7731,7 @@ done:
together
H5S_hyper_span_info_t *b_spans; IN: Second hyperslab spans to merge
together
+ unsigned ndims; IN: Number of dimensions of this span tree
RETURNS
Pointer to span tree containing the merged spans on success, NULL on failure
DESCRIPTION
@@ -5525,19 +7739,15 @@ done:
the merged set.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
+ Handles merging span trees that overlap.
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
static H5S_hyper_span_info_t *
-H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans)
+H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans,
+ unsigned ndims)
{
H5S_hyper_span_info_t *merged_spans = NULL; /* Pointer to the merged span tree */
- H5S_hyper_span_info_t *tmp_spans; /* Pointer to temporary new span tree */
- H5S_hyper_span_t *tmp_span; /* Pointer to temporary new span */
- H5S_hyper_span_t *span_a; /* Pointer to current span 'a' working on */
- H5S_hyper_span_t *span_b; /* Pointer to current span 'b' working on */
- H5S_hyper_span_t *prev_span_merge; /* Pointer to previous merged span */
- hbool_t recover_a, recover_b; /* Flags to indicate when to recover temporary spans */
H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
FUNC_ENTER_STATIC
@@ -5551,34 +7761,38 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
merged_spans = NULL;
else {
/* Copy one of the span trees to return */
- if(NULL == (merged_spans = H5S__hyper_copy_span(a_spans)))
+ if(NULL == (merged_spans = H5S__hyper_copy_span(a_spans, ndims)))
HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree")
} /* end else */
} /* end if */
else {
+ H5S_hyper_span_t *span_a; /* Pointer to current span 'a' working on */
+ H5S_hyper_span_t *span_b; /* Pointer to current span 'b' working on */
+ hbool_t recover_a, recover_b; /* Flags to indicate when to recover temporary spans */
+
/* Get the pointers to the 'a' and 'b' span lists */
span_a = a_spans->head;
span_b = b_spans->head;
- /* Set the pointer to the previous spans */
- prev_span_merge = NULL;
-
/* No spans to recover yet */
recover_a = recover_b = FALSE;
/* Work through the list of spans in the new list */
while(span_a != NULL && span_b != NULL) {
+ H5S_hyper_span_info_t *tmp_spans; /* Pointer to temporary new span tree */
+ H5S_hyper_span_t *tmp_span; /* Pointer to temporary new span */
+
/* Check if the 'a' span is completely before 'b' span */
/* AAAAAAA */
/* <-----------------------------------> */
/* BBBBBBBBBB */
if(span_a->high < span_b->low) {
/* Merge/add span 'a' with/to the merged spans */
- if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,span_a->down,NULL)==FAIL)
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, span_a->down) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
/* Advance span 'a' */
- H5S__hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next);
} /* end if */
/* Check if span 'a' overlaps only the lower bound */
/* of span 'b', up to the upper bound of span 'b' */
@@ -5589,19 +7803,19 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
/* Check if span 'a' and span 'b' down spans are equal */
if(H5S__hyper_cmp_spans(span_a->down, span_b->down)) {
/* Merge/add copy of span 'a' with/to merged spans */
- if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,span_a->down,NULL)==FAIL)
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, span_a->down) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
} /* end if */
else {
/* Merge/add lower part of span 'a' with/to merged spans */
- if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->low-1,span_a->down,NULL)==FAIL)
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->low - 1, span_a->down) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
/* Get merged span tree for overlapped section */
- tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down);
+ tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1);
/* Merge/add overlapped section to merged spans */
- if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->high,tmp_spans,NULL)==FAIL)
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->high, tmp_spans) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
/* Release merged span tree for overlapped section */
@@ -5613,20 +7827,20 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
/* 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_DATASPACE, H5E_NOSPACE, NULL, "can't allocate hyperslab span")
+ if(NULL == (tmp_span = H5S__hyper_new_span(span_a->high + 1, span_b->high, span_b->down, span_b->next)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span")
/* Advance span 'a' */
- H5S__hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_HYPER_ADVANCE_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);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span);
recover_b = TRUE;
} /* end if */
else {
/* Advance both span 'a' & 'b' */
- H5S__hyper_recover_span(&recover_a,&span_a,span_a->next);
- H5S__hyper_recover_span(&recover_b,&span_b,span_b->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next);
} /* end else */
} /* end if */
/* Check if span 'a' overlaps the lower & upper bound */
@@ -5638,19 +7852,19 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
/* Check if span 'a' and span 'b' down spans are equal */
if(H5S__hyper_cmp_spans(span_a->down, span_b->down)) {
/* Merge/add copy of lower & middle parts of span 'a' to merged spans */
- if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->high,span_a->down,NULL)==FAIL)
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->high, span_a->down) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
} /* end if */
else {
/* Merge/add lower part of span 'a' to merged spans */
- if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->low-1,span_a->down,NULL)==FAIL)
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->low - 1, span_a->down) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
/* Get merged span tree for overlapped section */
- tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down);
+ tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1);
/* Merge/add overlapped section to merged spans */
- if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,tmp_spans,NULL)==FAIL)
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, tmp_spans) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
/* Release merged span tree for overlapped section */
@@ -5664,11 +7878,11 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span")
/* Set new span 'a' to tmp_span */
- H5S__hyper_recover_span(&recover_a,&span_a,tmp_span);
+ H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span);
recover_a = TRUE;
/* Advance span 'b' */
- H5S__hyper_recover_span(&recover_b,&span_b,span_b->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next);
} /* end if */
/* Check if span 'a' is entirely within span 'b' */
/* AAAAA */
@@ -5678,14 +7892,14 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
/* Check if span 'a' and span 'b' down spans are equal */
if(H5S__hyper_cmp_spans(span_a->down, span_b->down)) {
/* Merge/add copy of lower & middle parts of span 'b' to merged spans */
- if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->high,span_a->down,NULL)==FAIL)
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->high, span_a->down) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
} /* end if */
else {
/* Check if there is a lower part of span 'b' */
if(span_a->low > span_b->low) {
/* Merge/add lower part of span 'b' to merged spans */
- if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->low-1,span_b->down,NULL)==FAIL)
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->low - 1, span_b->down) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
} /* end if */
else {
@@ -5693,10 +7907,10 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
} /* end else */
/* Get merged span tree for overlapped section */
- tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down);
+ tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1);
/* Merge/add overlapped section to merged spans */
- if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,tmp_spans,NULL)==FAIL)
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, tmp_spans) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
/* Release merged span tree for overlapped section */
@@ -5712,16 +7926,16 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span")
/* Advance span 'a' */
- H5S__hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_HYPER_ADVANCE_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);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, tmp_span);
recover_b = TRUE;
} /* end if */
else {
/* Advance both spans */
- H5S__hyper_recover_span(&recover_a,&span_a,span_a->next);
- H5S__hyper_recover_span(&recover_b,&span_b,span_b->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next);
} /* end else */
} /* end if */
/* Check if span 'a' overlaps only the upper bound */
@@ -5733,26 +7947,26 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
/* Check if span 'a' and span 'b' down spans are equal */
if(H5S__hyper_cmp_spans(span_a->down, span_b->down)) {
/* Merge/add copy of span 'b' to merged spans if so */
- if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,span_b->down,NULL)==FAIL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, span_b->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
} /* end if */
else {
/* Check if there is a lower part of span 'b' */
if(span_a->low > span_b->low) {
/* Merge/add lower part of span 'b' to merged spans */
- if(H5S__hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->low-1,span_b->down,NULL)==FAIL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_a->low - 1, span_b->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
} /* end if */
else {
/* No lower part of span 'b' , keep going... */
} /* end else */
/* Get merged span tree for overlapped section */
- tmp_spans = H5S__hyper_merge_spans_helper(span_a->down,span_b->down);
+ tmp_spans = H5S__hyper_merge_spans_helper(span_a->down, span_b->down, ndims - 1);
/* Merge/add overlapped section to merged spans */
- if(H5S__hyper_append_span(&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")
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_b->high, tmp_spans) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
/* Release merged span tree for overlapped section */
H5S__hyper_free_span_info(tmp_spans);
@@ -5765,11 +7979,11 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span")
/* Set new span 'a' to tmp_span */
- H5S__hyper_recover_span(&recover_a,&span_a,tmp_span);
+ H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, tmp_span);
recover_a = TRUE;
/* Advance span 'b' */
- H5S__hyper_recover_span(&recover_b,&span_b,span_b->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next);
} /* end if */
/* Span 'a' must be entirely above span 'b' */
/* AAAAA */
@@ -5777,11 +7991,11 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
/* 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")
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, span_b->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
/* Advance span 'b' */
- H5S__hyper_recover_span(&recover_b,&span_b,span_b->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next);
} /* end else */
} /* end while */
@@ -5789,11 +8003,11 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
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")
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_a->low, span_a->high, span_a->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
/* Advance to next 'a' span, until all processed */
- H5S__hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_a, span_a, span_a->next);
} /* end while */
} /* end if */
@@ -5801,11 +8015,11 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
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")
+ if(H5S__hyper_append_span(&merged_spans, ndims, span_b->low, span_b->high, span_b->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, NULL, "can't allocate hyperslab span")
/* Advance to next 'b' span, until all processed */
- H5S__hyper_recover_span(&recover_b,&span_b,span_b->next);
+ H5S_HYPER_ADVANCE_SPAN(recover_b, span_b, span_b->next);
} /* end while */
} /* end if */
} /* end else */
@@ -5815,8 +8029,8 @@ H5S__hyper_merge_spans_helper(H5S_hyper_span_info_t *a_spans, H5S_hyper_span_inf
done:
if(ret_value == NULL)
- if(merged_spans && H5S__hyper_free_span_info(merged_spans) < 0)
- HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, NULL, "failed to release merged hyperslab spans")
+ if(merged_spans)
+ H5S__hyper_free_span_info(merged_spans);
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5S__hyper_merge_spans_helper() */
@@ -5833,44 +8047,37 @@ done:
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.
+ Add a set of hyperslab spans to an existing 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)
+H5S__hyper_merge_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans)
{
- FUNC_ENTER_NOAPI_NOINIT_NOERR
+ herr_t ret_value = SUCCEED; /* Return value */
- /* Check args */
+ FUNC_ENTER_STATIC
+
+ /* Sanity checks */
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);
+ space->select.sel_info.hslab->span_lst = new_spans;
+ space->select.sel_info.hslab->span_lst->count++;
} /* 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);
+ if(NULL == (merged_spans = H5S__hyper_merge_spans_helper(space->select.sel_info.hslab->span_lst, new_spans, space->extent.rank)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTMERGE, FAIL, "can't merge hyperslab spans")
/* Free the previous spans */
H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst);
@@ -5879,18 +8086,21 @@ H5S__hyper_merge_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans, hbool_t c
space->select.sel_info.hslab->span_lst = merged_spans;
} /* end else */
- FUNC_LEAVE_NOAPI(SUCCEED)
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
} /* end H5S__hyper_merge_spans() */
/*--------------------------------------------------------------------------
NAME
- H5S__hyper_spans_nelem
+ H5S__hyper_spans_nelem_helper
PURPOSE
Count the number of elements in a span tree
USAGE
- hsize_t H5S__hyper_spans_nelem(spans)
+ hsize_t H5S__hyper_spans_nelem_helper(spans, op_info_i, op_gen)
const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of
+ unsigned op_info_i; IN: Index of op info to use
+ uint64_t op_gen; IN: Operation generation
RETURNS
Number of elements in span tree on success; negative on failure
DESCRIPTION
@@ -5901,33 +8111,147 @@ H5S__hyper_merge_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans, hbool_t c
REVISION LOG
--------------------------------------------------------------------------*/
static hsize_t
-H5S__hyper_spans_nelem(const H5S_hyper_span_info_t *spans)
+H5S__hyper_spans_nelem_helper(H5S_hyper_span_info_t *spans, unsigned op_info_i,
+ uint64_t op_gen)
{
hsize_t ret_value = 0; /* Return value */
FUNC_ENTER_STATIC_NOERR
- /* Count the number of elements in the span tree */
- if(spans != NULL) {
+ /* Sanity check */
+ HDassert(spans);
+
+ /* Check if the span tree was already counted */
+ if(spans->op_info[op_info_i].op_gen == op_gen)
+ /* Just return the # of elements in the already counted span tree */
+ ret_value = spans->op_info[op_info_i].u.nelmts;
+ else { /* Count the number of elements in the span tree */
const H5S_hyper_span_t *span; /* Hyperslab span */
span = spans->head;
- while(span != NULL) {
- /* If there are down spans, multiply the size of this span by the total down span elements */
- if(span->down != NULL)
- ret_value += span->nelem * H5S__hyper_spans_nelem(span->down);
- /* If there are no down spans, just count the elements in this span */
- else
- ret_value += span->nelem;
+ if(NULL == span->down) {
+ while(span != NULL) {
+ /* Compute # of elements covered */
+ ret_value += (span->high - span->low) + 1;
- /* Advance to next span */
- span = span->next;
- } /* end while */
+ /* Advance to next span */
+ span = span->next;
+ } /* end while */
+ } /* end if */
+ else {
+ while(span != NULL) {
+ hsize_t nelmts; /* # of elements covered by current span */
+
+ /* Compute # of elements covered */
+ nelmts = (span->high - span->low) + 1;
+
+ /* Multiply the size of this span by the total down span elements */
+ ret_value += nelmts * H5S__hyper_spans_nelem_helper(span->down, op_info_i, op_gen);
+
+ /* Advance to next span */
+ span = span->next;
+ } /* end while */
+ } /* end else */
+
+ /* Set the operation generation for this span tree, to avoid re-computing */
+ spans->op_info[op_info_i].op_gen = op_gen;
+
+ /* Hold a copy of the # of elements */
+ spans->op_info[op_info_i].u.nelmts = ret_value;
} /* end else */
FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__hyper_spans_nelem_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_spans_nelem
+ PURPOSE
+ Count the number of elements in a span tree
+ USAGE
+ hsize_t H5S__hyper_spans_nelem(spans)
+ const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of
+ RETURNS
+ Number of elements in span tree on success; negative on failure
+ DESCRIPTION
+ Counts the number of elements described by the spans in a span tree.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static hsize_t
+H5S__hyper_spans_nelem(H5S_hyper_span_info_t *spans)
+{
+ uint64_t op_gen; /* Operation generation value */
+ hsize_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(spans);
+
+ /* Acquire an operation generation value for this operation */
+ op_gen = H5S__hyper_get_op_gen();
+
+ /* Count the number of elements in the span tree */
+ /* Always use op_info[0] since we own this op_info, so there can be no
+ * simultaneous operations */
+ ret_value = H5S__hyper_spans_nelem_helper(spans, 0, op_gen);
+
+ FUNC_LEAVE_NOAPI(ret_value)
} /* end H5S__hyper_spans_nelem() */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_add_disjoint_spans
+ PURPOSE
+ Add new hyperslab spans to existing hyperslab selection in the case the
+ new hyperslab spans don't overlap with the existing hyperslab selection
+ USAGE
+ herr_t H5S__hyper_add_disjoint_spans(space, new_spans)
+ H5S_t *space; IN: Dataspace to add new spans to hyperslab
+ selection.
+ H5S_hyper_span_t *new_spans; IN: Span tree of new spans to add to
+ hyperslab selection
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Add a set of hyperslab spans to an existing hyperslab selection. The
+ new spans are required not to overlap with the existing spans in the
+ dataspace's current hyperslab selection in terms of bound box.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S__hyper_add_disjoint_spans(H5S_t *space, H5S_hyper_span_info_t *new_spans)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Check args */
+ HDassert(space);
+ HDassert(new_spans);
+
+ /* Update the number of elements in the selection */
+ space->select.num_elem += H5S__hyper_spans_nelem(new_spans);
+
+ /* Add the new spans to the existing selection in the dataspace */
+ if(H5S__hyper_merge_spans(space, new_spans) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't merge hyperslabs")
+
+ /* Free the memory space for new spans */
+ H5S__hyper_free_span_info(new_spans);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__hyper_add_disjoint_spans */
+
/*--------------------------------------------------------------------------
NAME
@@ -5936,12 +8260,12 @@ H5S__hyper_spans_nelem(const H5S_hyper_span_info_t *spans)
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
+ 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
+ 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
@@ -5961,9 +8285,7 @@ H5S__hyper_make_spans(unsigned rank, const hsize_t *start, const hsize_t *stride
H5S_hyper_span_info_t *down = NULL; /* Pointer to spans in next dimension down */
H5S_hyper_span_t *last_span; /* Current position in hyperslab span list */
H5S_hyper_span_t *head = NULL; /* Head of new hyperslab span list */
- hsize_t stride_iter; /* Iterator over the stride values */
int i; /* Counters */
- unsigned u; /* Counters */
H5S_hyper_span_info_t *ret_value = NULL; /* Return value */
FUNC_ENTER_STATIC
@@ -5977,6 +8299,9 @@ H5S__hyper_make_spans(unsigned rank, const hsize_t *start, const hsize_t *stride
/* Start creating spans in fastest changing dimension */
for(i = (int)(rank - 1); i >= 0; i--) {
+ hsize_t curr_low, curr_high; /* Current low & high values */
+ hsize_t dim_stride; /* Current dim's stride */
+ unsigned u; /* Local index variable */
/* Sanity check */
if(0 == count[i])
@@ -5987,8 +8312,10 @@ H5S__hyper_make_spans(unsigned rank, const hsize_t *start, const hsize_t *stride
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])
- {
+ curr_low = start[i];
+ curr_high = start[i] + (block[i] - 1);
+ dim_stride = stride[i];
+ for(u = 0; u < count[i]; u++, curr_low += dim_stride, curr_high += dim_stride) {
H5S_hyper_span_t *span; /* New hyperslab span */
/* Allocate a span node */
@@ -5996,12 +8323,14 @@ H5S__hyper_make_spans(unsigned rank, const hsize_t *start, const hsize_t *stride
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->low = curr_low;
+ span->high = curr_high;
span->next = NULL;
+ /* Set the information for the next dimension down's spans */
+ /* (Will be NULL for fastest changing dimension) */
+ span->down = down;
+
/* Append to the list of spans in this dimension */
if(head == NULL)
head = span;
@@ -6010,23 +8339,32 @@ H5S__hyper_make_spans(unsigned rank, const hsize_t *start, const hsize_t *stride
/* Move current pointer */
last_span = span;
-
- /* Set the information for the next dimension down's spans, if appropriate */
- if(down != NULL) {
- span->down = down;
- down->count++; /* Increment reference count for shared span */
- } /* end if */
- else
- span->down = NULL;
} /* end for */
+ /* Increment ref. count of shared span */
+ if(down != NULL)
+ down->count = (unsigned)count[i];
+
/* Allocate a span info node */
- if(NULL == (down = H5FL_CALLOC(H5S_hyper_span_info_t)))
+ if(NULL == (down = H5S__hyper_new_span_info(rank)))
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, NULL, "can't allocate hyperslab span")
/* Keep the pointer to the next dimension down's completed list */
down->head = head;
+ /* Keep the tail pointer to the next dimension down's completed list */
+ down->tail = last_span;
+
+ /* Set the low & high bounds for this dimension */
+ down->low_bounds[0] = down->head->low;
+ down->high_bounds[0] = down->tail->high;
+
+ /* Copy bounds from lower dimensions */
+ /* (head & tail pointers share lower dimensions, so using either is OK) */
+ if(head->down) {
+ H5MM_memcpy(&down->low_bounds[1], &head->down->low_bounds[0], sizeof(hsize_t) * ((rank - 1) - (unsigned)i));
+ H5MM_memcpy(&down->high_bounds[1], &head->down->high_bounds[0], sizeof(hsize_t) * ((rank - 1) - (unsigned)i));
+ } /* end if */
} /* end for */
/* Indicate that there is a pointer to this tree */
@@ -6047,7 +8385,7 @@ done:
do {
if(down) {
head = down->head;
- down = H5FL_FREE(H5S_hyper_span_info_t, down);
+ down = (H5S_hyper_span_info_t *)H5FL_ARR_FREE(hbounds_t, down);
} /* end if */
down = head->down;
@@ -6063,6 +8401,224 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5S__hyper_make_spans() */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__hyper_update_diminfo
+ PURPOSE
+ Attempt to update optimized hyperslab information quickly. (It can be
+ recovered with regular selection). If this algorithm cannot determine
+ the optimized dimension info quickly, this function will simply mark it
+ as invalid and unknown if it can be built (H5S_DIMINFO_VALID_NO), so
+ H5S__hyper_rebuild can be run later to determine for sure.
+ USAGE
+ herr_t H5S__hyper_update_diminfo(space, op, new_hyper_diminfo)
+ H5S_t *space; IN: Dataspace to check
+ H5S_seloper_t op; IN: The operation being performed on the
+ selection
+ const H5S_hyper_dim_t new_hyper_diminfo; IN: The new selection that
+ is being combined with
+ the current
+ RETURNS
+ >=0 on success, <0 on failure
+ DESCRIPTION
+ Examine the span tree for a hyperslab selection and rebuild
+ the start/stride/count/block information for the selection, if possible.
+
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S__hyper_update_diminfo(H5S_t *space, H5S_seloper_t op,
+ const H5S_hyper_dim_t *new_hyper_diminfo)
+{
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Check args */
+ HDassert(space);
+ HDassert(new_hyper_diminfo);
+
+ /* Check for conditions that prevent us from using the fast algorithm here */
+ /* (and instead require H5S__hyper_rebuild) */
+ if(!((op == H5S_SELECT_OR) || (op == H5S_SELECT_XOR))
+ || space->select.sel_info.hslab->diminfo_valid != H5S_DIMINFO_VALID_YES
+ || !space->select.sel_info.hslab->span_lst->head)
+ space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
+ else {
+ H5S_hyper_dim_t tmp_diminfo[H5S_MAX_RANK]; /* Temporary dimension info */
+ hbool_t found_nonidentical_dim = FALSE;
+ unsigned curr_dim;
+
+ /* Copy current diminfo.opt values */
+ H5MM_memcpy(tmp_diminfo, space->select.sel_info.hslab->diminfo.opt, sizeof(tmp_diminfo));
+
+ /* Loop over dimensions */
+ for(curr_dim = 0; curr_dim < space->extent.rank; curr_dim++) {
+ /* Check for this being identical */
+ if((tmp_diminfo[curr_dim].start != new_hyper_diminfo[curr_dim].start)
+ || (tmp_diminfo[curr_dim].stride != new_hyper_diminfo[curr_dim].stride)
+ || (tmp_diminfo[curr_dim].count != new_hyper_diminfo[curr_dim].count)
+ || (tmp_diminfo[curr_dim].block != new_hyper_diminfo[curr_dim].block)) {
+ hsize_t high_start, high_count, high_block; /* The start, count & block values for the higher block */
+
+ /* Dimension is not identical */
+ /* Check if we already found a nonidentical dim - only one is
+ * allowed */
+ if(found_nonidentical_dim) {
+ space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
+ break;
+ } /* end if */
+
+ /* Check that strides are the same, or count is 1 for one of the
+ * slabs */
+ if((tmp_diminfo[curr_dim].stride != new_hyper_diminfo[curr_dim].stride)
+ && (tmp_diminfo[curr_dim].count > 1)
+ && (new_hyper_diminfo[curr_dim].count > 1)) {
+ space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
+ break;
+ } /* end if */
+
+ /* Patch tmp_diminfo.stride if its count is 1 */
+ if((tmp_diminfo[curr_dim].count == 1)
+ && (new_hyper_diminfo[curr_dim].count > 1))
+ tmp_diminfo[curr_dim].stride = new_hyper_diminfo[curr_dim].stride;
+
+ /* Determine lowest start, and set tmp_diminfo.start, count and
+ * block to use the lowest, and high_start, high_count and
+ * high_block to use the highest
+ */
+ if(tmp_diminfo[curr_dim].start < new_hyper_diminfo[curr_dim].start) {
+ high_start = new_hyper_diminfo[curr_dim].start;
+ high_count = new_hyper_diminfo[curr_dim].count;
+ high_block = new_hyper_diminfo[curr_dim].block;
+ } /* end if */
+ else {
+ high_start = tmp_diminfo[curr_dim].start;
+ tmp_diminfo[curr_dim].start = new_hyper_diminfo[curr_dim].start;
+ high_count = tmp_diminfo[curr_dim].count;
+ tmp_diminfo[curr_dim].count = new_hyper_diminfo[curr_dim].count;
+ high_block = tmp_diminfo[curr_dim].block;
+ tmp_diminfo[curr_dim].block = new_hyper_diminfo[curr_dim].block;
+ } /* end else */
+
+ /* If count is 1 for both slabs, take different actions */
+ if((tmp_diminfo[curr_dim].count == 1) && (high_count == 1)) {
+ /* Check for overlap */
+ if((tmp_diminfo[curr_dim].start + tmp_diminfo[curr_dim].block)
+ > high_start) {
+ /* Check operation type */
+ if(op == H5S_SELECT_OR)
+ /* Merge blocks */
+ tmp_diminfo[curr_dim].block = ((high_start + high_block)
+ >= (tmp_diminfo[curr_dim].start + tmp_diminfo[curr_dim].block))
+ ? (high_start + high_block - tmp_diminfo[curr_dim].start)
+ : tmp_diminfo[curr_dim].block;
+ else {
+ /* Block values must be the same */
+ if(tmp_diminfo[curr_dim].block != high_block) {
+ space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
+ break;
+ } /* end if */
+
+ /* XOR - overlap creates 2 blocks */
+ tmp_diminfo[curr_dim].stride = high_block;
+ tmp_diminfo[curr_dim].count = 2;
+ tmp_diminfo[curr_dim].block = high_start - tmp_diminfo[curr_dim].start;
+ } /* end else */
+ } /* end if */
+ else if((tmp_diminfo[curr_dim].start + tmp_diminfo[curr_dim].block)
+ == high_start)
+ /* Blocks border, merge them */
+ tmp_diminfo[curr_dim].block += high_block;
+ else {
+ /* Distinct blocks */
+ /* Block values must be the same */
+ if(tmp_diminfo[curr_dim].block != high_block) {
+ space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
+ break;
+ } /* end if */
+
+ /* Create strided selection */
+ tmp_diminfo[curr_dim].stride = high_start - tmp_diminfo[curr_dim].start;
+ tmp_diminfo[curr_dim].count = 2;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Check if block values are the same */
+ if(tmp_diminfo[curr_dim].block != new_hyper_diminfo[curr_dim].block) {
+ space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
+ break;
+ } /* end if */
+
+ /* Check phase of strides */
+ if((tmp_diminfo[curr_dim].start % tmp_diminfo[curr_dim].stride)
+ != (new_hyper_diminfo[curr_dim].start % tmp_diminfo[curr_dim].stride)) {
+ space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
+ break;
+ } /* end if */
+
+ /* Check operation type */
+ if(op == H5S_SELECT_OR) {
+ /* Make sure the slabs border or overlap */
+ if(high_start > (tmp_diminfo[curr_dim].start
+ + (tmp_diminfo[curr_dim].count
+ * tmp_diminfo[curr_dim].stride))) {
+ space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
+ break;
+ } /* end if */
+ } /* end if */
+ else
+ /* XOR: Make sure the slabs border */
+ if(high_start != (tmp_diminfo[curr_dim].start
+ + (tmp_diminfo[curr_dim].count
+ * tmp_diminfo[curr_dim].stride))) {
+ space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
+ break;
+ } /* end if */
+
+ /* Set count for combined selection */
+ tmp_diminfo[curr_dim].count = ((high_start
+ - tmp_diminfo[curr_dim].start)
+ / tmp_diminfo[curr_dim].stride) + high_count;
+ } /* end else */
+
+ /* Indicate that we found a nonidentical dim */
+ found_nonidentical_dim = TRUE;
+ } /* end if */
+ } /* end for */
+
+ /* Check if we succeeded, if so, set the new diminfo values */
+ if(space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES)
+ for(curr_dim = 0; curr_dim < space->extent.rank; curr_dim++) {
+ hsize_t tmp_high_bound;
+
+ /* Set the new diminfo values */
+ space->select.sel_info.hslab->diminfo.app[curr_dim].start = space->select.sel_info.hslab->diminfo.opt[curr_dim].start = tmp_diminfo[curr_dim].start;
+ HDassert(tmp_diminfo[curr_dim].stride > 0);
+ space->select.sel_info.hslab->diminfo.app[curr_dim].stride = space->select.sel_info.hslab->diminfo.opt[curr_dim].stride = tmp_diminfo[curr_dim].stride;
+ HDassert(tmp_diminfo[curr_dim].count > 0);
+ space->select.sel_info.hslab->diminfo.app[curr_dim].count = space->select.sel_info.hslab->diminfo.opt[curr_dim].count = tmp_diminfo[curr_dim].count;
+ HDassert(tmp_diminfo[curr_dim].block > 0);
+ space->select.sel_info.hslab->diminfo.app[curr_dim].block = space->select.sel_info.hslab->diminfo.opt[curr_dim].block = tmp_diminfo[curr_dim].block;
+
+ /* Check for updating the low & high bounds */
+ if(tmp_diminfo[curr_dim].start < space->select.sel_info.hslab->diminfo.low_bounds[curr_dim])
+ space->select.sel_info.hslab->diminfo.low_bounds[curr_dim] = tmp_diminfo[curr_dim].start;
+ tmp_high_bound = tmp_diminfo[curr_dim].start +
+ (tmp_diminfo[curr_dim].block - 1) +
+ (tmp_diminfo[curr_dim].stride * (tmp_diminfo[curr_dim].count - 1));
+ if(tmp_high_bound > space->select.sel_info.hslab->diminfo.low_bounds[curr_dim])
+ space->select.sel_info.hslab->diminfo.high_bounds[curr_dim] = tmp_high_bound;
+ } /* end for */
+ } /* end else */
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__hyper_update_diminfo() */
+
/*--------------------------------------------------------------------------
NAME
@@ -6072,9 +8628,8 @@ done:
(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
+ const H5S_hyper_span_t *spans; IN: Portion of span tree to check
+ H5S_hyper_dim_t span_slab_info[]; OUT: Rebuilt section of hyperslab description
RETURNS
TRUE/FALSE for hyperslab selection rebuilt
DESCRIPTION
@@ -6089,108 +8644,85 @@ done:
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)
+H5S__hyper_rebuild_helper(const H5S_hyper_span_info_t *spans, H5S_hyper_dim_t span_slab_info[])
{
+ const H5S_hyper_span_t *span; /* Hyperslab span */
+ const H5S_hyper_span_t *prev_span; /* Previous span in list */
+ hsize_t start; /* Starting element for this dimension */
+ hsize_t stride; /* Stride for this dimension */
+ hsize_t block; /* Block size for this dimension */
+ hsize_t prev_low; /* Low bound for previous span */
+ size_t spancount; /* Number of spans encountered in this dimension */
hbool_t ret_value = TRUE; /* Return value */
FUNC_ENTER_STATIC_NOERR
- if(span) {
- const H5S_hyper_span_t *prev_span = NULL; /* Previous span in list */
- H5S_hyper_dim_t canon_down_span_slab_info[H5S_MAX_RANK];
- hsize_t curr_stride;
- hsize_t curr_block;
- hsize_t curr_start;
- hsize_t curr_low;
- size_t outcount; /* Number of spans encountered in this dimension */
-
- /* Initialization */
- curr_stride = 1;
- curr_low = 0;
- outcount = 0;
-
- /* Get "canonical" down span information */
- if(span->down) {
- HDassert(span->down->head);
-
- /* Go to the next down span and check whether the selection can be rebuilt */
- if(!H5S__hyper_rebuild_helper(span->down->head, span_slab_info, rank - 1))
- HGOTO_DONE(FALSE)
-
- H5MM_memcpy(canon_down_span_slab_info, span_slab_info, sizeof(H5S_hyper_dim_t) * rank);
- } /* end if */
+ /* Sanity check */
+ HDassert(spans);
- /* Assign the initial starting point & block size */
- curr_start = span->low;
- curr_block = (span->high - span->low) + 1;
+ /* Initialization */
+ span = spans->head;
+ stride = 1;
+ prev_low = 0;
+ spancount = 0;
- /* Loop the spans */
- while(span) {
- if(outcount > 0) {
- hsize_t next_stride; /* Stride from previous span */
- hsize_t next_block; /* Block size of current span */
+ /* Get "canonical" down span information */
+ if(span->down)
+ /* Go to the next down span and check whether the selection can be rebuilt */
+ if(!H5S__hyper_rebuild_helper(span->down, &span_slab_info[1]))
+ HGOTO_DONE(FALSE)
- /* Check that down spans match current slab info */
- /* (Can skip check if previous span's down pointer is same as current one) */
- if(span->down && (NULL == prev_span || prev_span->down != span->down)) {
- H5S_hyper_dim_t *curr_down_span_slab_info;
- unsigned u; /* Local index variable */
+ /* Assign the initial starting point & block size for this dimension */
+ start = span->low;
+ block = (span->high - span->low) + 1;
- HDassert(span->down->head);
+ /* Loop the spans */
+ prev_span = NULL;
+ while(span) {
+ if(spancount > 0) {
+ hsize_t curr_stride; /* Current stride from previous span */
+ hsize_t curr_block; /* Block size of current span */
- /* Go to the next down span and check whether the selection can be rebuilt.*/
- if(!H5S__hyper_rebuild_helper(span->down->head, span_slab_info, rank - 1))
- HGOTO_DONE(FALSE)
+ /* Sanity check */
+ HDassert(prev_span);
- /* Compare the slab information of the adjacent spans in the down span tree.
- We have to compare all the sub-tree slab information with the canon_down_span_slab_info.*/
- for(u = 0; u < rank - 1; u++) {
- curr_down_span_slab_info = &span_slab_info[u];
-
- if(curr_down_span_slab_info->count > 0 && canon_down_span_slab_info[u].count > 0) {
- if(curr_down_span_slab_info->start != canon_down_span_slab_info[u].start
- || curr_down_span_slab_info->stride != canon_down_span_slab_info[u].stride
- || curr_down_span_slab_info->block != canon_down_span_slab_info[u].block
- || curr_down_span_slab_info->count != canon_down_span_slab_info[u].count)
- HGOTO_DONE(FALSE)
- } /* end if */
- else if(!((curr_down_span_slab_info->count == 0) && (canon_down_span_slab_info[u].count == 0)))
- HGOTO_DONE(FALSE)
- } /* end for */
- } /* end if */
+ /* Check that down spans match current slab info */
+ /* (Can skip check if previous span's down pointer is same as current one) */
+ if(span->down && prev_span->down != span->down)
+ if(!H5S__hyper_cmp_spans(span->down, prev_span->down))
+ HGOTO_DONE(FALSE)
- /* Obtain values for stride and block */
- next_stride = span->low - curr_low;
- next_block = (span->high - span->low) + 1;
+ /* Obtain values for stride and block */
+ curr_stride = span->low - prev_low;
+ curr_block = (span->high - span->low) + 1;
- /* Compare stride and block in this span, to compare stride,
- * three spans are needed. Account for the first two spans.
- */
- if(next_block != curr_block)
- HGOTO_DONE(FALSE)
- if(outcount > 1 && curr_stride != next_stride)
+ /* Compare stride and block for this span. To compare stride,
+ * three spans are needed. Account for the first two spans.
+ */
+ if(curr_block != block)
+ HGOTO_DONE(FALSE)
+ if(spancount > 1) {
+ if(stride != curr_stride)
HGOTO_DONE(FALSE)
-
- /* Keep the isolated stride to be 1 */
- curr_stride = next_stride;
} /* end if */
+ else
+ stride = curr_stride;
+ } /* end if */
- /* Keep current starting point */
- curr_low = span->low;
+ /* Keep current starting point */
+ prev_low = span->low;
- /* Advance to next span */
- prev_span = span;
- span = span->next;
- outcount++;
- } /* end while */
+ /* Advance to next span */
+ prev_span = span;
+ span = span->next;
+ spancount++;
+ } /* 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 */
+ /* Save the span information. */
+ span_slab_info[0].start = start;
+ span_slab_info[0].count = spancount;
+ span_slab_info[0].block = block;
+ span_slab_info[0].stride = stride;
done:
FUNC_LEAVE_NOAPI(ret_value)
@@ -6204,13 +8736,13 @@ done:
Rebuild optimized hyperslab information if possible.
(It can be recovered with regular selection)
USAGE
- hbool_t H5S__hyper_rebuild(space)
- const H5S_t *space; IN: Dataspace to check
+ void H5S__hyper_rebuild(space)
+ H5S_t *space; IN: Dataspace to check
RETURNS
- TRUE/FALSE for hyperslab selection rebuilt
+ None
DESCRIPTION
- Examine the span tree for a hyperslab selection and rebuild
- the start/stride/count/block information for the selection, if possible.
+ Examine the span tree for a hyperslab selection and rebuild a regular
+ start/stride/count/block hyperslab selection, if possible.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
To be able to recover the optimized information, the span tree must conform
@@ -6218,47 +8750,32 @@ done:
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-static hbool_t
+void
H5S__hyper_rebuild(H5S_t *space)
{
- H5S_hyper_dim_t top_span_slab_info[H5S_MAX_RANK];
- unsigned rank, curr_dim;
- hbool_t ret_value = TRUE; /* Return value */
+ H5S_hyper_dim_t rebuilt_slab_info[H5S_MAX_RANK];
- FUNC_ENTER_STATIC_NOERR
+ FUNC_ENTER_PACKAGE_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 */
+ /* Check whether the slab can be rebuilt */
+ /* (Only regular selection can be rebuilt. If yes, fill in correct values) */
+ if(FALSE == H5S__hyper_rebuild_helper(space->select.sel_info.hslab->span_lst, rebuilt_slab_info))
+ space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_IMPOSSIBLE;
else {
- H5S_hyper_dim_t *diminfo;
- H5S_hyper_dim_t *app_diminfo;
-
- diminfo = space->select.sel_info.hslab->diminfo.opt;
- app_diminfo = space->select.sel_info.hslab->diminfo.app;
-
- 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;
-
- }
+ /* Set the dimension info & bounds for the dataspace, from the rebuilt info */
+ H5MM_memcpy(space->select.sel_info.hslab->diminfo.app, rebuilt_slab_info, sizeof(rebuilt_slab_info));
+ H5MM_memcpy(space->select.sel_info.hslab->diminfo.opt, rebuilt_slab_info, sizeof(rebuilt_slab_info));
+ H5MM_memcpy(space->select.sel_info.hslab->diminfo.low_bounds, space->select.sel_info.hslab->span_lst->low_bounds, sizeof(hsize_t) * space->extent.rank);
+ H5MM_memcpy(space->select.sel_info.hslab->diminfo.high_bounds, space->select.sel_info.hslab->span_lst->high_bounds, sizeof(hsize_t) * space->extent.rank);
space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
} /* end else */
-done:
- FUNC_LEAVE_NOAPI(ret_value)
+ FUNC_LEAVE_NOAPI_VOID
} /* end H5S__hyper_rebuild() */
@@ -6320,7 +8837,386 @@ done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5S__hyper_generate_spans() */
-#ifndef NEW_HYPERSLAB_API
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__check_spans_overlap
+ PURPOSE
+ Check if two selections' bounds overlap.
+ USAGE
+ hbool_t H5S__check_spans_overlap(spans1, spans2)
+ const H5S_hyper_span_info_t *spans1; IN: Second span list
+ const H5S_hyper_span_info_t *spans2; IN: Second span list
+ RETURNS
+ TRUE for overlap, FALSE for no overlap
+ PROGRAMMER
+ Quincey Koziol - January 24, 2019
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5_ATTR_PURE hbool_t
+H5S__check_spans_overlap(const H5S_hyper_span_info_t *spans1,
+ const H5S_hyper_span_info_t *spans2)
+{
+ hbool_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(spans1);
+ HDassert(spans2);
+
+ /* Use low & high bounds to try to avoid spinning through the span lists */
+ if(H5S_RANGE_OVERLAP(spans1->low_bounds[0], spans1->high_bounds[0],
+ spans2->low_bounds[0], spans2->high_bounds[0])) {
+ H5S_hyper_span_t *span1, *span2; /* Hyperslab spans */
+
+ /* Walk over spans, comparing them for overlap */
+ span1 = spans1->head;
+ span2 = spans2->head;
+ while(span1 && span2) {
+ /* Check current two spans for overlap */
+ if(H5S_RANGE_OVERLAP(span1->low, span1->high, span2->low, span2->high)) {
+ /* Check for spans in lowest dimension already */
+ if(span1->down) {
+ /* Sanity check */
+ HDassert(span2->down);
+
+ /* Check lower dimensions for overlap */
+ if(H5S__check_spans_overlap(span1->down, span2->down))
+ HGOTO_DONE(TRUE);
+ } /* end if */
+ else
+ HGOTO_DONE(TRUE);
+ } /* end if */
+
+ /* Advance one of the spans */
+ if(span1->high <= span2->high) {
+ /* Advance span1, unless it would be off the list and span2 has more nodes */
+ if(NULL == span1->next && NULL != span2->next)
+ span2 = span2->next;
+ else
+ span1 = span1->next;
+ } /* end if */
+ else {
+ /* Advance span2, unless it would be off the list and span1 has more nodes */
+ if(NULL == span2->next && NULL != span1->next)
+ span1 = span1->next;
+ else
+ span2 = span2->next;
+ } /* end else */
+ } /* end while */
+
+ /* Make certain we've exhausted our comparisons */
+ HDassert((NULL == span1 && (NULL != span2 && NULL == span2->next)) ||
+ ((NULL != span1 && NULL == span1->next) && NULL == span2));
+ } /* end of */
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__check_spans_overlap() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S__fill_in_new_space
+ PURPOSE
+ Combine two span lists, one from an existing dataspace and the
+ other from input arguments, into a new selection depending on the
+ selection operator. The new selection is put into a resulting dataspace
+ which could be allocated inside the function.
+ USAGE
+ herr_t H5S__fill_in_new_space(space1, op, space2_span_lst, can_own_span2,
+ span2_owned, result)
+ H5S_t *space1; IN: Dataspace containing the first span list
+ H5S_seloper_t op; IN: Selection operation
+ H5S_hyper_span_info_t *space2_span_lst; IN: Second span list
+ hbool_t can_own_span2; IN: Indicates whether the 2nd span list could be
+ owned by the result. If not, the 2nd span list
+ has to be copied.
+ hbool_t *span2_owned; OUT: Indicates if the 2nd span list is actually owned
+ H5S_t **result; OUT: The dataspace containing the the new selection. It
+ could be same with the 1st dataspace.
+ RETURNS
+ Non-negative on success, negative on failure
+ PROGRAMMER
+ Chao Mei July 8, 2011
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S__fill_in_new_space(H5S_t *space1, H5S_seloper_t op,
+ H5S_hyper_span_info_t *space2_span_lst, hbool_t can_own_span2,
+ hbool_t *span2_owned, hbool_t *updated_spans, H5S_t **result)
+{
+ H5S_hyper_span_info_t *a_not_b = NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */
+ H5S_hyper_span_info_t *a_and_b = NULL; /* Span tree for hyperslab spans in both old and new span trees */
+ H5S_hyper_span_info_t *b_not_a = NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */
+ hbool_t overlapped = FALSE; /* Whether selections overlap */
+ hbool_t is_result_new = FALSE;
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ HDassert(space1);
+ HDassert(space2_span_lst);
+ HDassert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA);
+ /* The result is either a to-be-created space or an empty one */
+ HDassert(*result == NULL || *result == space1);
+ HDassert(space1->select.sel_info.hslab->span_lst);
+ HDassert(span2_owned);
+
+ /* Reset flags to return */
+ *span2_owned = FALSE;
+ *updated_spans = FALSE;
+
+ /* The result shares the same info from space1 */
+ if(*result == NULL) {
+ if(NULL == ((*result) = H5S_copy(space1, TRUE, TRUE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace")
+ space1->select.sel_info.hslab->span_lst->count--;
+ (*result)->select.sel_info.hslab->span_lst = NULL;
+ is_result_new = TRUE;
+ } /* end if */
+
+ /* Check both spaces to see if they overlap */
+ overlapped = H5S__check_spans_overlap(space1->select.sel_info.hslab->span_lst, space2_span_lst);
+
+ if(!overlapped) {
+ switch(op) {
+ case H5S_SELECT_OR:
+ case H5S_SELECT_XOR:
+ /* Add the new disjoint spans to the space */
+ /* Copy of space1's spans to *result, and another copy of space2's spans */
+ if(is_result_new)
+ (*result)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(space1->select.sel_info.hslab->span_lst, space1->extent.rank);
+ if(!can_own_span2) {
+ b_not_a = H5S__hyper_copy_span(space2_span_lst, space1->extent.rank);
+ if(H5S__hyper_add_disjoint_spans(*result, b_not_a) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't append hyperslabs")
+
+ /* The new_spans are now owned by 'space', so they should not be released */
+ b_not_a = NULL;
+ } /* end if */
+ else {
+ if(H5S__hyper_add_disjoint_spans(*result, space2_span_lst) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't append hyperslabs")
+ *span2_owned = TRUE;
+ } /* end else */
+
+ /* Indicate that the spans changed */
+ *updated_spans = TRUE;
+ break;
+
+ case H5S_SELECT_AND:
+ /* Convert *result to "none" selection */
+ if(H5S_select_none(*result) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection")
+ HGOTO_DONE(SUCCEED);
+
+ case H5S_SELECT_NOTB:
+ /* Copy space1's spans to *result */
+ if(is_result_new)
+ (*result)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(space1->select.sel_info.hslab->span_lst, space1->extent.rank);
+
+ /* Indicate that the spans changed */
+ *updated_spans = TRUE;
+ break;
+
+ case H5S_SELECT_NOTA:
+ if(!is_result_new) {
+ HDassert(space1 == *result);
+
+ /* Free the current selection */
+ H5S__hyper_free_span_info(space1->select.sel_info.hslab->span_lst);
+ space1->select.sel_info.hslab->span_lst = NULL;
+ } /* end if */
+
+ /* Copy space2's spans to *result */
+ if(!can_own_span2)
+ (*result)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(space2_span_lst, space1->extent.rank);
+ else {
+ (*result)->select.sel_info.hslab->span_lst = space2_span_lst;
+ *span2_owned = TRUE;
+ } /* end else */
+
+ /* Reset the number of items in selection */
+ (*result)->select.num_elem = H5S__hyper_spans_nelem(space2_span_lst);
+
+ /* Indicate that the spans changed */
+ *updated_spans = TRUE;
+ 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 */
+ } /* end if */
+ else {
+ unsigned selector = 0; /* Select which clipping spans to generate */
+
+ /* Generate mask for clip operation depending on the op */
+ switch(op) {
+ case H5S_SELECT_OR: /* a + b_not_a */
+ selector = H5S_HYPER_COMPUTE_B_NOT_A;
+ break;
+
+ case H5S_SELECT_XOR: /* a_not_b + b_not_a */
+ selector = H5S_HYPER_COMPUTE_A_NOT_B | H5S_HYPER_COMPUTE_B_NOT_A;
+ break;
+
+ case H5S_SELECT_AND: /* a_and_b */
+ selector = H5S_HYPER_COMPUTE_A_AND_B;
+ break;
+
+ case H5S_SELECT_NOTB: /* a_not_b */
+ selector = H5S_HYPER_COMPUTE_A_NOT_B;
+ break;
+
+ case H5S_SELECT_NOTA: /* b_not_a */
+ selector = H5S_HYPER_COMPUTE_B_NOT_A;
+ 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 */
+
+ /* Generate lists of spans which overlap and don't overlap */
+ if(H5S__hyper_clip_spans(space1->select.sel_info.hslab->span_lst,
+ space2_span_lst, selector, space1->extent.rank,
+ &a_not_b, &a_and_b, &b_not_a) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
+ switch(op) {
+ case H5S_SELECT_OR:
+ if(is_result_new)
+ (*result)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(space1->select.sel_info.hslab->span_lst, space1->extent.rank);
+ break;
+
+ case H5S_SELECT_AND:
+ case H5S_SELECT_XOR:
+ case H5S_SELECT_NOTB:
+ case H5S_SELECT_NOTA:
+ if(!is_result_new) {
+ HDassert(space1 == *result);
+
+ /* Free the current selection */
+ H5S__hyper_free_span_info(space1->select.sel_info.hslab->span_lst);
+ space1->select.sel_info.hslab->span_lst = NULL;
+ } /* end if */
+
+ /* Reset the number of items in selection */
+ /* (Will be set below) */
+ (*result)->select.num_elem = 0;
+ break;
+
+ case H5S_SELECT_NOOP:
+ case H5S_SELECT_SET:
+ case H5S_SELECT_APPEND:
+ case H5S_SELECT_PREPEND:
+ case H5S_SELECT_INVALID:
+ default:
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ } /* end switch */
+
+ /* Check if there are any non-overlapped selections */
+ if(a_not_b) {
+ /* Other than OR, the span_lst is set to NULL. And in OR,
+ * a_not_b is not needed
+ */
+ HDassert(NULL == (*result)->select.sel_info.hslab->span_lst);
+
+ /* The results dataspace takes ownership of the spans */
+ /* (Since it must be NULL) */
+ (*result)->select.sel_info.hslab->span_lst = a_not_b;
+
+ /* Update the number of elements in current selection */
+ (*result)->select.num_elem = H5S__hyper_spans_nelem(a_not_b);
+
+ /* Indicate that the spans were updated */
+ *updated_spans = TRUE;
+
+ /* Indicate that the a_not_b spans are owned */
+ a_not_b = NULL;
+ } /* end if */
+
+ if(a_and_b) {
+ /**
+ * 1. Other than OR, the span_lst is set to NULL. And in OR,
+ * a_and_b is not needed
+ * 2. a_not_b will never be computed together with a_and_b
+ * because merging these two equals to a.
+ */
+ HDassert(NULL == (*result)->select.sel_info.hslab->span_lst);
+
+ /* The results dataspace takes ownership of the spans */
+ /* (Since it must be NULL) */
+ (*result)->select.sel_info.hslab->span_lst = a_and_b;
+
+ /* Update the number of elements in current selection */
+ (*result)->select.num_elem = H5S__hyper_spans_nelem(a_and_b);
+
+ /* Indicate that the spans were updated */
+ *updated_spans = TRUE;
+
+ /* Indicate that the a_and_b spans are owned */
+ a_and_b = NULL;
+ } /* end if */
+
+ if(b_not_a) {
+ /* Merge the b_not_a spans into the result dataspace */
+ if(H5S__hyper_merge_spans(*result, b_not_a) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+
+ /* Update the number of elements in current selection */
+ (*result)->select.num_elem += H5S__hyper_spans_nelem(b_not_a);
+
+ /* Indicate that the spans were updated */
+ *updated_spans = TRUE;
+ } /* end if */
+ } /* end else for the case the new span overlaps with the old (i.e. space) */
+
+ /* Check if the spans weren't updated, and reset selection if so */
+ if(!*updated_spans) {
+ /* If updated_spans remains FALSE as in this branch, it means the
+ * result has been cleared in XOR / AND / NOTB / NOTA cases, and the
+ * result is a copy of the dataspace in the OR case.
+ *
+ * If two dataspaces have generated any of the three clipped
+ * span trees (i.e. a_not_b, a_and_b, and b_not_a), the
+ * updated_spans must be TRUE.
+ */
+ if(H5S_SELECT_OR != op) {
+ /* Convert *result to "none" selection */
+ if(H5S_select_none(*result) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection")
+ } /* end else */
+ } /* end if */
+
+done:
+ /* Free resources */
+ if(a_not_b)
+ H5S__hyper_free_span_info(a_not_b);
+ if(a_and_b)
+ H5S__hyper_free_span_info(a_and_b);
+ if(b_not_a)
+ H5S__hyper_free_span_info(b_not_a);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__fill_in_new_space() */
+
/*-------------------------------------------------------------------------
* Function: H5S__generate_hyperlab
@@ -6339,9 +9235,6 @@ 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_STATIC
@@ -6360,9 +9253,12 @@ H5S__generate_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[],
/* 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")
+ /* Free current selection */
+ if(NULL != space->select.sel_info.hslab->span_lst)
+ H5S__hyper_free_span_info(space->select.sel_info.hslab->span_lst);
+
+ /* Set the hyperslab selection to the new span tree */
+ space->select.sel_info.hslab->span_lst = new_spans;
/* Set the number of elements in current selection */
space->select.num_elem = H5S__hyper_spans_nelem(new_spans);
@@ -6371,194 +9267,375 @@ H5S__generate_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[],
new_spans = NULL;
} /* end if */
else {
+ hbool_t new_spans_owned = FALSE;
hbool_t updated_spans = FALSE;
- /* 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")
+ /* Generate new spans for space */
+ if(H5S__fill_in_new_space(space, op, new_spans, TRUE, &new_spans_owned, &updated_spans, &space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't generate the specified hyperslab")
- switch(op) {
- case H5S_SELECT_OR:
- /* Add any new spans from b_not_a to current selection */
- if(b_not_a!=NULL) {
- if(H5S__hyper_merge_spans(space,b_not_a,FALSE)<0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs")
+ /* Check if the spans were updated by H5S__fill_in_new_space */
+ if(updated_spans) {
+ H5S_hyper_dim_t new_hyper_diminfo[H5S_MAX_RANK];
+ unsigned u; /* Local index variable */
- /* Update the number of elements in current selection */
- space->select.num_elem += H5S__hyper_spans_nelem(b_not_a);
+ /* Sanity check */
+ HDassert(space->select.sel_info.hslab->span_lst->head);
+
+ /* Build diminfo struct */
+ for(u = 0; u <space->extent.rank; u++) {
+ new_hyper_diminfo[u].start = start[u];
+ new_hyper_diminfo[u].stride = stride[u];
+ new_hyper_diminfo[u].count = count[u];
+ new_hyper_diminfo[u].block = block[u];
+ } /* end for */
- /* Indicate that the spans were updated */
- updated_spans = TRUE;
- } /* end if */
- break;
+ /* Update space's dim info */
+ if(H5S__hyper_update_diminfo(space, op, new_hyper_diminfo) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't update hyperslab info")
+ } /* end if */
- 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;
+ /* Indicate that the new_spans are owned, there's no need to free */
+ if(new_spans_owned)
+ new_spans = NULL;
+ } /* end else */
- /* Reset the number of items in selection */
- space->select.num_elem=0;
+done:
+ if(new_spans)
+ H5S__hyper_free_span_info(new_spans);
- /* 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")
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__generate_hyperslab() */
- /* Update the number of elements in current selection */
- space->select.num_elem = H5S__hyper_spans_nelem(a_and_b);
+
+/*-------------------------------------------------------------------------
+ * Function: H5S__set_regular_hyperslab
+ *
+ * Purpose: Set a regular hyperslab
+ *
+ * Return: Non-negative on success/Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Thursday, October 2, 2014
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5S__set_regular_hyperslab(H5S_t *space, const hsize_t start[],
+ const hsize_t *app_stride, const hsize_t app_count[], const hsize_t *app_block,
+ const hsize_t *opt_stride, const hsize_t opt_count[], const hsize_t *opt_block)
+{
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
- /* Indicate that the a_and_b spans are owned */
- a_and_b=NULL;
+ FUNC_ENTER_STATIC
- /* Indicate that the spans were updated */
- updated_spans = TRUE;
- } /* end if */
- break;
+ /* Check args */
+ HDassert(space);
+ HDassert(start);
+ HDassert(app_stride);
+ HDassert(app_count);
+ HDassert(app_block);
+ HDassert(opt_stride);
+ HDassert(opt_count);
+ HDassert(opt_block);
+
+ /* If we are setting a new selection, remove current selection first */
+ if(H5S_SELECT_RELEASE(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
- 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;
+ /* Allocate space for the hyperslab selection information */
+ if(NULL == (space->select.sel_info.hslab = H5FL_MALLOC(H5S_hyper_sel_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info")
- /* Reset the number of items in selection */
- space->select.num_elem=0;
+ /* Set the diminfo */
+ space->select.num_elem = 1;
+ space->select.sel_info.hslab->unlim_dim = -1;
+ for(u = 0; u < space->extent.rank; u++) {
+ /* Set application and optimized hyperslab info */
+ space->select.sel_info.hslab->diminfo.app[u].start = start[u];
+ space->select.sel_info.hslab->diminfo.app[u].stride = app_stride[u];
+ space->select.sel_info.hslab->diminfo.app[u].count = app_count[u];
+ space->select.sel_info.hslab->diminfo.app[u].block = app_block[u];
+
+ space->select.sel_info.hslab->diminfo.opt[u].start = start[u];
+ space->select.sel_info.hslab->diminfo.opt[u].stride = opt_stride[u];
+ space->select.sel_info.hslab->diminfo.opt[u].count = opt_count[u];
+ space->select.sel_info.hslab->diminfo.opt[u].block = opt_block[u];
+
+ /* Update # of elements selected */
+ space->select.num_elem *= (opt_count[u] * opt_block[u]);
+
+ /* Set low bound of bounding box for the hyperslab selection */
+ space->select.sel_info.hslab->diminfo.low_bounds[u] = start[u];
+
+ /* Check for unlimited dimension & set high bound */
+ if((app_count[u] == H5S_UNLIMITED) || (app_block[u] == H5S_UNLIMITED)) {
+ space->select.sel_info.hslab->unlim_dim = (int)u;
+ space->select.sel_info.hslab->diminfo.high_bounds[u] = H5S_UNLIMITED;
+ } /* end if */
+ else
+ space->select.sel_info.hslab->diminfo.high_bounds[u] = start[u] + opt_stride[u] * (opt_count[u] - 1) + (opt_block[u] - 1);
+ } /* end for */
- /* 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")
+ /* Handle unlimited selections */
+ if(space->select.sel_info.hslab->unlim_dim >= 0) {
+ /* Calculate num_elem_non_unlim */
+ space->select.sel_info.hslab->num_elem_non_unlim = (hsize_t)1;
+ for(u = 0; u < space->extent.rank; u++)
+ if((int)u != space->select.sel_info.hslab->unlim_dim)
+ space->select.sel_info.hslab->num_elem_non_unlim *= (opt_count[u] * opt_block[u]);
- /* Update the number of elements in current selection */
- space->select.num_elem = H5S__hyper_spans_nelem(a_not_b);
+ /* Update num_elem */
+ space->select.num_elem = H5S_UNLIMITED;
+ } /* end if */
- /* 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")
+ /* Indicate that the dimension information is valid */
+ space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
- /* Update the number of elements in current selection */
- space->select.num_elem += H5S__hyper_spans_nelem(b_not_a);
+ /* Indicate that there's no slab information */
+ space->select.sel_info.hslab->span_lst = NULL;
- /* Indicate that the spans were updated */
- updated_spans = TRUE;
- } /* end if */
- break;
+ /* Set selection type */
+ space->select.type = H5S_sel_hyper;
- 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;
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__set_regular_hyperslab() */
- /* 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")
+/*-------------------------------------------------------------------------
+ * Function: H5S__hyper_regular_and_single_block
+ *
+ * Purpose: Optimized routine to perform "AND" operation of a single
+ * block against a regular hyperslab selection.
+ *
+ * Note: This algorithm is invoked when constructing the chunk map
+ * and a regular hyperslab is selected in the file's dataspace.
+ *
+ * Return: Non-negative on success / Negative on failure
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, February 9, 2019
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S__hyper_regular_and_single_block(H5S_t *space, const hsize_t start[],
+ const hsize_t block[])
+{
+ hsize_t select_end, block_end; /* End of block & selection */
+ hbool_t single_block; /* Whether the selection is a single block */
+ hbool_t overlap; /* Whether block & selection overlap */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
- /* Update the number of elements in current selection */
- space->select.num_elem = H5S__hyper_spans_nelem(a_not_b);
+ FUNC_ENTER_NOAPI(FAIL)
- /* Indicate that the a_not_b are owned */
- a_not_b=NULL;
+ /* Check args */
+ HDassert(space);
+ HDassert(start);
+ HDassert(block);
- /* Indicate that the spans were updated */
- updated_spans = TRUE;
- } /* end if */
+ /* Check for single block selection in dataspace */
+ single_block = TRUE;
+ for(u = 0; u < space->extent.rank; u++)
+ if(1 != space->select.sel_info.hslab->diminfo.opt[u].count) {
+ single_block = FALSE;
+ break;
+ } /* end if */
+
+ /* Perform different optimizations, based on type of regular selection */
+ if(single_block) {
+ hsize_t new_start[H5S_MAX_RANK]; /* New starting coordinate */
+ hsize_t new_block[H5S_MAX_RANK]; /* New block size */
+
+ /* Check for overlap and compute new start offset & block sizes */
+ overlap = TRUE;
+ for(u = 0; u < space->extent.rank; u++) {
+ /* Compute the end of the selection & block in this dimension */
+ select_end = space->select.sel_info.hslab->diminfo.high_bounds[u];
+ block_end = (start[u] + block[u]) - 1;
+
+ /* Check for overlap */
+ if(!H5S_RANGE_OVERLAP(space->select.sel_info.hslab->diminfo.opt[u].start, select_end, start[u], block_end)) {
+ overlap = FALSE;
break;
+ } /* end if */
- 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;
+ /* Set new start & block size in this dimension */
+ new_start[u] = MAX(space->select.sel_info.hslab->diminfo.opt[u].start, start[u]);
+ new_block[u] = (MIN(select_end, block_end) - new_start[u]) + 1;
+ } /* end for */
- /* Reset the number of items in selection */
- space->select.num_elem=0;
+ /* Check for overlap of selection & block */
+ if(overlap) {
+ /* Set selection to regular hyperslab */
+ if(H5S__set_regular_hyperslab(space, new_start, H5S_hyper_ones_g, H5S_hyper_ones_g, new_block,
+ H5S_hyper_ones_g, H5S_hyper_ones_g, new_block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular hyperslab selection")
+ } /* end if */
+ else
+ /* Selection & block don't overlap, set to "none" selection */
+ if(H5S_select_none(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection")
+ } /* end if */
+ else {
+ hsize_t new_start[H5S_MAX_RANK]; /* New start for hyperslab selection */
+ hsize_t new_count[H5S_MAX_RANK]; /* New count for hyperslab selection */
+ hsize_t stride[H5S_MAX_RANK]; /* Stride for hyperslab selection */
+ hsize_t new_block[H5S_MAX_RANK]; /* New block for hyperslab selection */
+ hbool_t partial_first_span; /* Whether first span in intersection is partial */
+ hbool_t partial_last_span; /* Whether last span in intersection is partial */
+
+ /* Iterate over selection, checking for overlap and computing first / last
+ * span that intersects with the block.
+ */
+ overlap = TRUE;
+ partial_first_span = FALSE;
+ partial_last_span = FALSE;
+ for(u = 0; u < space->extent.rank; u++) {
+ hsize_t first_span_start, first_span_end; /* Start / end of first span */
+ hsize_t last_span_start, last_span_end; /* Start / end of last span */
+ hsize_t nstride; /* Number of strides into the selection */
+
+ /* Compute the end of the selection & block in this dimension */
+ select_end = space->select.sel_info.hslab->diminfo.high_bounds[u];
+ block_end = (start[u] + block[u]) - 1;
+
+ /* Check for overlap */
+ if(!H5S_RANGE_OVERLAP(space->select.sel_info.hslab->diminfo.opt[u].start, select_end, start[u], block_end)) {
+ overlap = FALSE;
+ break;
+ } /* end if */
- /* 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")
+ /* Find first span that is before or overlaps with start of block */
+ if(space->select.sel_info.hslab->diminfo.opt[u].start >= start[u]) {
+ /* Calculate start & end of first span */
+ first_span_start = space->select.sel_info.hslab->diminfo.opt[u].start;
+ first_span_end = (first_span_start +
+ space->select.sel_info.hslab->diminfo.opt[u].block) - 1;
- /* Update the number of elements in current selection */
- space->select.num_elem = H5S__hyper_spans_nelem(b_not_a);
+ /* Check if first span overlaps _end_ of block */
+ if(block_end >= first_span_start && block_end <= first_span_end)
+ partial_first_span = TRUE;
+ } /* end if */
+ else {
+ hsize_t adj_start; /* Start coord, adjusted for hyperslab selection parameters */
+
+ /* Adjust start coord for selection's 'start' offset */
+ adj_start = start[u] - space->select.sel_info.hslab->diminfo.opt[u].start;
+
+ /* Compute # of strides into the selection */
+ if(space->select.sel_info.hslab->diminfo.opt[u].count > 1)
+ nstride = adj_start / space->select.sel_info.hslab->diminfo.opt[u].stride;
+ else
+ nstride = 0;
- /* Indicate that the b_not_a are owned */
- b_not_a=NULL;
+ /* Calculate start & end of first span */
+ first_span_start = space->select.sel_info.hslab->diminfo.opt[u].start +
+ (nstride * space->select.sel_info.hslab->diminfo.opt[u].stride);
+ first_span_end = (first_span_start +
+ space->select.sel_info.hslab->diminfo.opt[u].block) - 1;
- /* Indicate that the spans were updated */
- updated_spans = TRUE;
+ /* Check if first span overlaps start of block */
+ if(first_span_start < start[u] && first_span_end >= start[u])
+ partial_first_span = TRUE;
+
+ /* Advance first span to start higher than block's start,
+ * if it's not partial.
+ */
+ if(first_span_end < start[u]) {
+ first_span_start += space->select.sel_info.hslab->diminfo.opt[u].stride;
+ first_span_end += space->select.sel_info.hslab->diminfo.opt[u].stride;
} /* end if */
- break;
+ } /* end else */
- 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 */
+ /* Find last span that is before or overlaps with end of block */
+ if(select_end < block_end) {
+ /* Calculate start & end of last span */
+ last_span_start = (select_end -
+ space->select.sel_info.hslab->diminfo.opt[u].block) + 1;
+ last_span_end = select_end;
- /* 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 */
+ /* Check if last span overlaps _start_ of block */
+ if(start[u] >= last_span_start && start[u] <= last_span_end)
+ partial_last_span = TRUE;
+ } /* end if */
+ else {
+ hsize_t adj_end; /* End coord, adjusted for hyperslab selection parameters */
+
+ /* Adjust end coord for selection's 'start' offset */
+ adj_end = block_end - space->select.sel_info.hslab->diminfo.opt[u].start;
+
+ /* Compute # of strides into the selection */
+ if(space->select.sel_info.hslab->diminfo.opt[u].count > 1)
+ nstride = adj_end / space->select.sel_info.hslab->diminfo.opt[u].stride;
+ else
+ nstride = 0;
+
+ /* Calculate start & end of last span */
+ last_span_start = space->select.sel_info.hslab->diminfo.opt[u].start +
+ (nstride * space->select.sel_info.hslab->diminfo.opt[u].stride);
+ last_span_end = (last_span_start +
+ space->select.sel_info.hslab->diminfo.opt[u].block) - 1;
+
+ /* Check if last span overlaps end of block */
+ if(block_end >= last_span_start && block_end <= last_span_end)
+ partial_last_span = TRUE;
+ } /* end else */
+
+ /* Check if no spans are inside block */
+ /* (Can happen when block falls in "gap" between spans) */
+ if(last_span_end < start[u]) {
+ overlap = FALSE;
+ break;
+ } /* end if */
/* Sanity check */
- HDassert(space->select.num_elem == 0);
+ HDassert(first_span_start <= last_span_start);
- /* 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")
+ /* Compute new start / count / block values */
+ new_start[u] = first_span_start;
+ if(last_span_start != first_span_start)
+ new_count[u] = ((last_span_start - first_span_start) /
+ space->select.sel_info.hslab->diminfo.opt[u].stride) + 1;
+ else
+ new_count[u] = 1;
+ new_block[u] = space->select.sel_info.hslab->diminfo.opt[u].block;
- /* Set the reference count */
- spans->count=1;
+ /* Keep same stride */
+ stride[u] = space->select.sel_info.hslab->diminfo.opt[u].stride;
+ } /* end for */
- /* Reset the scratch pad space */
- spans->scratch=0;
+ /* Check for overlap of selection & block */
+ if(overlap) {
+ /* Set selection to regular hyperslab */
+ if(H5S__set_regular_hyperslab(space, new_start, stride, new_count, new_block,
+ stride, new_count, new_block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular hyperslab selection")
- /* Set to empty tree */
- spans->head=NULL;
+ /* If there's a partial first or last span, have to 'AND' against selection */
+ if(partial_first_span || partial_last_span) {
+ /* Generate span tree for regular selection */
+ if(H5S__hyper_generate_spans(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
- /* Set pointer to empty span tree */
- space->select.sel_info.hslab->span_lst=spans;
+ /* 'AND' against block */
+ if(H5S__generate_hyperslab(space, H5S_SELECT_AND, start, H5S_hyper_ones_g, H5S_hyper_ones_g, block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs")
+ } /* end if */
} /* end if */
else {
- /* Check if we updated the spans */
- if(updated_spans) {
- /* Attempt to rebuild "optimized" start/stride/count/block information.
- * from resulting hyperslab span tree
- */
- H5S__hyper_rebuild(space);
- } /* end if */
+ /* Selection & block don't overlap, set to "none" selection */
+ if(H5S_select_none(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection")
} /* end else */
} /* end else */
done:
- /* Free resources */
- if(a_not_b)
- if(H5S__hyper_free_span_info(a_not_b) < 0)
- HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans")
- if(a_and_b)
- if(H5S__hyper_free_span_info(a_and_b) < 0)
- HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans")
- if(b_not_a)
- if(H5S__hyper_free_span_info(b_not_a) < 0)
- HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans")
- if(new_spans)
- if(H5S__hyper_free_span_info(new_spans) < 0)
- HDONE_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans")
-
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5S__generate_hyperslab() */
+} /* end H5S__hyper_regular_and_single_block() */
/*-------------------------------------------------------------------------
@@ -6798,56 +9875,13 @@ H5S_select_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[],
} /* 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->diminfo.app[u].start = start[u];
- space->select.sel_info.hslab->diminfo.app[u].stride = stride[u];
- space->select.sel_info.hslab->diminfo.app[u].count = count[u];
- space->select.sel_info.hslab->diminfo.app[u].block = block[u];
-
- space->select.sel_info.hslab->diminfo.opt[u].start = start[u];
- space->select.sel_info.hslab->diminfo.opt[u].stride = opt_stride[u];
- space->select.sel_info.hslab->diminfo.opt[u].count = opt_count[u];
- space->select.sel_info.hslab->diminfo.opt[u].block = opt_block[u];
-
- space->select.num_elem *= (opt_count[u] * opt_block[u]);
- } /* end for */
-
- /* 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 = H5S_DIMINFO_VALID_YES;
-
- /* 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 */
-
- /* Set selection type */
- space->select.type = H5S_sel_hyper;
+ /* Set selection to regular hyperslab */
+ if(H5S__set_regular_hyperslab(space, start, stride, count, block, opt_stride, opt_count, opt_block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular hyperslab selection")
} /* end if */
else if(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA) {
+ hbool_t single_block; /* Whether the selection is a single block */
+
/* Sanity check */
HDassert(H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS);
@@ -6884,21 +9918,35 @@ H5S_select_hyperslab(H5S_t *space, H5S_seloper_t op, const hsize_t start[],
} /* 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")
+ /* Check for a single block selected */
+ single_block = TRUE;
+ for(u = 0; u < space->extent.rank; u++)
+ if(1 != opt_count[u]) {
+ single_block = FALSE;
+ break;
+ } /* end if */
- /* Indicate that the regular dimensions are no longer valid */
- space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
+ /* Check for single block "AND" operation on a regular hyperslab, which
+ * is used for constructing chunk maps and can be optimized for.
+ */
+ if(H5S_SELECT_AND == op && single_block &&
+ space->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
+ if(H5S__hyper_regular_and_single_block(space, start, opt_block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTOPERATE, FAIL, "can't 'AND' single block against regular hyperslab")
+ } /* end if */
+ else {
+ /* Check if there's no hyperslab span information currently */
+ if(NULL == space->select.sel_info.hslab->span_lst)
+ if(H5S__hyper_generate_spans(space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
- /* Set selection type */
- /* (Could be overridden by resetting selection to 'none', below) */
- space->select.type = H5S_sel_hyper;
+ /* Set selection type */
+ space->select.type = H5S_sel_hyper;
- /* 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")
+ /* Add in the new hyperslab information */
+ if(H5S__generate_hyperslab(space, op, start, opt_stride, opt_count, opt_block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs")
+ } /* end else */
} /* end if */
else
HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
@@ -6970,690 +10018,265 @@ H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[],
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
- */
- H5S__hyper_rebuild(result);
- } /* 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(NULL == (new_spans = H5S__hyper_make_spans(space->extent.rank, start, stride, count, block)))
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information")
-
- /* 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:
- *
- *-------------------------------------------------------------------------
- */
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_combine_hyperslab
+ PURPOSE
+ Specify a hyperslab to combine with the current hyperslab selection, and
+ store the result in the new hyperslab selection.
+ USAGE
+ herr_t H5S_combine_hyperslab(new_space, old_space, op, start, stride, count, block)
+ H5S_t *old_space; IN: The old space the selection is performed on
+ H5S_seloper_t op; IN: Operation to perform on current selection
+ const hsize_t start[]; IN: Offset of start of hyperslab
+ const hsize_t *stride; IN: Hyperslab stride
+ const hsize_t count[]; IN: Number of blocks included in hyperslab
+ const hsize_t *block; IN: Size of block in hyperslab
+ H5S_t **new_space; OUT: The new dataspace to store the selection result
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Combines a hyperslab selection with the current selection for a dataspace.
+ If STRIDE or BLOCK is NULL, they are assumed to be set to all '1'.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ In some cases, copying the whole span tree from old_space to new_space
+ can be avoided. Deal with such cases directly, otherwise this function
+ is equivalent to:
+ 1. Copy the whole span tree from old_space into new_space
+ 2. Call H5S_select_hyperslab with the new_space.
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
herr_t
-H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op,
- const hsize_t start[],
- const hsize_t *stride,
- const hsize_t count[],
- const hsize_t *block)
+H5S_combine_hyperslab(H5S_t *old_space, H5S_seloper_t op, const hsize_t start[],
+ const hsize_t *stride, const hsize_t count[], const hsize_t *block,
+ H5S_t **new_space)
{
- hsize_t int_stride[H5S_MAX_RANK]; /* Internal storage for stride information */
- hsize_t int_count[H5S_MAX_RANK]; /* Internal storage for count information */
- hsize_t int_block[H5S_MAX_RANK]; /* Internal storage for block information */
- const hsize_t *opt_stride; /* Optimized stride information */
- const hsize_t *opt_count; /* Optimized count information */
- const hsize_t *opt_block; /* Optimized block information */
- unsigned u; /* Counters */
- int unlim_dim = -1; /* Unlimited dimension in selection, of -1 if none */
- herr_t ret_value=SUCCEED; /* Return value */
+ unsigned u; /* Local index variable */
+ herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_NOAPI(FAIL)
/* Check args */
- HDassert(space);
+ HDassert(old_space);
HDassert(start);
HDassert(count);
- HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
+ HDassert(op >= H5S_SELECT_SET && op <= H5S_SELECT_NOTA);
+ HDassert(new_space);
+ HDassert(*new_space == NULL);
/* Point to the correct stride values */
- if(stride==NULL)
+ if(stride == NULL)
stride = H5S_hyper_ones_g;
/* Point to the correct block values */
- if(block==NULL)
+ if(block == NULL)
block = H5S_hyper_ones_g;
- /* 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 new selection. */
+ for(u = 0; u < old_space->extent.rank; u++) {
/* Check for overlapping hyperslab blocks in new selection. */
- if(count[u]>1 && stride[u]<block[u])
+ 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")
+ /* Copy the first dataspace without sharing the list of spans */
+ if(NULL == ((*new_space) = H5S_copy(old_space, TRUE, TRUE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace")
+ if(H5S_select_none((*new_space)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection")
HGOTO_DONE(SUCCEED);
case H5S_SELECT_OR: /* Binary "or" operation for hyperslabs */
case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */
case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */
+ /* Copy the first dataspace with sharing the list of spans */
+ if(NULL == ((*new_space) = H5S_copy(old_space, FALSE, TRUE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace")
HGOTO_DONE(SUCCEED); /* Selection stays same */
+ case H5S_SELECT_NOOP:
+ case H5S_SELECT_SET:
+ case H5S_SELECT_APPEND:
+ case H5S_SELECT_PREPEND:
+ case H5S_SELECT_INVALID:
default:
HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
} /* end switch */
} /* end if */
} /* end for */
- /* Optimize hyperslab parameters to merge contiguous blocks, etc. */
- if(stride == H5S_hyper_ones_g && block == H5S_hyper_ones_g) {
- /* Point to existing arrays */
- opt_stride = H5S_hyper_ones_g;
- opt_count = H5S_hyper_ones_g;
- opt_block = count;
- } /* end if */
- else {
- /* Point to local arrays */
- opt_stride = int_stride;
- opt_count = int_count;
- opt_block = int_block;
- for(u=0; u<space->extent.rank; u++) {
- /* contiguous hyperslabs have the block size equal to the stride */
- if((stride[u] == block[u]) && (count[u] != H5S_UNLIMITED)) {
- int_count[u]=1;
- int_stride[u]=1;
- if(block[u]==1)
- int_block[u]=count[u];
- else
- int_block[u]=block[u]*count[u];
- } /* end if */
- else {
- if(count[u]==1)
- int_stride[u]=1;
- else {
- HDassert((stride[u] > block[u]) || ((stride[u] == block[u])
- && (count[u] == H5S_UNLIMITED)));
- int_stride[u]=stride[u];
- } /* end else */
- int_count[u]=count[u];
- int_block[u]=block[u];
- } /* end else */
- } /* end for */
- } /* end else */
-
- /* Check for operating on unlimited selection */
- if((H5S_GET_SELECT_TYPE(space) == H5S_SEL_HYPERSLABS)
- && (space->select.sel_info.hslab->unlim_dim >= 0)
- && (op != H5S_SELECT_SET))
- {
- /* Check for invalid operation */
- if(unlim_dim >= 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "cannot modify unlimited selection with another unlimited selection")
- if(!((op == H5S_SELECT_AND) || (op == H5S_SELECT_NOTA)))
- HGOTO_ERROR(H5E_DATASPACE, H5E_UNSUPPORTED, FAIL, "unsupported operation on unlimited selection")
- HDassert(space->select.sel_info.hslab->diminfo_valid);
+ if(H5S_GET_SELECT_TYPE(old_space) == H5S_SEL_HYPERSLABS) {
+ hsize_t *old_low_bounds; /* Pointer to old space's low & high bounds */
+ hsize_t *old_high_bounds;
+ hsize_t new_low_bounds[H5S_MAX_RANK]; /* New space's low & high bounds */
+ hsize_t new_high_bounds[H5S_MAX_RANK];
+ hbool_t overlapped = FALSE;
+
+ /* Set up old space's low & high bounds */
+ if(old_space->select.sel_info.hslab->span_lst) {
+ old_low_bounds = old_space->select.sel_info.hslab->span_lst->low_bounds;
+ old_high_bounds = old_space->select.sel_info.hslab->span_lst->high_bounds;
+ } /* end if */
+ else {
+ old_low_bounds = old_space->select.sel_info.hslab->diminfo.low_bounds;
+ old_high_bounds = old_space->select.sel_info.hslab->diminfo.high_bounds;
+ } /* end else */
- /* 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")
+ /* Generate bounding box for hyperslab parameters */
+ for(u = 0; u < old_space->extent.rank; u++) {
+ new_low_bounds[u] = start[u];
+ new_high_bounds[u] = start[u] + stride[u] * (count[u] - 1) + (block[u] - 1);
+ } /* end for */
- /* 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 */
+ /* Check bound box of both spaces to see if they overlap */
+ if(H5S_RANGE_OVERLAP(old_low_bounds[0], old_high_bounds[0],
+ new_low_bounds[0], new_high_bounds[0]))
+ overlapped = TRUE;
+
+ /* Non-overlapping situations can be handled in special ways */
+ if(!overlapped) {
+ H5S_hyper_span_info_t *new_spans = NULL;
+ H5S_hyper_dim_t new_hyper_diminfo[H5S_MAX_RANK];
+
+ if(NULL == ((*new_space) = H5S_copy(old_space, TRUE, TRUE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy dataspace")
+ if(NULL != (*new_space)->select.sel_info.hslab->span_lst) {
+ old_space->select.sel_info.hslab->span_lst->count--;
+ (*new_space)->select.sel_info.hslab->span_lst = NULL;
+ } /* end if */
- /* Fixup operation for non-hyperslab selections */
- switch(H5S_GET_SELECT_TYPE(space)) {
- case H5S_SEL_NONE: /* No elements selected in dataspace */
+ /* Generate hyperslab info for new space */
switch(op) {
- case H5S_SELECT_SET: /* Select "set" operation */
- /* Change "none" selection to hyperslab selection */
- break;
+ case H5S_SELECT_OR:
+ case H5S_SELECT_XOR:
+ /* Add the new space to the space */
+ if(NULL == (new_spans = H5S__hyper_make_spans(old_space->extent.rank, start, stride, count, block)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information")
+ if(NULL != old_space->select.sel_info.hslab->span_lst)
+ (*new_space)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(old_space->select.sel_info.hslab->span_lst, old_space->extent.rank);
+ if(H5S__hyper_add_disjoint_spans(*new_space, new_spans) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't append hyperslabs")
+
+ /* Build diminfo struct */
+ for(u = 0; u < (*new_space)->extent.rank; u++) {
+ new_hyper_diminfo[u].start = start[u];
+ new_hyper_diminfo[u].stride = stride[u];
+ new_hyper_diminfo[u].count = count[u];
+ new_hyper_diminfo[u].block = block[u];
+ } /* end for */
- 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 */
+ /* Update space's dim info */
+ if(H5S__hyper_update_diminfo(*new_space, op, new_hyper_diminfo) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't update hyperslab info")
break;
- 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 */
+ case H5S_SELECT_AND:
+ if(H5S_select_none((*new_space)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert 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 */
+ case H5S_SELECT_NOTB:
+ if(NULL != old_space->select.sel_info.hslab->span_lst) {
+ if(NULL == ((*new_space)->select.sel_info.hslab->span_lst = H5S__hyper_copy_span(old_space->select.sel_info.hslab->span_lst, old_space->extent.rank)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "unable to copy dataspace")
+ } /* end if */
+ else {
+ if(H5S_select_none((*new_space)) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't convert selection")
+ } /* end else */
break;
- case H5S_SELECT_XOR: /* Binary "xor" operation for hyperslabs */
- case H5S_SELECT_NOTB: /* Binary "A not B" operation for hyperslabs */
- /* Convert current "all" selection to "real" hyperslab selection */
- /* Then allow operation to proceed */
- {
- hsize_t tmp_start[H5S_MAX_RANK]; /* Temporary start information */
- hsize_t tmp_stride[H5S_MAX_RANK]; /* Temporary stride information */
- hsize_t tmp_count[H5S_MAX_RANK]; /* Temporary count information */
- hsize_t tmp_block[H5S_MAX_RANK]; /* Temporary block information */
-
- /* Fill in temporary information for the dimensions */
- for(u=0; 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 */
+ case H5S_SELECT_NOTA:
+ if(H5S__set_regular_hyperslab(*new_space, start, stride, count, block, stride, count, block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't set regular selection")
break;
- case 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_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 */
- 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->diminfo.app[u].start = start[u];
- space->select.sel_info.hslab->diminfo.app[u].stride = stride[u];
- space->select.sel_info.hslab->diminfo.app[u].count = count[u];
- space->select.sel_info.hslab->diminfo.app[u].block = block[u];
-
- space->select.sel_info.hslab->diminfo.opt[u].start = start[u];
- space->select.sel_info.hslab->diminfo.opt[u].stride = opt_stride[u];
- space->select.sel_info.hslab->diminfo.opt[u].count = opt_count[u];
- space->select.sel_info.hslab->diminfo.opt[u].block = opt_block[u];
-
- space->select.num_elem*=(opt_count[u]*opt_block[u]);
- } /* end for */
-
- /* 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 = H5S_DIMINFO_VALID_YES;
- /* Indicate that there's no slab information */
- space->select.sel_info.hslab->span_lst = NULL;
+ HGOTO_DONE(SUCCEED);
+ } /* end if(!overlapped) */
+ } /* end if the selection of old space is H5S_SEL_HYPERSLABS */
- /* 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]);
+ /* Copy the first dataspace with sharing the list of spans */
+ if(NULL == ((*new_space) = H5S_copy(old_space, TRUE, TRUE)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy dataspace")
- /* 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 != H5S_hyper_ones_g));
- HDassert((tmp_block == 1) || (opt_block != H5S_hyper_ones_g));
- if(opt_count != H5S_hyper_ones_g) {
- HDassert(opt_count == int_count);
- int_count[unlim_dim] = tmp_count;
- } /* end if */
- if(opt_block != H5S_hyper_ones_g) {
- HDassert(opt_block == int_block);
- int_block[unlim_dim] = tmp_block;
- } /* end if */
- } /* end if */
-
- /* Check 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 = H5S_DIMINFO_VALID_NO;
-
- /* 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;
+ /* Note: a little overhead in calling the function as some conditions are checked again */
+ if(H5S_select_hyperslab(*new_space, op, start, stride, count, block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection")
done:
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5S_select_hyperslab() */
+} /* end H5S_combine_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[])
+/*-------------------------------------------------------------------------
+ * Function: H5S__fill_in_select
+ *
+ * Purpose: Combines two hyperslabs with an operation, putting the
+ * result into a third hyperslab selection
+ *
+ * Return: Non-negative on success/negative on failure
+ *
+ * Programmer: Chao Mei
+ * Tuesday, July 5, 2011
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S__fill_in_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2, H5S_t **result)
{
- 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);
+ hbool_t span2_owned;
+ hbool_t updated_spans;
+ herr_t ret_value = SUCCEED; /* Return value */
- /* Check args */
- if (NULL == (space = (H5S_t *)H5I_object_verify(space_id, H5I_DATASPACE)))
- HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
- if (H5S_SCALAR==H5S_GET_EXTENT_TYPE(space))
- HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_SCALAR space")
- if (H5S_NULL==H5S_GET_EXTENT_TYPE(space))
- HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "hyperslab doesn't support H5S_NULL space")
- if(start==NULL || count==NULL)
- HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified")
- if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID))
- HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
- if(stride!=NULL) {
- unsigned u; /* Local index variable */
+ FUNC_ENTER_STATIC
- /* 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 */
+ /* Sanity check */
+ HDassert(space1);
+ HDassert(space2);
+ HDassert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA);
+ HDassert(space1->extent.rank == space2->extent.rank);
+ /* The result is either a to-be-created space or an empty one */
+ HDassert(NULL == *result || *result == space1);
+ HDassert(space1->select.sel_info.hslab->span_lst);
+ HDassert(space2->select.sel_info.hslab->span_lst);
+
+ /* Note: the offset of space2 is not considered here for bounding box */
+ if(H5S__fill_in_new_space(space1, op, space2->select.sel_info.hslab->span_lst, FALSE, &span2_owned, &updated_spans, result) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSELECT, FAIL, "can't create the specified selection")
+
+ /* Update diminfo if space2's diminfo was valid, otherwise just mark it as
+ * invalid if the spans were updated */
+ HDassert(result);
+ if(updated_spans) {
+ if(space2->select.sel_info.hslab->diminfo_valid == H5S_DIMINFO_VALID_YES) {
+ if(H5S__hyper_update_diminfo(*result, op, space2->select.sel_info.hslab->diminfo.opt) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't update hyperslab info")
+ } /* end if */
+ else
+ (*result)->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
} /* end if */
- 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() */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__fill_in_select() */
/*--------------------------------------------------------------------------
@@ -7664,7 +10287,7 @@ done:
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 H5Scombine_hyperslab(dsid, op, start, stride, count, block)
hid_t dsid; IN: Dataspace ID of selection to use
H5S_seloper_t op; IN: Operation to perform on current selection
const hsize_t *start; IN: Offset of start of hyperslab
@@ -7704,12 +10327,8 @@ H5Scombine_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t start[],
if(!(op >= H5S_SELECT_SET && op <= H5S_SELECT_NOTA))
HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, H5I_INVALID_HID, "invalid selection operation")
- /* Copy the first dataspace */
- if (NULL == (new_space = H5S_copy (space, TRUE, TRUE)))
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, H5I_INVALID_HID, "unable to copy dataspace")
-
- /* Go modify the selection in the new dataspace */
- if (H5S_select_hyperslab(new_space, op, start, stride, count, block)<0)
+ /* Generate new space, with combination of selections */
+ if(H5S_combine_hyperslab(space, op, start, stride, count, block, &new_space) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, H5I_INVALID_HID, "unable to set hyperslab selection")
/* Atomize */
@@ -7740,7 +10359,6 @@ static H5S_t *
H5S__combine_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2)
{
H5S_t *new_space = NULL; /* New dataspace generated */
- hbool_t span2_owned=FALSE; /* Flag to indicate that span2 was used in H5S_operate_hyperslab() */
H5S_t *ret_value = NULL; /* Return value */
FUNC_ENTER_STATIC
@@ -7750,34 +10368,38 @@ H5S__combine_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2)
HDassert(space2);
HDassert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA);
- /* 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)
+ /* Check if space1 selections has span trees */
+ if(NULL == space1->select.sel_info.hslab->span_lst)
+ if(H5S__hyper_generate_spans(space1) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, NULL, "dataspace does not have span tree")
- /* Copy the first dataspace */
- if (NULL == (new_space = H5S_copy (space1, TRUE, TRUE)))
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to copy dataspace")
-
- /* 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")
+ if(NULL == space2->select.sel_info.hslab->span_lst) {
+ hsize_t tmp_start[H5S_MAX_RANK];
+ hsize_t tmp_stride[H5S_MAX_RANK];
+ hsize_t tmp_count[H5S_MAX_RANK];
+ hsize_t tmp_block[H5S_MAX_RANK];
+ unsigned u;
+
+ for(u = 0; u < space2->extent.rank; u++) {
+ tmp_start[u] = space2->select.sel_info.hslab->diminfo.opt[u].start;
+ tmp_stride[u] = space2->select.sel_info.hslab->diminfo.opt[u].stride;
+ tmp_count[u] = space2->select.sel_info.hslab->diminfo.opt[u].count;
+ tmp_block[u] = space2->select.sel_info.hslab->diminfo.opt[u].block;
+ } /* end for */
- /* Allocate space for the hyperslab selection information */
- if((new_space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)) == NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab info")
- new_space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
+ /* Combine hyperslab selection with regular selection directly */
+ if(H5S_combine_hyperslab(space1, op, tmp_start, tmp_stride, tmp_count, tmp_block, &new_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to set hyperslab selection")
+ } /* end if */
+ else{
+ /* Combine new_space (a copy of space 1) & space2, with the result in new_space */
+ if(H5S__fill_in_select(space1, op, space2, &new_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, NULL, "can't clip hyperslab information")
+ } /* end else */
/* 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;
@@ -7814,37 +10436,47 @@ done:
hid_t
H5Scombine_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id)
{
- H5S_t *space1; /* First Dataspace */
- H5S_t *space2; /* Second Dataspace */
- H5S_t *new_space = NULL; /* New Dataspace */
- hid_t ret_value; /* Return value */
+ H5S_t *space1; /* First Dataspace */
+ H5S_t *space2; /* Second Dataspace */
+ H5S_t *new_space = NULL; /* New Dataspace */
+ hid_t ret_value; /* Return value */
- FUNC_ENTER_API(FAIL)
+ FUNC_ENTER_API(H5I_INVALID_HID)
H5TRACE3("i", "iSsi", space1_id, op, space2_id);
/* Check args */
if(NULL == (space1 = (H5S_t *)H5I_object_verify(space1_id, H5I_DATASPACE)))
- HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a dataspace")
if(NULL == (space2 = (H5S_t *)H5I_object_verify(space2_id, H5I_DATASPACE)))
- HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataspace")
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, H5I_INVALID_HID, "not a dataspace")
if(!(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA))
- HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation")
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, H5I_INVALID_HID, "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")
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "dataspaces not same rank")
+
+ /* Note: currently, the offset of each dataspace is ignored */
+#if 0
+ /* Check that both dataspaces have the same offset */
+ /* Same note as in H5Smodify_select */
+ for(u=0; u<space1->extent.rank; u++) {
+ if(space1->select.offset[u] != space2->select.offset[u])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "dataspaces not same offset")
+ } /* end for */
+#endif
/* 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")
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, H5I_INVALID_HID, "dataspaces don't have hyperslab selections")
/* Go combine the dataspaces */
if(NULL == (new_space = H5S__combine_select(space1, op, space2)))
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to create hyperslab selection")
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, H5I_INVALID_HID, "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")
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTREGISTER, H5I_INVALID_HID, "unable to register dataspace atom")
done:
if(ret_value < 0 && new_space)
@@ -7857,7 +10489,7 @@ done:
/*-------------------------------------------------------------------------
* Function: H5S__modify_select
*
- * Purpose: Internal version of H5Sselect_select().
+ * Purpose: Internal version of H5Smodify_select().
*
* Return: New dataspace on success/NULL on failure
*
@@ -7869,8 +10501,6 @@ done:
herr_t
H5S__modify_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_PACKAGE
@@ -7878,53 +10508,52 @@ H5S__modify_select(H5S_t *space1, H5S_seloper_t op, H5S_t *space2)
/* Check args */
HDassert(space1);
HDassert(space2);
- HDassert(op > H5S_SELECT_NOOP && op < H5S_SELECT_INVALID);
+ HDassert(op >= H5S_SELECT_OR && op <= H5S_SELECT_NOTA);
/* 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)
+ if(NULL == space1->select.sel_info.hslab->span_lst)
+ if(H5S__hyper_generate_spans(space1) < 0)
HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
- /* Take ownership of the dataspace's hyperslab spans */
- /* (These are freed later) */
- tmp_spans=space1->select.sel_info.hslab->span_lst;
- space1->select.sel_info.hslab->span_lst=NULL;
-
- /* Reset the other dataspace selection information */
- if(H5S_SELECT_RELEASE(space1)<0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
-
- /* Allocate space for the hyperslab selection information */
- if((space1->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)) == NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info")
- space1->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
-
/* Set unlim_dim */
space1->select.sel_info.hslab->unlim_dim = -1;
- /* 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")
+ if(NULL == space2->select.sel_info.hslab->span_lst) {
+ hsize_t tmp_start[H5S_MAX_RANK];
+ hsize_t tmp_stride[H5S_MAX_RANK];
+ hsize_t tmp_count[H5S_MAX_RANK];
+ hsize_t tmp_block[H5S_MAX_RANK];
+ unsigned u;
+
+ for(u = 0; u < space2->extent.rank; u++) {
+ tmp_start[u] = space2->select.sel_info.hslab->diminfo.opt[u].start;
+ tmp_stride[u] = space2->select.sel_info.hslab->diminfo.opt[u].stride;
+ tmp_count[u] = space2->select.sel_info.hslab->diminfo.opt[u].count;
+ tmp_block[u] = space2->select.sel_info.hslab->diminfo.opt[u].block;
+ } /* end for */
-done:
- if(tmp_spans!=NULL)
- H5S__hyper_free_span_info(tmp_spans);
+ /* Call H5S_select_hyperslab directly */
+ if(H5S_select_hyperslab(space1, op, tmp_start, tmp_stride, tmp_count, tmp_block) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection")
+ } /* end if */
+ else
+ /* Combine spans from space1 & spans from space2, with the result in space1 */
+ if(H5S__fill_in_select(space1, op, space2, &space1) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't perform operation on two selections")
+done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5S__modify_select() */
/*--------------------------------------------------------------------------
NAME
- H5Sselect_select
+ H5Smodify_select
PURPOSE
Refine a hyperslab selection with an operation using a second hyperslab
to modify it
USAGE
- herr_t H5Sselect_select(space1, op, space2)
+ herr_t H5Smodify_select(space1, op, space2)
hid_t space1; IN/OUT: First Dataspace ID
H5S_seloper_t op; IN: Selection operation
hid_t space2; IN: Second Dataspace ID
@@ -7940,10 +10569,10 @@ done:
REVISION LOG
--------------------------------------------------------------------------*/
herr_t
-H5Sselect_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id)
+H5Smodify_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 *space1; /* First Dataspace */
+ H5S_t *space2; /* Second Dataspace */
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_API(FAIL)
@@ -7961,6 +10590,31 @@ H5Sselect_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id)
if(space1->extent.rank != space2->extent.rank)
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same rank")
+ /* Check that both dataspaces have the same offset */
+ /** Note that this is a tricky part of this function. It's
+ * possible that two dataspaces have different "offset". If the
+ * space2 has smaller offset value than that of space1 in a
+ * dimension, then the span elements of this dimension in
+ * space2 could have negative "low" and "high" values relative
+ * to the offset in space1. In other words, if the bounds of
+ * span elements in space2 are adjusted relative to the offset
+ * in space1, then every span element's bound is computed as
+ * "origin_bound+offset2-offset1". Therefore, if offset2 (the
+ * offset of space2) is smaller, then
+ * "origin_bound+offset2-offset1" could be negative which is
+ * not allowed by the bound type declaration as hsize_t!
+ * As a result, if the op is an OR selection, then the final
+ * result may contain span elements that have negative bound!
+ * So right now, the difference in the offset is totally
+ * ignored!!
+ */
+#if 0
+ for(u=0; u<space1->extent.rank; u++) {
+ if(space1->select.offset[u] != space2->select.offset[u])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same offset")
+ } /* end for */
+#endif
+
/* 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")
@@ -7971,1345 +10625,652 @@ H5Sselect_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id)
done:
FUNC_LEAVE_API(ret_value)
-} /* end H5Sselect_select() */
-#endif /* NEW_HYPERSLAB_API */ /* Works */
+} /* end H5Smodify_select() */
/*--------------------------------------------------------------------------
NAME
- H5S__hyper_get_seq_list_gen
+ H5S__hyper_proj_int_build_proj
PURPOSE
- Create a list of offsets & lengths for a selection
+ Secondary iteration routine for H5S__hyper_project_intersection
USAGE
- herr_t H5S_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
+ herr_t H5S__hyper_proj_int_build_proj(udata)
+ H5S_hyper_project_intersect_ud_t *udata; IN/OUT: Persistent shared data for iteration
RETURNS
Non-negative on success/Negative on failure.
DESCRIPTION
- Use the selection in the dataspace to generate a list of byte offsets and
- lengths for the region(s) selected. Start/Restart from the position in the
- ITER parameter. The number of sequences generated is limited by the MAXSEQ
- parameter and the number of sequences actually generated is stored in the
- NSEQ parameter.
+ Takes the skip and nelem amounts listed in udata and converts them to
+ span trees in the projected space, using the destination space. This
+ is a non-recursive algorithm by necessity, it saves the current state
+ of iteration in udata and resumes in the same location on subsequent
+ calls.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
static herr_t
-H5S__hyper_get_seq_list_gen(const H5S_t *space, H5S_sel_iter_t *iter,
- size_t maxseq, size_t maxelem, size_t *nseq, size_t *nelem,
- hsize_t *off, size_t *len)
-{
- H5S_hyper_span_t *curr_span; /* Current hyperslab span node */
- H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */
- hsize_t slab[H5S_MAX_RANK]; /* Cumulative size of each dimension in bytes */
- hsize_t acc; /* Accumulator for computing cumulative sizes */
- hsize_t loc_off; /* Element offset in the dataspace */
- hsize_t last_span_end = 0; /* The offset of the end of the last span */
- hsize_t *abs_arr; /* Absolute hyperslab span position */
- const hssize_t *off_arr; /* Offset within the dataspace extent */
- size_t span_size = 0; /* Number of bytes in current span to actually process */
- size_t io_left; /* Number of elements left to process */
- size_t io_bytes_left; /* Number of bytes left to process */
- size_t io_used; /* Number of elements processed */
- size_t curr_seq = 0; /* Number of sequence/offsets stored in the arrays */
- size_t elem_size; /* Size of each element iterating over */
- unsigned ndims; /* Number of dimensions of dataset */
- unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
- int curr_dim; /* Current dimension being operated on */
- unsigned u; /* Index variable */
- int i; /* Index variable */
-
- FUNC_ENTER_STATIC_NOERR
-
- /* Check args */
- HDassert(space);
- HDassert(iter);
- HDassert(maxseq > 0);
- HDassert(maxelem > 0);
- HDassert(nseq);
- HDassert(nelem);
- HDassert(off);
- HDassert(len);
-
- /* 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;
+H5S__hyper_proj_int_build_proj(H5S_hyper_project_intersect_ud_t *udata) {
+ H5S_hyper_span_info_t *copied_span_info = NULL; /* Temporary span info pointer */
+ herr_t ret_value = SUCCEED; /* Return value */
- /* Advance the hyperslab iterator */
- /* Check if we are done */
- if(io_bytes_left > 0) {
- /* Move to next span in fastest changing dimension */
- curr_span = curr_span->next;
+ FUNC_ENTER_STATIC
- if(NULL != curr_span) {
- /* Move location offset of destination */
- loc_off += (curr_span->low - abs_arr[fast_dim]) * elem_size;
+ HDassert(udata->nelem > 0);
- /* 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;
+ /*
+ * Skip over skipped elements
+ */
+ if(udata->skip > 0) {
+ /* Work upwards, finishing each span tree before moving up */
+ HDassert(udata->ds_span[udata->depth]);
+ do {
+ /* Check for lowest dimension */
+ if(udata->ds_span[udata->depth]->down) {
+ if(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high) {
+ /* If we will run out of elements to skip in this span,
+ * advance to the first not fully skipped span and break
+ * out of this loop (start moving downwards) */
+ if(udata->skip < H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen)
+ * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
+ udata->ds_low[udata->depth] += udata->skip / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
+ udata->skip %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
+ break;
+ } /* end if */
- /* Check if we are still within the span */
- if(abs_arr[fast_dim] <= curr_span->high) {
- iter->u.hyp.span[fast_dim] = curr_span;
+ /* Skip over this entire span */
+ udata->skip -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts
+ * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1);
+ } /* end if */
} /* end if */
- /* 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) {
+ HDassert(udata->ds_rank - udata->depth == 1);
+
+ /* If we will run out of elements to skip in this span,
+ * skip the remainder of the skipped elements and break out */
+ HDassert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high);
+ if(udata->skip < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
+ udata->ds_low[udata->depth] += udata->skip;
+ udata->skip = 0;
break;
} /* end if */
- /* 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;
+ /* Skip over this entire span */
+ udata->skip -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1;
+ } /* end else */
- /* Reset absolute position */
- abs_arr[curr_dim] = curr_span->low;
+ /* Advance to next span */
+ udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
+ if(udata->ds_span[udata->depth])
+ udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
+ else if(udata->depth > 0) {
+ /* If present, append this span tree to the higher dimension's,
+ * and release ownership of it */
+ if(udata->ps_span_info[udata->depth]) {
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth - 1],
+ udata->ds_rank - udata->depth + 1, udata->ds_low[udata->depth - 1],
+ udata->ds_low[udata->depth - 1],
+ udata->ps_span_info[udata->depth]) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ H5S__hyper_free_span_info(udata->ps_span_info[udata->depth]);
+ udata->ps_span_info[udata->depth] = NULL;
+ } /* end if */
+ /* Ran out of spans, move up one dimension */
+ udata->depth--;
+ HDassert(udata->ds_span[udata->depth]);
+ udata->ds_low[udata->depth]++;
+ } /* end if */
+ else
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "insufficient elements in destination selection")
+ } while((udata->skip > 0)
+ || (udata->ds_low[udata->depth] > udata->ds_span[udata->depth]->high));
+
+ /* Work downwards until skip is 0 */
+ HDassert(udata->ds_span[udata->depth]);
+ while(udata->skip > 0) {
+ HDassert(udata->ds_span[udata->depth]->down);
+ udata->depth++;
+ udata->ds_span[udata->depth] = udata->ds_span[udata->depth - 1]->down->head;
+ udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
+ if(udata->ds_span[udata->depth]->down) {
+ do {
+ /* If we will run out of elements to skip in this span,
+ * advance to the first not fully skipped span and
+ * continue down */
+ if(udata->skip < H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen)
+ * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
+ udata->ds_low[udata->depth] += udata->skip / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
+ udata->skip %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
break;
} /* end if */
- 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, resetting 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 */
+ /* Skip over this entire span */
+ udata->skip -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts
+ * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1);
- /* 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;
+ /* Advance to next span */
+ udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
+ HDassert(udata->ds_span[udata->depth]);
+ udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
+ } while(udata->skip > 0);
} /* end if */
else {
- /* 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 */
+ do {
+ /* If we will run out of elements to skip in this span,
+ * skip the remainder of the skipped elements */
+ if(udata->skip < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
+ udata->ds_low[udata->depth] += udata->skip;
+ udata->skip = 0;
+ break;
+ } /* end if */
- /* Set the location of the last span's end */
- last_span_end = loc_off + span_size;
-/* end COMMON */
+ /* Skip over this entire span */
+ udata->skip -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1;
- /* If the sequence & offset arrays are full, do what? */
- if(curr_seq >= maxseq) {
- /* Break out now, we are finished with sequences */
- break;
- } /* end else */
+ /* Advance to next span */
+ udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
+ HDassert(udata->ds_span[udata->depth]);
+ udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
+ } while(udata->skip > 0);
} /* end else */
-
- /* Move to next span in fastest changing dimension */
- curr_span=curr_span->next;
} /* end while */
+ } /* end if */
- /* 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;
+ /*
+ * Add requested number of elements to projected space
+ */
+ /* Work upwards, adding all elements of each span tree until it can't fit
+ * all elements */
+ HDassert(udata->ds_span[udata->depth]);
+ do {
+ /* Check for lowest dimension */
+ if(udata->ds_span[udata->depth]->down) {
+ if(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high) {
+ /* If we will run out of elements to add in this span, add
+ * any complete spans, advance to the first not fully added
+ * span, and break out of this loop (start moving downwards)
+ */
+ if(udata->nelem < H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen)
+ * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
+ if(udata->nelem >= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) {
+ if(udata->share_selection) {
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
+ udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
+ udata->ds_low[udata->depth] + (udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) - 1,
+ udata->ds_span[udata->depth]->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ } /* end if */
+ else {
+ /* If we're not sharing the destination space's
+ * spans, we must copy it first (then release it
+ * afterwards) */
+ if(NULL == (copied_span_info = H5S__hyper_copy_span_helper(udata->ds_span[udata->depth]->down, udata->ds_rank - udata->depth, 1, udata->op_gen)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination spans")
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
+ udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
+ udata->ds_low[udata->depth] + (udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) - 1,
+ copied_span_info) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ H5S__hyper_free_span_info(copied_span_info);
+ copied_span_info = NULL;
+ } /* end else */
+ udata->ds_low[udata->depth] += udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
+ udata->nelem %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
+ } /* end if */
break;
} /* end if */
- } /* 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;
+ /* Append span tree for entire span */
+ if(udata->share_selection) {
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
+ udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
+ udata->ds_span[udata->depth]->high,
+ udata->ds_span[udata->depth]->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
} /* end if */
else {
- /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
- curr_dim--;
+ /* If we're not sharing the destination space's
+ * spans, we must copy it first (then release it
+ * afterwards) */
+ if(NULL == (copied_span_info = H5S__hyper_copy_span_helper(udata->ds_span[udata->depth]->down, udata->ds_rank - udata->depth, 1, udata->op_gen)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination spans")
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
+ udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
+ udata->ds_span[udata->depth]->high,
+ copied_span_info) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ H5S__hyper_free_span_info(copied_span_info);
+ copied_span_info = NULL;
} /* end else */
- } /* 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;
+ udata->nelem -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts
+ * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1);
+ } /* end if */
} /* end if */
else {
- /* Walk back down the iterator positions, resetting them */
- while((unsigned)curr_dim < fast_dim) {
- HDassert(curr_span);
- HDassert(curr_span->down);
- HDassert(curr_span->down->head);
-
- /* Increment current dimension to the next dimension down */
- curr_dim++;
-
- /* Set the new span for the next dimension down */
- iter->u.hyp.span[curr_dim] = curr_span->down->head;
-
- /* Advance span down the tree */
- curr_span = curr_span->down->head;
-
- /* Reset the absolute offset for the dim */
- abs_arr[curr_dim] = curr_span->low;
- } /* end while */
+ HDassert(udata->ds_rank - udata->depth == 1);
+
+ /* If we will run out of elements to add in this span, add the
+ * remainder of the elements and break out */
+ HDassert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high);
+ if(udata->nelem < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1,
+ udata->ds_low[udata->depth], udata->ds_low[udata->depth] + udata->nelem - 1, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ udata->ds_low[udata->depth] += udata->nelem;
+ udata->nelem = 0;
+ break;
+ } /* end if */
- /* Verify that the curr_span points to the fastest dim */
- HDassert(curr_span == iter->u.hyp.span[fast_dim]);
+ /* Append span tree for entire span */
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1,
+ udata->ds_low[udata->depth], udata->ds_span[udata->depth]->high, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ udata->nelem -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1;
} /* end else */
- /* 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[H5S_MAX_RANK]; /* Hyperslab size */
- const hssize_t *sel_off; /* Selection offset in dataspace */
- hsize_t offset[H5S_MAX_RANK]; /* Coordinate offset in dataspace */
- hsize_t tmp_count[H5S_MAX_RANK];/* Temporary block count */
- hsize_t tmp_block[H5S_MAX_RANK];/* Temporary block offset */
- hsize_t wrap[H5S_MAX_RANK]; /* Bytes to wrap around at the end of a row */
- hsize_t skip[H5S_MAX_RANK]; /* Bytes to skip between blocks */
- const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
- hsize_t fast_dim_start, /* Local copies of fastest changing dimension info */
- fast_dim_stride,
- fast_dim_block,
- fast_dim_offset;
- size_t fast_dim_buf_off; /* Local copy of amount to move fastest dimension buffer offset */
- size_t fast_dim_count; /* Number of blocks left in fastest changing dimension */
- size_t tot_blk_count; /* Total number of blocks left to output */
- size_t act_blk_count; /* Actual number of blocks to output */
- size_t total_rows; /* Total number of entire rows to output */
- size_t curr_rows; /* Current number of entire rows to output */
- unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
- unsigned ndims; /* Number of dimensions of dataset */
- int temp_dim; /* Temporary rank holder */
- hsize_t acc; /* Accumulator */
- hsize_t loc; /* Coordinate offset */
- size_t curr_seq = 0; /* Current sequence being operated on */
- size_t actual_elem; /* The actual number of elements to count */
- size_t actual_bytes;/* The actual number of bytes to copy */
- size_t io_left; /* The number of elements left in I/O operation */
- size_t start_io_left; /* The initial number of elements left in I/O operation */
- size_t elem_size; /* Size of each element iterating over */
- unsigned u; /* Local index variable */
- int i; /* Local index variable */
-
- FUNC_ENTER_STATIC_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]);
+ /* Advance to next span */
+ udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
+ if(udata->ds_span[udata->depth])
+ udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
+ else if(udata->depth > 0) {
+ /* Append this span tree to the higher dimension's, and release
+ * ownership of it */
+ HDassert(udata->ps_span_info[udata->depth]);
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth - 1],
+ udata->ds_rank - udata->depth + 1, udata->ds_low[udata->depth - 1],
+ udata->ds_low[udata->depth - 1],
+ udata->ps_span_info[udata->depth]) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ H5S__hyper_free_span_info(udata->ps_span_info[udata->depth]);
+ udata->ps_span_info[udata->depth] = NULL;
- /* 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;
+ /* Ran out of spans, move up one dimension */
+ udata->depth--;
+ HDassert(udata->ds_span[udata->depth]);
+ udata->ds_low[udata->depth]++;
} /* 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;
+ /* We have finished the entire destination span tree. If there are
+ * still elements to add, issue an error. */
+ if(udata->nelem > 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_BADVALUE, FAIL, "insufficient elements in destination selection")
+ break;
} /* end else */
- } /* 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)
+ } while((udata->nelem > 0)
+ || (udata->ds_low[udata->depth] > udata->ds_span[udata->depth]->high));
+
+ /* Work downwards until nelem is 0 */
+ HDassert(udata->ds_span[udata->depth] || (udata->nelem == 0));
+ while(udata->nelem > 0) {
+ HDassert(udata->ds_span[udata->depth]->down);
+ udata->depth++;
+ udata->ds_span[udata->depth] = udata->ds_span[udata->depth - 1]->down->head;
+ udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
+ if(udata->ds_span[udata->depth]->down) {
+ do {
+ /* If we will run out of elements to add in this span, add
+ * any complete spans, advance to the first not fully added
+ * span and continue down
+ */
+ HDassert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high);
+ if(udata->nelem < H5S__hyper_spans_nelem_helper(udata->ds_span[udata->depth]->down, 0, udata->op_gen)
+ * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
+ if(udata->nelem >= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) {
+ if(udata->share_selection) {
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
+ udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
+ udata->ds_low[udata->depth] + (udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) - 1,
+ udata->ds_span[udata->depth]->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ } /* end if */
+ else {
+ /* If we're not sharing the destination space's
+ * spans, we must copy it first (then release it
+ * afterwards) */
+ if(NULL == (copied_span_info = H5S__hyper_copy_span_helper(udata->ds_span[udata->depth]->down, udata->ds_rank - udata->depth, 1, udata->op_gen)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination spans")
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
+ udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
+ udata->ds_low[udata->depth] + (udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts) - 1,
+ copied_span_info) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ H5S__hyper_free_span_info(copied_span_info);
+ copied_span_info = NULL;
+ } /* end else */
+ udata->ds_low[udata->depth] += udata->nelem / udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
+ udata->nelem %= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts;
+ } /* end if */
break;
- 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]++;
+ } /* end if */
- /* 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 */
+ /* Append span tree for entire span */
+ if(udata->share_selection) {
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
+ udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
+ udata->ds_span[udata->depth]->high,
+ udata->ds_span[udata->depth]->down) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ } /* end if */
+ else {
+ /* If we're not sharing the destination space's
+ * spans, we must copy it first (then release it
+ * afterwards) */
+ if(NULL == (copied_span_info = H5S__hyper_copy_span_helper(udata->ds_span[udata->depth]->down, udata->ds_rank - udata->depth, 1, udata->op_gen)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOPY, FAIL, "can't copy destination spans")
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth],
+ udata->ds_rank - udata->depth, udata->ds_low[udata->depth],
+ udata->ds_span[udata->depth]->high,
+ copied_span_info) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ H5S__hyper_free_span_info(copied_span_info);
+ copied_span_info = NULL;
} /* end else */
-
- /* Decrement dimension count */
- temp_dim--;
- } /* end while */
+ udata->nelem -= udata->ds_span[udata->depth]->down->op_info[0].u.nelmts
+ * (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1);
+
+ /* Advance to next span */
+ udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
+ HDassert(udata->ds_span[udata->depth]);
+ udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
+ } while(udata->nelem > 0);
} /* end if */
else {
- /* Update the offset in the fastest dimension */
- offset[fast_dim] += (fast_dim_stride * act_blk_count);
- } /* end else */
- } /* end if */
-
- /* Compute the number of entire rows to read in */
- H5_CHECK_OVERFLOW(tot_blk_count / tdiminfo[fast_dim].count, hsize_t, size_t);
- curr_rows = total_rows = (size_t)(tot_blk_count / tdiminfo[fast_dim].count);
-
- /* Reset copy of number of blocks in fastest dimension */
- H5_CHECKED_ASSIGN(fast_dim_count, size_t, tdiminfo[fast_dim].count, hsize_t);
-
- /* Read in data until an entire sequence can't be written out any longer */
- while(curr_rows > 0) {
-
-#define DUFF_GUTS \
-/* Store the sequence information */ \
-off[curr_seq] = loc; \
-len[curr_seq] = actual_bytes; \
- \
-/* Increment sequence count */ \
-curr_seq++; \
- \
-/* Increment information to reflect block just processed */ \
-loc += fast_dim_buf_off;
-
-#ifdef NO_DUFFS_DEVICE
- /* Loop over all the blocks in the fastest changing dimension */
- while(fast_dim_count > 0) {
- DUFF_GUTS
-
- /* Decrement number of blocks */
- fast_dim_count--;
- } /* end while */
-#else /* NO_DUFFS_DEVICE */
- {
- size_t duffs_index; /* Counting index for Duff's device */
-
- duffs_index = (fast_dim_count + 7) / 8;
- switch (fast_dim_count % 8) {
- default:
- HDassert(0 && "This Should never be executed!");
- break;
- case 0:
- do
- {
- DUFF_GUTS
- H5_ATTR_FALLTHROUGH
- case 7:
- DUFF_GUTS
- H5_ATTR_FALLTHROUGH
- case 6:
- DUFF_GUTS
- H5_ATTR_FALLTHROUGH
- case 5:
- DUFF_GUTS
- H5_ATTR_FALLTHROUGH
- case 4:
- DUFF_GUTS
- H5_ATTR_FALLTHROUGH
- case 3:
- DUFF_GUTS
- H5_ATTR_FALLTHROUGH
- case 2:
- DUFF_GUTS
- H5_ATTR_FALLTHROUGH
- case 1:
- DUFF_GUTS
- } while (--duffs_index > 0);
- } /* end switch */
- }
-#endif /* NO_DUFFS_DEVICE */
-#undef DUFF_GUTS
-
- /* Increment offset in destination buffer */
- loc += wrap[fast_dim];
-
- /* Increment the offset and count for the other dimensions */
- temp_dim = (int)fast_dim - 1;
- while(temp_dim >= 0) {
- /* Move to the next row in the curent dimension */
- offset[temp_dim]++;
- tmp_block[temp_dim]++;
-
- /* If this block is still in the range of blocks to output for the dimension, break out of loop */
- if(tmp_block[temp_dim] < tdiminfo[temp_dim].block)
- break;
- else {
- /* Move to the next block in the current dimension */
- offset[temp_dim] += (tdiminfo[temp_dim].stride - tdiminfo[temp_dim].block);
- loc += skip[temp_dim];
- tmp_block[temp_dim] = 0;
- tmp_count[temp_dim]++;
-
- /* If this block is still in the range of blocks to output for the dimension, break out of loop */
- if(tmp_count[temp_dim] < tdiminfo[temp_dim].count)
+ HDassert(udata->ds_rank - udata->depth == 1);
+ do {
+ /* If we will run out of elements to add in this span, add
+ * the remainder of the elements and break out */
+ HDassert(udata->ds_low[udata->depth] <= udata->ds_span[udata->depth]->high);
+ if(udata->nelem < (udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1)) {
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1,
+ udata->ds_low[udata->depth], udata->ds_low[udata->depth] + udata->nelem - 1, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ udata->ds_low[udata->depth] += udata->nelem;
+ udata->nelem = 0;
break;
- 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 */
- /* Decrement the number of rows left */
- curr_rows--;
+ /* Append span tree for entire span */
+ if(H5S__hyper_append_span(&udata->ps_span_info[udata->depth], 1,
+ udata->ds_low[udata->depth], udata->ds_span[udata->depth]->high, NULL) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ udata->nelem -= udata->ds_span[udata->depth]->high - udata->ds_low[udata->depth] + 1;
+
+ /* Advance to next span */
+ udata->ds_span[udata->depth] = udata->ds_span[udata->depth]->next;
+ HDassert(udata->ds_span[udata->depth]);
+ udata->ds_low[udata->depth] = udata->ds_span[udata->depth]->low;
+ } while(udata->nelem > 0);
+ } /* end else */
} /* end while */
- /* 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;
+ HDassert(udata->skip == 0);
+ HDassert(udata->nelem == 0);
- /* Decrement number of blocks */
- fast_dim_count--;
- } /* end while */
+ /* Mark projected space as changed (for all ranks) */
+ udata->ps_clean_bitmap = 0;
- /* 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);
+done:
+ /* Cleanup on failure */
+ if(copied_span_info) {
+ HDassert(ret_value < 0);
+ H5S__hyper_free_span_info(copied_span_info);
+ copied_span_info = NULL;
} /* end if */
- /* 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() */
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5S__hyper_proj_int_build_proj() */
/*--------------------------------------------------------------------------
NAME
- H5S__hyper_get_seq_list_single
+ H5S__hyper_proj_int_iterate
PURPOSE
- Create a list of offsets & lengths for a selection
+ Main iteration routine for H5S__hyper_project_intersection
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
+ herr_t H5S__hyper_proj_int_iterate(ss_span_info,sis_span_info,count,depth,udata)
+ const H5S_hyper_span_info_t *ss_span_info; IN: Span tree for source selection
+ const H5S_hyper_span_info_t *sis_span_info; IN: Span tree for source intersect selection
+ hsize_t count; IN: Number of times to compute the intersection of ss_span_info and sis_span_info
+ unsigned depth; IN: Depth of iteration (in terms of rank)
+ H5S_hyper_project_intersect_ud_t *udata; IN/OUT: Persistent shared data for iteration
RETURNS
Non-negative on success/Negative on failure.
DESCRIPTION
- 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.
+ Computes the intersection of ss_span_info and sis_span_info and projects it
+ to the projected space (held in udata). It accomplishes this by iterating
+ over both spaces and computing the number of elements to skip (in
+ ss_span_info) and the number of elements to add (the intersection) in a
+ sequential fashion (similar to run length encoding). As necessary, this
+ function both recurses into lower dimensions and calls
+ H5S__hyper_proj_int_build_proj to convert the skip/nelem pairs to the
+ projected span tree.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
static herr_t
-H5S__hyper_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)
+H5S__hyper_proj_int_iterate(const H5S_hyper_span_info_t *ss_span_info,
+ const H5S_hyper_span_info_t *sis_span_info, hsize_t count, unsigned depth,
+ H5S_hyper_project_intersect_ud_t *udata)
{
- const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
- const hssize_t *sel_off; /* Selection offset in dataspace */
- hsize_t *mem_size; /* Size of the source buffer */
- hsize_t base_offset[H5S_MAX_RANK]; /* Base coordinate offset in dataspace */
- hsize_t offset[H5S_MAX_RANK]; /* Coordinate offset in dataspace */
- hsize_t slab[H5S_MAX_RANK]; /* Hyperslab size */
- hsize_t fast_dim_block; /* Local copies of fastest changing dimension info */
- hsize_t acc; /* Accumulator */
- hsize_t loc; /* Coordinate offset */
- size_t tot_blk_count; /* Total number of blocks left to output */
- size_t elem_size; /* Size of each element iterating over */
- size_t io_left; /* The number of elements left in I/O operation */
- size_t actual_elem; /* The actual number of elements to count */
- unsigned ndims; /* Number of dimensions of dataset */
- unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
- unsigned skip_dim; /* Rank of the dimension to skip along */
+ const H5S_hyper_span_t *ss_span; /* Current span in source space */
+ const H5S_hyper_span_t *sis_span; /* Current span in source intersect space */
+ hsize_t ss_low; /* Current low bounds of source span */
+ hsize_t sis_low; /* Current low bounds of source intersect span */
+ hsize_t high; /* High bounds of current intersection */
+ hsize_t low; /* Low bounds of current intersection */
+ hsize_t old_skip; /* Value of udata->skip before main loop */
+ hsize_t old_nelem; /* Value of udata->nelem before main loop */
+ hbool_t check_intersect; /* Whether to check for intersecting elements */
unsigned u; /* Local index variable */
- int i; /* Local index variable */
-
- FUNC_ENTER_STATIC_NOERR
-
- /* Check args */
- HDassert(space);
- HDassert(iter);
- HDassert(maxseq > 0);
- HDassert(maxelem > 0);
- HDassert(nseq);
- HDassert(nelem);
- HDassert(off);
- HDassert(len);
-
- /* 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;
+ herr_t ret_value = SUCCEED; /* Return value */
- /* Check for 1-dim selection */
- if(0 == fast_dim) {
- /* Sanity checks */
- HDassert(1 == tot_blk_count);
- HDassert(io_left == actual_elem);
+ FUNC_ENTER_STATIC
- /* Store the sequence information */
- *off++ = loc;
- *len++ = actual_bytes;
+ /* Check for non-overlapping bounds */
+ check_intersect = TRUE;
+ for(u = 0; u < (udata->ss_rank - depth); u++)
+ if(!H5S_RANGE_OVERLAP(ss_span_info->low_bounds[u],
+ ss_span_info->high_bounds[u],
+ sis_span_info->low_bounds[u],
+ sis_span_info->high_bounds[u])) {
+ check_intersect = FALSE;
+ break;
} /* end if */
- 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;
+ /* Only enter main loop if there's something to do */
+ if(check_intersect) {
+ /* Set ps_clean_bitmap */
+ udata->ps_clean_bitmap |= (((uint32_t)1) << depth);
- /* Decrement block count */
- blk_count--;
- } /* end while */
-
- /* Move to the next location */
- offset[skip_dim] += tot_blk_count;
- } /* end if */
- else {
- hsize_t tmp_block[H5S_MAX_RANK];/* Temporary block offset */
- hsize_t skip[H5S_MAX_RANK]; /* Bytes to skip between blocks */
- int temp_dim; /* Temporary rank holder */
+ /* Save old skip and nelem */
+ old_skip = udata->skip;
+ old_nelem = udata->nelem;
- /* Set the starting block location */
- for(u = 0; u < ndims; u++)
- tmp_block[u] = iter->u.hyp.off[u] - tdiminfo[u].start;
+ /* Intersect spaces once per count */
+ for(u = 0; u < count; u++) {
+ ss_span = ss_span_info->head;
+ sis_span = sis_span_info->head;
+ HDassert(ss_span && sis_span);
+ ss_low = ss_span->low;
+ sis_low = sis_span->low;
- /* 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;
+ /* Main loop */
+ do {
+ /* Check if spans overlap */
+ if(H5S_RANGE_OVERLAP(ss_low, ss_span->high,
+ sis_low, sis_span->high)) {
+ high = MIN(ss_span->high, sis_span->high);
+ if(ss_span->down) {
+ /* Add skipped elements if there's a pre-gap */
+ if(ss_low < sis_low) {
+ low = sis_low;
+ H5S_HYPER_PROJ_INT_ADD_SKIP(udata, H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) * (sis_low - ss_low), FAIL);
+ } /* end if */
+ else
+ low = ss_low;
- /* Set temporary dimension for advancing offsets */
- temp_dim = (int)skip_dim;
+ /* Recurse into next dimension down */
+ if(H5S__hyper_proj_int_iterate(ss_span->down, sis_span->down, high - low + 1, depth + 1, udata) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "can't iterate over source selections")
+ } /* end if */
+ else {
+ HDassert(depth == udata->ss_rank - 1);
- /* Increment offset in destination buffer */
- loc += skip_slab;
+ /* Add skipped elements if there's a pre-gap */
+ if(ss_low < sis_low) {
+ low = sis_low;
+ H5S_HYPER_PROJ_INT_ADD_SKIP(udata, sis_low - ss_low, FAIL);
+ } /* end if */
+ else
+ low = ss_low;
- /* 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]++;
+ /* Add overlapping elements */
+ udata->nelem += high - low + 1;
+ } /* end else */
- /* 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 */
+ /* Advance spans */
+ if(ss_span->high == sis_span->high) {
+ /* Advance both spans */
+ ss_span = ss_span->next;
+ if(ss_span)
+ ss_low = ss_span->low;
+ sis_span = sis_span->next;
+ if(sis_span)
+ sis_low = sis_span->low;
+ } /* end if */
+ else if(ss_span->high == high) {
+ /* Advance source span */
+ HDassert(ss_span->high < sis_span->high);
+ sis_low = high + 1;
+ ss_span = ss_span->next;
+ if(ss_span)
+ ss_low = ss_span->low;
+ } /* end if */
+ else {
+ /* Advance source intersect span */
+ HDassert(ss_span->high > sis_span->high);
+ ss_low = high + 1;
+ sis_span = sis_span->next;
+ if(sis_span)
+ sis_low = sis_span->low;
+ } /* end else */
+ } /* end if */
+ else {
+ /* Advance spans */
+ if(ss_span->high < sis_low) {
+ /* Add skipped elements */
+ if(ss_span->down)
+ H5S_HYPER_PROJ_INT_ADD_SKIP(udata, H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) * (ss_span->high - ss_low + 1), FAIL);
+ else
+ H5S_HYPER_PROJ_INT_ADD_SKIP(udata, ss_span->high - ss_low + 1, FAIL);
- /* Decrement dimension count */
- temp_dim--;
+ /* Advance source span */
+ ss_span = ss_span->next;
+ if(ss_span)
+ ss_low = ss_span->low;
+ } /* end if */
+ else {
+ /* Advance source intersect span */
+ HDassert(ss_low > sis_span->high);
+ sis_span = sis_span->next;
+ if(sis_span)
+ sis_low = sis_span->low;
+ } /* end else */
+ } /* end else */
+ } while(ss_span && sis_span);
+
+ if(ss_span && !((depth == 0) && (u == count - 1))) {
+ /* Count remaining elements in ss_span_info */
+ if(ss_span->down) {
+ H5S_HYPER_PROJ_INT_ADD_SKIP(udata, H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) * (ss_span->high - ss_low + 1), FAIL);
+ ss_span = ss_span->next;
+ while(ss_span) {
+ H5S_HYPER_PROJ_INT_ADD_SKIP(udata, H5S__hyper_spans_nelem_helper(ss_span->down, 0, udata->op_gen) * (ss_span->high - ss_span->low + 1), FAIL);
+ ss_span = ss_span->next;
} /* end while */
-
- /* 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_STATIC_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(H5S_DIMINFO_VALID_YES == space->select.sel_info.hslab->diminfo_valid) {
- const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */
- const hssize_t *sel_off; /* Selection offset in dataspace */
- hsize_t *mem_size; /* Size of the source buffer */
- unsigned ndims; /* Number of dimensions of dataset */
- unsigned fast_dim; /* Rank of the fastest changing dimension for the dataspace */
- hbool_t single_block; /* Whether the selection is a single block */
- unsigned u; /* Local index variable */
-
- /* Set a local copy of the diminfo pointer */
- tdiminfo = iter->u.hyp.diminfo;
-
- /* Check if this is a "flattened" regular hyperslab selection */
- if(iter->u.hyp.iter_rank != 0 && iter->u.hyp.iter_rank < space->extent.rank) {
- /* Set the aliases for a few important dimension ranks */
- ndims = iter->u.hyp.iter_rank;
-
- /* Set the local copy of the selection offset */
- sel_off = iter->u.hyp.sel_off;
-
- /* Set up the pointer to the size of the memory space */
- mem_size = iter->u.hyp.size;
- } /* end if */
- else {
- /* Set the aliases for a few important dimension ranks */
- ndims = space->extent.rank;
-
- /* Set the local copy of the selection offset */
- sel_off = space->select.offset;
-
- /* Set up the pointer to the size of the memory space */
- mem_size = space->extent.size;
- } /* end else */
- fast_dim = ndims - 1;
-
- /* Check if we stopped in the middle of a sequence of elements */
- if((iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start) % tdiminfo[fast_dim].stride != 0 ||
- ((iter->u.hyp.off[fast_dim] != tdiminfo[fast_dim].start) && tdiminfo[fast_dim].count == 1)) {
- hsize_t slab[H5S_MAX_RANK]; /* Hyperslab size */
- hsize_t loc; /* Coordinate offset */
- hsize_t acc; /* Accumulator */
- size_t leftover; /* The number of elements left over from the last sequence */
- size_t actual_elem; /* The actual number of elements to count */
- size_t elem_size; /* Size of each element iterating over */
- int i; /* Local index variable */
-
-
- /* Calculate the number of elements left in the sequence */
- if(tdiminfo[fast_dim].count == 1) {
- H5_CHECKED_ASSIGN(leftover, size_t, tdiminfo[fast_dim].block - (iter->u.hyp.off[fast_dim] - tdiminfo[fast_dim].start), hsize_t);
+ } /* end if */
+ else {
+ H5S_HYPER_PROJ_INT_ADD_SKIP(udata, ss_span->high - ss_low + 1, FAIL);
+ ss_span = ss_span->next;
+ while(ss_span) {
+ H5S_HYPER_PROJ_INT_ADD_SKIP(udata, ss_span->high - ss_span->low + 1, FAIL);
+ ss_span = ss_span->next;
+ } /* end while */
+ } /* end else */
} /* end if */
- 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 if the projected space was not changed since we started the
+ * first iteration of the loop, if so we do not need to continue
+ * looping and can just copy the result */
+ if(udata->ps_clean_bitmap & (((uint32_t)1) << depth)) {
+ HDassert(u == 0);
+ if(udata->skip == old_skip) {
+ /* First case: algorithm added only elements */
+ HDassert(udata->nelem >= old_nelem);
+ udata->nelem += (count - 1) * (udata->nelem - old_nelem);
+ } /* end if */
+ else if(udata->nelem == 0) {
+ /* Second case: algorithm added only skip. In this case,
+ * nelem must be 0 since otherwise adding skip would have
+ * triggered a change in the projected space */
+ HDassert(old_nelem == 0);
+ HDassert(udata->skip > old_skip);
+ udata->skip += (count - 1) * (udata->skip - old_skip);
+ } /* end if */
+ else {
+ /* Third case: agorithm added skip and nelem (in that
+ * order). Add the same skip and nelem once for each item
+ * remaining in count. */
+ hsize_t skip_add;
+ hsize_t nelem_add;
+
+ HDassert(udata->nelem > 0);
+ HDassert(udata->skip > old_skip);
+ HDassert(old_nelem == 0);
+
+ skip_add = udata->skip - old_skip;
+ nelem_add = udata->nelem - old_nelem;
+ for(u = 1; u < count; u++) {
+ H5S_HYPER_PROJ_INT_ADD_SKIP(udata, skip_add, FAIL);
+ udata->nelem += nelem_add;
+ } /* end for */
+ } /* end else */
- /* Check for a single block selected */
- single_block = TRUE;
- for(u = 0; u < ndims; u++)
- if(1 != tdiminfo[u].count) {
- single_block = FALSE;
+ /* End loop since we already took care of it */
break;
} /* end if */
-
- /* Check for single block selection */
- if(single_block)
- /* Use single-block optimized call to generate sequence list */
- ret_value = H5S__hyper_get_seq_list_single(space, iter, maxseq, maxelem, nseq, nelem, off, len);
- else
- /* Use optimized call to generate sequence list */
- ret_value = H5S__hyper_get_seq_list_opt(space, iter, maxseq, maxelem, nseq, nelem, off, len);
+ } /* end for */
+ } /* end if */
+ else if(depth > 0)
+ /* Just count skipped elements */
+ H5S_HYPER_PROJ_INT_ADD_SKIP(udata, H5S__hyper_spans_nelem_helper((H5S_hyper_span_info_t *)ss_span_info, 0, udata->op_gen) * count, FAIL); /* Casting away const OK -NAF */
+
+ /* Clean up if we are done */
+ if(depth == 0) {
+ /* Add remaining elements */
+ if(udata->nelem > 0)
+ if(H5S__hyper_proj_int_build_proj(udata) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't add elements to projected selection")
+
+ /* Append remaining span trees */
+ for(u = udata->ds_rank - 1; u > 0; u--)
+ if(udata->ps_span_info[u]) {
+ if(H5S__hyper_append_span(&udata->ps_span_info[u - 1],
+ udata->ds_rank - u + 1, udata->ds_low[u - 1],
+ udata->ds_low[u - 1],
+ udata->ps_span_info[u]) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ H5S__hyper_free_span_info(udata->ps_span_info[u]);
+ udata->ps_span_info[u] = NULL;
+ } /* end if */
} /* end if */
- else
- /* Call the general sequence generator routine */
- ret_value = H5S__hyper_get_seq_list_gen(space, iter, maxseq, maxelem, nseq, nelem, off, len);
+done:
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5S__hyper_get_seq_list() */
+} /* end H5S__hyper_proj_int_iterate() */
/*--------------------------------------------------------------------------
@@ -9320,21 +11281,23 @@ H5S__hyper_get_seq_list(const H5S_t *space, unsigned H5_ATTR_UNUSED flags, H5S_s
src_intersect_space within the selection of src_space as a selection
within the selection of dst_space
USAGE
- herr_t H5S__hyper_project_intersection(src_space,dst_space,src_intersect_space,proj_space)
+ herr_t H5S__hyper_project_intersection(src_space,dst_space,src_intersect_space,proj_space,share_selection)
H5S_t *src_space; IN: Selection that is mapped to dst_space, and intersected with src_intersect_space
H5S_t *dst_space; IN: Selection that is mapped to src_space, and which contains the result
H5S_t *src_intersect_space; IN: Selection whose intersection with src_space is projected to dst_space to obtain the result
H5S_t *proj_space; OUT: Will contain the result (intersection of src_intersect_space and src_space projected from src_space to dst_space) after the operation
+ hbool_t share_selection; IN: Whether we are allowed to share structures inside dst_space with proj_space
RETURNS
Non-negative on success/Negative on failure.
DESCRIPTION
Projects the intersection of of the selections of src_space and
src_intersect_space within the selection of src_space as a selection
- within the selection of dst_space. The result is placed in the
- selection of proj_space. Note src_space, dst_space, and
- src_intersect_space do not need to use hyperslab selections, but they
- cannot use point selections. The result is always a hyperslab
- selection.
+ within the selection of dst_space. The result is placed in the selection
+ of proj_space. Note src_space, dst_space, and src_intersect_space do not
+ need to use hyperslab selections, but they cannot use point selections.
+ The result is always a hyperslab or none selection. Note also that
+ proj_space can share some span trees with dst_space, so proj_space
+ must not be subsequently modified if dst_space must be preserved.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
@@ -9342,48 +11305,14 @@ H5S__hyper_get_seq_list(const H5S_t *space, unsigned H5_ATTR_UNUSED flags, H5S_s
--------------------------------------------------------------------------*/
herr_t
H5S__hyper_project_intersection(const H5S_t *src_space, const H5S_t *dst_space,
- const H5S_t *src_intersect_space, H5S_t *proj_space)
+ const H5S_t *src_intersect_space, H5S_t *proj_space,
+ hbool_t share_selection)
{
- hsize_t ss_off[H5S_PROJECT_INTERSECT_NSEQS]; /* Offset array for src_space */
- size_t ss_len[H5S_PROJECT_INTERSECT_NSEQS]; /* Length array for src_space */
- size_t ss_nseq; /* Number of sequences for src_space */
- size_t ss_nelem; /* Number of elements for src_space */
- size_t ss_i = (size_t)0; /* Index into offset/length arrays for src_space */
- hbool_t advance_ss = FALSE; /* Whether to advance ss_i on the next iteration */
- H5S_sel_iter_t *ss_iter = NULL; /* Selection iterator for src_space */
- hbool_t ss_iter_init = FALSE; /* Whether ss_iter is initialized */
- hsize_t ss_sel_off = (hsize_t)0; /* Offset within src_space selection */
- hsize_t ds_off[H5S_PROJECT_INTERSECT_NSEQS]; /* Offset array for dst_space */
- size_t ds_len[H5S_PROJECT_INTERSECT_NSEQS]; /* Length array for dst_space */
- size_t ds_nseq; /* Number of sequences for dst_space */
- size_t ds_nelem; /* Number of elements for dst_space */
- size_t ds_i = (size_t)0; /* Index into offset/length arrays for dst_space */
- H5S_sel_iter_t *ds_iter = NULL; /* Selection iterator for dst_space */
- hbool_t ds_iter_init = FALSE; /* Whether ds_iter is initialized */
- hsize_t ds_sel_off = (hsize_t)0; /* Offset within dst_space selection */
- hsize_t sis_off[H5S_PROJECT_INTERSECT_NSEQS]; /* Offset array for src_intersect_space */
- size_t sis_len[H5S_PROJECT_INTERSECT_NSEQS]; /* Length array for src_intersect_space */
- size_t sis_nseq; /* Number of sequences for src_intersect_space */
- size_t sis_nelem; /* Number of elements for src_intersect_space */
- size_t sis_i = (size_t)0; /* Index into offset/length arrays for src_intersect_space */
- hbool_t advance_sis = FALSE; /* Whether to advance sis_i on the next iteration */
- H5S_sel_iter_t *sis_iter = NULL; /* Selection iterator for src_intersect_space */
- hbool_t sis_iter_init = FALSE; /* Whether sis_iter is initialized */
- hsize_t int_sel_off; /* Offset within intersected selections (ss/sis and ds/ps) */
- size_t int_len; /* Length of segment in intersected selections */
- hsize_t proj_off; /* Segment offset in proj_space */
- size_t proj_len; /* Segment length in proj_space */
- size_t proj_len_rem; /* Remaining length in proj_space for segment */
- hsize_t proj_down_dims[H5S_MAX_RANK]; /* "Down" dimensions in proj_space */
- H5S_hyper_span_info_t *curr_span_tree[H5S_MAX_RANK]; /* Current span tree being built (in each dimension) */
- H5S_hyper_span_t *prev_span[H5S_MAX_RANK]; /* Previous span in tree (in each dimension) */
- hsize_t curr_span_up_dim[H5S_MAX_RANK]; /* "Up" dimensions for current span */
- unsigned proj_rank; /* Rank of proj_space */
- hsize_t low; /* Low value of span */
- hsize_t high; /* High value of span */
- size_t span_len; /* Length of span */
- size_t nelem; /* Number of elements returned for get_seq_list op */
- unsigned i; /* Local index variable */
+ H5S_hyper_project_intersect_ud_t udata; /* User data for subroutines */
+ const H5S_hyper_span_info_t *ss_span_info;
+ const H5S_hyper_span_info_t *ds_span_info;
+ H5S_hyper_span_info_t *ss_span_info_buf = NULL;
+ H5S_hyper_span_info_t *ds_span_info_buf = NULL;
herr_t ret_value = SUCCEED; /* Return value */
FUNC_ENTER_PACKAGE
@@ -9394,303 +11323,100 @@ H5S__hyper_project_intersection(const H5S_t *src_space, const H5S_t *dst_space,
HDassert(src_intersect_space);
HDassert(proj_space);
- /* Assert that src_space and src_intersect_space have same extent and there
+ /* Assert that src_space and src_intersect_space have same rank and there
* are no point selections */
- HDassert(H5S_GET_EXTENT_NDIMS(src_space)
- == H5S_GET_EXTENT_NDIMS(src_intersect_space));
- HDassert(!HDmemcmp(src_space->extent.size, src_intersect_space->extent.size,
- (size_t)H5S_GET_EXTENT_NDIMS(src_space)
- * sizeof(src_space->extent.size[0])));
+ HDassert(H5S_GET_EXTENT_NDIMS(src_space) == H5S_GET_EXTENT_NDIMS(src_intersect_space));
+ HDassert(H5S_GET_SELECT_NPOINTS(src_space) == H5S_GET_SELECT_NPOINTS(dst_space));
HDassert(H5S_GET_SELECT_TYPE(src_space) != H5S_SEL_POINTS);
HDassert(H5S_GET_SELECT_TYPE(dst_space) != H5S_SEL_POINTS);
- HDassert(H5S_GET_SELECT_TYPE(src_intersect_space) != H5S_SEL_POINTS);
-
- /* Initialize prev_space, curr_span_tree, and curr_span_up_dim */
- for(i = 0; i < H5S_MAX_RANK; i++) {
- curr_span_tree[i] = NULL;
- prev_span[i] = NULL;
- curr_span_up_dim[i] = (hsize_t)0;
- } /* end for */
-
- /* Save rank of projected space */
- proj_rank = proj_space->extent.rank;
- HDassert(proj_rank > 0);
-
- /* Get numbers of elements */
- ss_nelem = (size_t)H5S_GET_SELECT_NPOINTS(src_space);
- ds_nelem = (size_t)H5S_GET_SELECT_NPOINTS(dst_space);
- sis_nelem = (size_t)H5S_GET_SELECT_NPOINTS(src_intersect_space);
- HDassert(ss_nelem == ds_nelem);
-
- /* Calculate proj_down_dims (note loop relies on unsigned i wrapping around)
- */
- if(H5VM_array_down(proj_rank, proj_space->extent.size, proj_down_dims) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTSET, FAIL, "can't compute 'down' chunk size value")
-
- /* Remove current selection from proj_space */
- if(H5S_SELECT_RELEASE(proj_space) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
+ HDassert(H5S_GET_SELECT_TYPE(src_intersect_space) == H5S_SEL_HYPERSLABS);
- /* 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;
+ /* Set up ss_span_info */
+ if(H5S_GET_SELECT_TYPE(src_space) == H5S_SEL_HYPERSLABS) {
+ /* Make certain the selection has a span tree */
+ if(NULL == src_space->select.sel_info.hslab->span_lst)
+ if(H5S__hyper_generate_spans((H5S_t *)src_space) < 0) /* Casting away const OK -NAF */
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "can't construct span tree for source hyperslab selection")
- /* Allocate space for the hyperslab selection information (note this sets
- * diminfo arrays to 0, and span list to NULL)
- */
- if((proj_space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)) == NULL)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info")
- proj_space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
-
- /* Set selection type */
- proj_space->select.type = H5S_sel_hyper;
-
- /* Set unlim_dim */
- proj_space->select.sel_info.hslab->unlim_dim = -1;
-
- /* Allocate the source space iterator */
- if(NULL == (ss_iter = H5FL_MALLOC(H5S_sel_iter_t)))
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate source space iterator")
-
- /* Initialize source space iterator */
- if(H5S_select_iter_init(ss_iter, src_space, (size_t)1) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
- ss_iter_init = TRUE;
-
- /* Get sequence list for source space */
- if(H5S_SELECT_GET_SEQ_LIST(src_space, 0u, ss_iter, H5S_PROJECT_INTERSECT_NSEQS, ss_nelem, &ss_nseq, &nelem, ss_off, ss_len) < 0)
- HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
- ss_nelem -= nelem;
- HDassert(ss_nseq > 0);
-
- /* Allocate the destination space iterator */
- if(NULL == (ds_iter = H5FL_MALLOC(H5S_sel_iter_t)))
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate destination space iterator")
-
- /* Initialize destination space iterator */
- if(H5S_select_iter_init(ds_iter, dst_space, (size_t)1) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
- ds_iter_init = TRUE;
-
- /* Get sequence list for destination space */
- if(H5S_SELECT_GET_SEQ_LIST(dst_space, 0u, ds_iter, H5S_PROJECT_INTERSECT_NSEQS, ds_nelem, &ds_nseq, &nelem, ds_off, ds_len) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
- ds_nelem -= nelem;
- HDassert(ds_nseq > 0);
-
- /* Allocate the source intersect space iterator */
- if(NULL == (sis_iter = H5FL_MALLOC(H5S_sel_iter_t)))
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate source intersect space iterator")
-
- /* Initialize source intersect space iterator */
- if(H5S_select_iter_init(sis_iter, src_intersect_space, (size_t)1) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection iterator")
- sis_iter_init = TRUE;
-
- /* Get sequence list for source intersect space */
- if(H5S_SELECT_GET_SEQ_LIST(src_intersect_space, 0u, sis_iter, H5S_PROJECT_INTERSECT_NSEQS, sis_nelem, &sis_nseq, &nelem, sis_off, sis_len) < 0)
- HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
- sis_nelem -= nelem;
- HDassert(sis_nseq > 0);
-
- /* Loop until we run out of sequences in either the source or source
- * intersect space */
- while(1) {
- while(advance_ss || (ss_off[ss_i] + ss_len[ss_i] <= sis_off[sis_i])) {
- /* Either we finished the current source sequence or the
- * sequences do not intersect. Advance source space. */
- ss_sel_off += (hsize_t)ss_len[ss_i];
- if(++ss_i == ss_nseq) {
- if(ss_nelem > 0) {
- /* Try to grab more sequences from src_space */
- if(H5S_SELECT_GET_SEQ_LIST(src_space, 0u, ss_iter, H5S_PROJECT_INTERSECT_NSEQS, ss_nelem, &ss_nseq, &nelem, ss_off, ss_len) < 0)
- HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
- HDassert(ss_len[0] > 0);
-
- /* Update ss_nelem */
- HDassert(nelem > 0);
- HDassert(nelem <= ss_nelem);
- ss_nelem -= nelem;
-
- /* Reset source space index */
- ss_i = 0;
- } /* end if */
- else
- /* There are no more sequences in src_space, so we can exit
- * the loop. Use goto instead of break so we exit the outer
- * loop. */
- goto loop_end;
- } /* end if */
-
- /* Reset advance_ss */
- advance_ss = FALSE;
- } /* end if */
- if(advance_sis
- || (sis_off[sis_i] + sis_len[sis_i] <= ss_off[ss_i])) {
- do {
- /* Either we finished the current source intersect sequence or
- * the sequences do not intersect. Advance source intersect
- * space. */
- if(++sis_i == sis_nseq) {
- if(sis_nelem > 0) {
- /* Try to grab more sequences from src_intersect_space
- */
- if(H5S_SELECT_GET_SEQ_LIST(src_intersect_space, 0u, sis_iter, H5S_PROJECT_INTERSECT_NSEQS, sis_nelem, &sis_nseq, &nelem, sis_off, sis_len) < 0)
- HGOTO_ERROR(H5E_INTERNAL, H5E_UNSUPPORTED, FAIL, "sequence length generation failed")
- HDassert(sis_len[0] > 0);
-
- /* Update ss_nelem */
- HDassert(nelem > 0);
- HDassert(nelem <= sis_nelem);
- sis_nelem -= nelem;
-
- /* Reset source space index */
- sis_i = 0;
- } /* end if */
- else
- /* There are no more sequences in src_intersect_space,
- * so we can exit the loop. Use goto instead of break
- * so we exit the outer loop. */
- goto loop_end;
- } /* end if */
- } while(sis_off[sis_i] + sis_len[sis_i] <= ss_off[ss_i]);
-
- /* 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_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ /* Simply point to existing span tree */
+ ss_span_info = src_space->select.sel_info.hslab->span_lst;
+ } /* end if */
+ else {
+ /* Create temporary span tree from all selection */
+ HDassert(H5S_GET_SELECT_TYPE(src_space) == H5S_SEL_ALL);
- /* Reset lower dimension's span tree and previous
- * span since we just committed it and will start
- * over with a new one */
- if(H5S__hyper_free_span_info(curr_span_tree[i]) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free span info")
- curr_span_tree[i] = NULL;
- prev_span[i] = NULL;
- } /* end if */
+ if(NULL == (ss_span_info_buf = H5S__hyper_make_spans(H5S_GET_EXTENT_NDIMS(src_space),
+ H5S_hyper_zeros_g, H5S_hyper_zeros_g, H5S_hyper_ones_g, src_space->extent.size)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't create span tree for ALL source space")
+ ss_span_info = ss_span_info_buf;
+ } /* end else */
- /* Update curr_span_up_dim */
- curr_span_up_dim[i - 1] = proj_off / proj_down_dims[i - 1];
- } /* end for */
+ /* Set up ds_span_info */
+ if(H5S_GET_SELECT_TYPE(dst_space) == H5S_SEL_HYPERSLABS) {
+ /* Make certain the selection has a span tree */
+ if(NULL == dst_space->select.sel_info.hslab->span_lst)
+ if(H5S__hyper_generate_spans((H5S_t *)dst_space) < 0) /* Casting away const OK -NAF */
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "can't construct span tree for dsetination hyperslab selection")
- /* Compute bounds for new span in lowest dimension */
- low = proj_off % proj_space->extent.size[proj_rank - 1];
- span_len = MIN(proj_len_rem,
- (size_t)(proj_space->extent.size[proj_rank - 1]
- - low));
- HDassert(proj_len_rem >= span_len);
- high = low + (hsize_t)span_len - (hsize_t)1;
+ /* Simply point to existing span tree */
+ ds_span_info = dst_space->select.sel_info.hslab->span_lst;
+ } /* end if */
+ else {
+ /* Create temporary span tree from all selection */
+ HDassert(H5S_GET_SELECT_TYPE(dst_space) == H5S_SEL_ALL);
- /* Append span in lowest dimension */
- if(H5S__hyper_append_span(&prev_span[proj_rank - 1], &curr_span_tree[proj_rank - 1], low, high, NULL, NULL) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ if(NULL == (ds_span_info_buf = H5S__hyper_make_spans(H5S_GET_EXTENT_NDIMS(dst_space),
+ H5S_hyper_zeros_g, H5S_hyper_zeros_g, H5S_hyper_ones_g, dst_space->extent.size)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "can't create span tree for ALL destination space")
+ ds_span_info = ds_span_info_buf;
+ } /* end else */
- /* Update remaining offset and length */
- proj_off += (hsize_t)span_len;
- proj_len_rem -= span_len;
- } /* end while */
+ /* Make certain the source intersect selection has a span tree */
+ if(NULL == src_intersect_space->select.sel_info.hslab->span_lst)
+ if(H5S__hyper_generate_spans((H5S_t *)src_intersect_space) < 0) /* Casting away const OK -NAF */
+ HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "can't construct span tree for source intersect hyperslab selection")
+
+ /* Initialize udata */
+ /* We will use op_info[0] for nelem and op_info[1] for copied spans */
+ HDmemset(&udata, 0, sizeof(udata));
+ udata.ds_span[0] = ds_span_info->head;
+ udata.ds_low[0] = udata.ds_span[0]->low;
+ udata.ss_rank = H5S_GET_EXTENT_NDIMS(src_space);
+ udata.ds_rank = H5S_GET_EXTENT_NDIMS(dst_space);
+ udata.op_gen = H5S__hyper_get_op_gen();
+ udata.share_selection = share_selection;
+
+ /* Iterate over selections and build projected span tree */
+ if(H5S__hyper_proj_int_iterate(ss_span_info, src_intersect_space->select.sel_info.hslab->span_lst, 1, 0, &udata) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOMPARE, FAIL, "selection iteration failed")
- /* Update intersection sequence */
- int_sel_off += (hsize_t)proj_len;
- int_len -= proj_len;
- } /* end while */
- } /* end else */
- } /* end while */
+ /* Remove current selection from proj_space */
+ if(H5S_SELECT_RELEASE(proj_space) < 0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
-loop_end:
- /* Add remaining spans to span tree */
- for(i = proj_rank - 1; i > 0; i--)
- if(curr_span_tree[i]) {
- HDassert(prev_span[i]);
+ /* Check for elements in projected space */
+ if(udata.ps_span_info[0]) {
+ /* Allocate space for the hyperslab selection information (note this sets
+ * diminfo_valid to FALSE, diminfo arrays to 0, and span list to NULL) */
+ if(NULL == (proj_space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)))
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab info")
- /* Append remaining span tree to higher dimension */
- low = curr_span_up_dim[i - 1] % proj_space->extent.size[i - 1];
- if(H5S__hyper_append_span(&prev_span[i - 1], &curr_span_tree[i - 1], low, low, curr_span_tree[i], NULL) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTAPPEND, FAIL, "can't allocate hyperslab span")
+ /* Set selection type */
+ proj_space->select.type = H5S_sel_hyper;
- /* Reset span tree */
- if(H5S__hyper_free_span_info(curr_span_tree[i]) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free span info")
- curr_span_tree[i] = NULL;
- } /* end if */
+ /* Set unlim_dim */
+ proj_space->select.sel_info.hslab->unlim_dim = -1;
- /* Add span tree to proj_space */
- if(curr_span_tree[0]) {
- proj_space->select.sel_info.hslab->span_lst = curr_span_tree[0];
- curr_span_tree[0] = NULL;
+ /* Set span tree */
+ proj_space->select.sel_info.hslab->span_lst = udata.ps_span_info[0];
+ udata.ps_span_info[0] = NULL;
/* Set the number of elements in current selection */
proj_space->select.num_elem = H5S__hyper_spans_nelem(proj_space->select.sel_info.hslab->span_lst);
- /* Attempt to rebuild "optimized" start/stride/count/block information.
- * from resulting hyperslab span tree */
+ /* Attempt to build "optimized" start/stride/count/block information
+ * from resulting hyperslab span tree.
+ */
H5S__hyper_rebuild(proj_space);
} /* end if */
else
@@ -9699,154 +11425,42 @@ loop_end:
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't convert selection")
done:
- /* Release source selection iterator */
- if(ss_iter_init && H5S_SELECT_ITER_RELEASE(ss_iter) < 0)
- HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
- if(ss_iter)
- ss_iter = H5FL_FREE(H5S_sel_iter_t, ss_iter);
-
- /* Release destination selection iterator */
- if(ds_iter_init && H5S_SELECT_ITER_RELEASE(ds_iter) < 0)
- HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
- if(ds_iter)
- ds_iter = H5FL_FREE(H5S_sel_iter_t, ds_iter);
-
- /* Release source intersect selection iterator */
- if(sis_iter_init && H5S_SELECT_ITER_RELEASE(sis_iter) < 0)
- HDONE_ERROR(H5E_DATASPACE, H5E_CANTRELEASE, FAIL, "unable to release selection iterator")
- if(sis_iter)
- sis_iter = H5FL_FREE(H5S_sel_iter_t, sis_iter);
+ /* Free ss_span_info_buf */
+ if(ss_span_info_buf) {
+ H5S__hyper_free_span_info(ss_span_info_buf);
+ ss_span_info_buf = NULL;
+ } /* end if */
+
+ /* Free ds_span_info_buf */
+ if(ds_span_info_buf) {
+ H5S__hyper_free_span_info(ds_span_info_buf);
+ ds_span_info_buf = NULL;
+ } /* end if */
/* Cleanup on error */
if(ret_value < 0) {
- /* Remove current selection from proj_space */
- if(H5S_SELECT_RELEASE(proj_space) < 0)
- HDONE_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
+ unsigned u;
/* Free span trees */
- for(i = 0; i < proj_rank; i++)
- if(curr_span_tree[i]) {
- if(H5S__hyper_free_span_info(curr_span_tree[i]) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTFREE, FAIL, "can't free span info")
- curr_span_tree[i] = NULL;
+ for(u = 0; u < udata.ds_rank; u++)
+ if(udata.ps_span_info[u]) {
+ H5S__hyper_free_span_info(udata.ps_span_info[u]);
+ udata.ps_span_info[u] = NULL;
} /* end if */
} /* end if */
- FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5S__hyper_project_intersection() */
-
-
-/*--------------------------------------------------------------------------
- NAME
- H5S__hyper_subtract
- PURPOSE
- Subtract one hyperslab selection from another
- USAGE
- herr_t H5S__hyper_subtract(space,subtract_space)
- H5S_t *space; IN/OUT: Selection to be operated on
- H5S_t *subtract_space; IN: Selection that will be subtracted from space
- RETURNS
- Non-negative on success/Negative on failure.
- DESCRIPTION
- Removes any and all portions of space that are also present in
- subtract_space. In essence, performs an A_NOT_B operation with the
- two selections.
-
- Note this function basically duplicates a subset of the functionality
- of H5S_select_select(). It should probably be removed when that
- function is enabled.
- GLOBAL VARIABLES
- COMMENTS, BUGS, ASSUMPTIONS
- EXAMPLES
- REVISION LOG
---------------------------------------------------------------------------*/
-herr_t
-H5S__hyper_subtract(H5S_t *space, H5S_t *subtract_space)
-{
- H5S_hyper_span_info_t *a_not_b = NULL; /* Span tree for hyperslab spans in old span tree and not in new span tree */
- H5S_hyper_span_info_t *a_and_b = NULL; /* Span tree for hyperslab spans in both old and new span trees */
- H5S_hyper_span_info_t *b_not_a = NULL; /* Span tree for hyperslab spans in new span tree and not in old span tree */
- herr_t ret_value = SUCCEED; /* Return value */
-
- FUNC_ENTER_NOAPI_NOINIT
-
- /* Check args */
- HDassert(space);
- HDassert(subtract_space);
-
- /* Check that the space selections both have span trees */
- if(space->select.sel_info.hslab->span_lst == NULL)
- if(H5S__hyper_generate_spans(space) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
- if(subtract_space->select.sel_info.hslab->span_lst == NULL)
- if(H5S__hyper_generate_spans(subtract_space) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_UNINITIALIZED, FAIL, "dataspace does not have span tree")
-
- /* Generate lists of spans which overlap and don't overlap */
- if(H5S__hyper_clip_spans(space->select.sel_info.hslab->span_lst, subtract_space->select.sel_info.hslab->span_lst, &a_not_b, &a_and_b, &b_not_a)<0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information")
-
- /* Reset the other dataspace selection information */
- if(H5S_SELECT_RELEASE(space) < 0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release selection")
-
- /* Allocate space for the hyperslab selection information */
- if((space->select.sel_info.hslab = H5FL_CALLOC(H5S_hyper_sel_t)) == NULL)
- HGOTO_ERROR(H5E_DATASPACE, H5E_NOSPACE, FAIL, "can't allocate hyperslab info")
- space->select.sel_info.hslab->diminfo_valid = H5S_DIMINFO_VALID_NO;
-
- /* Set unlim_dim */
- space->select.sel_info.hslab->unlim_dim = -1;
-
- /* Check for anything returned in a_not_b */
- if(a_not_b) {
- /* Update spans in space */
- space->select.sel_info.hslab->span_lst = a_not_b;
- a_not_b = NULL;
-
- /* Update number of elements */
- space->select.num_elem = H5S__hyper_spans_nelem(space->select.sel_info.hslab->span_lst);
-
- /* Attempt to rebuild "optimized" start/stride/count/block information.
- * from resulting hyperslab span tree */
- H5S__hyper_rebuild(space);
- } /* end if */
- else {
- H5S_hyper_span_info_t *spans; /* Empty hyperslab span tree */
-
- /* Set number of elements */
- space->select.num_elem = 0;
+#ifndef NDEBUG
+ /* Verify there are no more span trees */
+ {
+ unsigned u;
- /* Allocate a span info node */
- if(NULL == (spans = H5FL_MALLOC(H5S_hyper_span_info_t)))
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTALLOC, FAIL, "can't allocate hyperslab span")
-
- /* Set the reference count */
- spans->count = 1;
-
- /* Reset the scratch pad space */
- spans->scratch = 0;
-
- /* Set to empty tree */
- spans->head = NULL;
-
- /* Set pointer to empty span tree */
- space->select.sel_info.hslab->span_lst = spans;
- } /* end if */
-
-done:
- /* Free span trees */
- if(a_and_b)
- H5S__hyper_free_span_info(a_and_b);
- if(b_not_a)
- H5S__hyper_free_span_info(b_not_a);
- if(a_not_b) {
- HDassert(ret_value < 0);
- H5S__hyper_free_span_info(b_not_a);
- } /* end if */
+ for(u = 0; u < H5S_MAX_RANK; u++)
+ HDassert(!udata.ps_span_info[u]);
+ } /* end block */
+#endif /* NDEBUG */
FUNC_LEAVE_NOAPI(ret_value)
-} /* end H5S__hyper_subtract() */
+} /* end H5S__hyper_project_intersection() */
/*--------------------------------------------------------------------------
@@ -10018,6 +11632,13 @@ H5S_hyper_clip_unlim(H5S_t *space, hsize_t clip_size)
hslab->diminfo_valid = H5S_DIMINFO_VALID_YES;
} /* end else */
+ /* Update the upper bound, if the diminfo is valid */
+ if(hslab && (H5S_DIMINFO_VALID_YES == hslab->diminfo_valid))
+ hslab->diminfo.high_bounds[orig_unlim_dim] =
+ hslab->diminfo.opt[orig_unlim_dim].start +
+ hslab->diminfo.opt[orig_unlim_dim].stride * (hslab->diminfo.opt[orig_unlim_dim].count - 1) +
+ (hslab->diminfo.opt[orig_unlim_dim].block - 1);
+
done:
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5S_hyper_clip_unlim() */