summaryrefslogtreecommitdiffstats
path: root/src/H5Shyper.c
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@hdfgroup.org>2001-11-02 20:31:35 (GMT)
committerQuincey Koziol <koziol@hdfgroup.org>2001-11-02 20:31:35 (GMT)
commit1cd9eb7e0d282aaf5161af220aae00cc7f7e31f9 (patch)
tree90c364175d9336948f7f98ec7c632494af48edb3 /src/H5Shyper.c
parente9d955be61f79ceddd6be3d279f723d8e9153b9b (diff)
downloadhdf5-1cd9eb7e0d282aaf5161af220aae00cc7f7e31f9.zip
hdf5-1cd9eb7e0d282aaf5161af220aae00cc7f7e31f9.tar.gz
hdf5-1cd9eb7e0d282aaf5161af220aae00cc7f7e31f9.tar.bz2
[svn-r4586] Purpose:
Code speedups, etc. Description: Bring in new algorithms and data structures for dealing with hyperslabs. This speeds up the hyperslab I/O for non-regular hyperslabs by a huge amount. Currently, the new API functions are ifdef'ed out, pending discussion and consensus approval. Platforms tested: FreeBSD 4.4 (hawkwind)
Diffstat (limited to 'src/H5Shyper.c')
-rw-r--r--src/H5Shyper.c7777
1 files changed, 5168 insertions, 2609 deletions
diff --git a/src/H5Shyper.c b/src/H5Shyper.c
index 175d0c6..c0a51e4 100644
--- a/src/H5Shyper.c
+++ b/src/H5Shyper.c
@@ -27,25 +27,6 @@
static int interface_initialize_g = 0;
/* Local datatypes */
-/* Parameter block for H5S_hyper_fread, H5S_hyper_fwrite, H5S_hyper_mread & H5S_hyper_mwrite */
-typedef struct {
- H5F_t *f;
- const struct H5O_layout_t *layout;
- const struct H5O_pline_t *pline;
- const struct H5O_fill_t *fill;
- const struct H5O_efl_t *efl;
- size_t elmt_size;
- const H5S_t *space;
- H5S_sel_iter_t *iter;
- hsize_t nelmts;
- hid_t dxpl_id;
- const void *src;
- void *dst;
- hsize_t mem_size[H5O_LAYOUT_NDIMS];
- hssize_t offset[H5O_LAYOUT_NDIMS];
- hsize_t hsize[H5O_LAYOUT_NDIMS];
-} H5S_hyper_io_info_t;
-
/* Parameter block for H5S_hyper_select_iter_mem */
typedef struct {
hid_t dt;
@@ -53,62 +34,40 @@ typedef struct {
const H5S_t *space;
H5S_sel_iter_t *iter;
void *src;
- hsize_t mem_size[H5O_LAYOUT_NDIMS];
- hssize_t mem_offset[H5O_LAYOUT_NDIMS];
H5D_operator_t op;
void * op_data;
} H5S_hyper_iter_info_t;
/* Static function prototypes */
-static H5S_hyper_region_t * H5S_hyper_get_regions (size_t *num_regions,
- unsigned rank, unsigned dim, size_t bound_count,
- H5S_hyper_bound_t **lo_bounds, hssize_t *pos, hssize_t *offset);
-static hsize_t H5S_hyper_fread (int dim, H5S_hyper_io_info_t *io_info);
-static hsize_t H5S_hyper_fread_opt (H5F_t *f, const struct H5O_layout_t *layout,
- const struct H5O_pline_t *pline, const struct H5O_fill_t *fill,
+static herr_t H5S_hyper_init (const H5S_t *space, size_t elmt_size, H5S_sel_iter_t *iter);
+static hsize_t H5S_hyper_favail (const H5S_t UNUSED *space,
+ const H5S_sel_iter_t *sel_iter, hsize_t max);
+static hsize_t H5S_hyper_fgath (H5F_t *f, const struct H5O_layout_t *layout,
+ const struct H5O_pline_t *pline,
+ const struct H5O_fill_t *fill,
const struct H5O_efl_t *efl, size_t elmt_size,
const H5S_t *file_space, H5S_sel_iter_t *file_iter,
hsize_t nelmts, hid_t dxpl_id, void *_buf/*out*/);
-static hsize_t H5S_hyper_fwrite (int dim,
- H5S_hyper_io_info_t *io_info);
-static hsize_t H5S_hyper_fwrite_opt (H5F_t *f, const struct H5O_layout_t *layout,
- const struct H5O_pline_t *pline, const struct H5O_fill_t *fill,
+static herr_t H5S_hyper_fscat (H5F_t *f, const struct H5O_layout_t *layout,
+ const struct H5O_pline_t *pline,
+ const struct H5O_fill_t *fill,
const struct H5O_efl_t *efl, size_t elmt_size,
const H5S_t *file_space, H5S_sel_iter_t *file_iter,
hsize_t nelmts, hid_t dxpl_id, const void *_buf);
-static herr_t H5S_hyper_init (const H5S_t *space, H5S_sel_iter_t *iter);
-static hsize_t H5S_hyper_favail (const H5S_t *space, const H5S_sel_iter_t *iter,
- hsize_t max);
-static hsize_t H5S_hyper_fgath (H5F_t *f, const struct H5O_layout_t *layout,
- const struct H5O_pline_t *pline,
- const struct H5O_fill_t *fill,
- const struct H5O_efl_t *efl, size_t elmt_size,
- const H5S_t *file_space,
- H5S_sel_iter_t *file_iter, hsize_t nelmts,
- hid_t dxpl_id, void *buf/*out*/);
-static herr_t H5S_hyper_fscat (H5F_t *f, const struct H5O_layout_t *layout,
- const struct H5O_pline_t *pline,
- const struct H5O_fill_t *fill,
- const struct H5O_efl_t *efl, size_t elmt_size,
- const H5S_t *file_space,
- H5S_sel_iter_t *file_iter, hsize_t nelmts,
- hid_t dxpl_id, const void *buf);
-static hsize_t H5S_hyper_mread (int dim, H5S_hyper_io_info_t *io_info);
-static hsize_t H5S_hyper_mread_opt (const void *_buf, size_t elmt_size,
+static hsize_t H5S_hyper_mgath (const void *_buf, size_t elmt_size,
const H5S_t *mem_space, H5S_sel_iter_t *mem_iter,
hsize_t nelmts, void *_tconv_buf/*out*/);
-static hsize_t H5S_hyper_mgath (const void *_buf, size_t elmt_size,
- const H5S_t *mem_space,
- H5S_sel_iter_t *mem_iter, hsize_t nelmts,
- void *_tconv_buf/*out*/);
-static size_t H5S_hyper_mwrite (int dim, H5S_hyper_io_info_t *io_info);
-static hsize_t H5S_hyper_mwrite_opt (const void *_tconv_buf, size_t elmt_size,
+static herr_t H5S_hyper_mscat (const void *_tconv_buf, size_t elmt_size,
const H5S_t *mem_space, H5S_sel_iter_t *mem_iter,
hsize_t nelmts, void *_buf/*out*/);
-static herr_t H5S_hyper_mscat (const void *_tconv_buf, size_t elmt_size,
- const H5S_t *mem_space,
- H5S_sel_iter_t *mem_iter, hsize_t nelmts,
- void *_buf/*out*/);
+static herr_t H5S_hyper_free_span_info (H5S_hyper_span_info_t *span_info);
+static herr_t H5S_hyper_free_span (H5S_hyper_span_t *span);
+static H5S_hyper_span_info_t *H5S_hyper_copy_span (H5S_hyper_span_info_t *spans);
+static herr_t H5S_hyper_span_scratch (H5S_hyper_span_info_t *spans, void *scr_value);
+static herr_t H5S_hyper_span_precompute (H5S_hyper_span_info_t *spans, size_t elmt_size);
+static herr_t H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, const hssize_t start[],
+ const hsize_t stride[], const hsize_t count[],
+ const hsize_t block[]);
const H5S_fconv_t H5S_HYPER_FCONV[1] = {{
"hslab", /*name */
@@ -127,14 +86,14 @@ const H5S_mconv_t H5S_HYPER_MCONV[1] = {{
H5S_hyper_mscat, /*scatter */
}};
-/* Array for use with I/O algorithms which frequently need array of zeros */
-static const hssize_t zero[H5O_LAYOUT_NDIMS]={0}; /* Array of zeros */
+/* 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_node_t struct */
-H5FL_DEFINE_STATIC(H5S_hyper_node_t);
+/* Declare a free list to manage arrays of H5S_hyper_span_t */
+H5FL_ARR_DEFINE_STATIC(H5S_hyper_span_t,H5S_MAX_RANK);
-/* Declare a free list to manage the H5S_hyper_list_t struct */
-H5FL_DEFINE_STATIC(H5S_hyper_list_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 arrays of size_t */
H5FL_ARR_DEFINE_STATIC(size_t,-1);
@@ -142,57 +101,160 @@ H5FL_ARR_DEFINE_STATIC(size_t,-1);
/* Declare a free list to manage arrays of hsize_t */
H5FL_ARR_DEFINE_STATIC(hsize_t,-1);
-typedef H5S_hyper_bound_t *H5S_hyper_bound_ptr_t;
-/* Declare a free list to manage arrays of H5S_hyper_bound_ptr_t */
-H5FL_ARR_DEFINE_STATIC(H5S_hyper_bound_ptr_t,H5S_MAX_RANK);
-
/* Declare a free list to manage arrays of H5S_hyper_dim_t */
H5FL_ARR_DEFINE_STATIC(H5S_hyper_dim_t,H5S_MAX_RANK);
-/* Declare a free list to manage arrays of H5S_hyper_bound_t */
-H5FL_ARR_DEFINE_STATIC(H5S_hyper_bound_t,-1);
+#ifdef QAK
+static herr_t
+H5S_hyper_print_spans_helper(struct H5S_hyper_span_t *span,unsigned depth)
+{
+ struct H5S_hyper_span_t *tmp_span;
+
+ FUNC_ENTER(H5S_hyper_print_spans_helper, FAIL);
-/* Declare a free list to manage arrays of H5S_hyper_region_t */
-H5FL_ARR_DEFINE_STATIC(H5S_hyper_region_t,-1);
+ tmp_span=span;
+ while(tmp_span) {
+ printf("%s: depth=%u, span=%p, (%d, %d), nelem=%u, pstride=%u\n",FUNC,depth,tmp_span,(int)tmp_span->low,(int)tmp_span->high,(unsigned)tmp_span->nelem,(unsigned)tmp_span->pstride);
+ if(tmp_span->down && tmp_span->down->head) {
+ printf("%s: spans=%p, count=%u, scratch=%p, head=%p\n",FUNC,tmp_span->down,tmp_span->down->count,tmp_span->down->scratch,tmp_span->down->head);
+ H5S_hyper_print_spans_helper(tmp_span->down->head,depth+1);
+ } /* end if */
+ tmp_span=tmp_span->next;
+ } /* end while */
-/* Declare a free list to manage blocks of hyperslab data */
-H5FL_BLK_DEFINE_STATIC(hyper_block);
+ FUNC_LEAVE(SUCCEED);
+}
+
+static herr_t
+H5S_hyper_print_spans(const struct H5S_hyper_span_info_t *span_lst)
+{
+ FUNC_ENTER(H5S_hyper_print_spans, FAIL);
+
+ if(span_lst!=NULL) {
+ printf("%s: spans=%p, count=%u, scratch=%p, head=%p\n",FUNC,span_lst,span_lst->count,span_lst->scratch,span_lst->head);
+ H5S_hyper_print_spans_helper(span_lst->head,0);
+ } /* end if */
+
+ FUNC_LEAVE(SUCCEED);
+}
+#endif /* QAK */
/*-------------------------------------------------------------------------
* Function: H5S_hyper_init
*
- * Purpose: Initializes iteration information for hyperslab selection.
+ * Purpose: Initializes iteration information for hyperslab span tree selection.
*
* Return: non-negative on success, negative on failure.
*
* Programmer: Quincey Koziol
- * Tuesday, June 16, 1998
+ * Saturday, February 24, 2001
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
static herr_t
-H5S_hyper_init (const H5S_t *space, H5S_sel_iter_t *sel_iter)
+H5S_hyper_init (const H5S_t *space, size_t elmt_size, H5S_sel_iter_t *sel_iter)
{
+ H5S_hyper_span_info_t *spans; /* Pointer to hyperslab span info node */
+ unsigned u; /* Index variable */
+
FUNC_ENTER (H5S_hyper_init, FAIL);
/* Check args */
- assert (space && H5S_SEL_HYPERSLABS==space->select.type);
- assert (sel_iter);
+ assert(space && H5S_SEL_HYPERSLABS==space->select.type);
+ assert(sel_iter);
+ assert(space->select.sel_info.hslab.span_lst);
/* Initialize the number of points to iterate over */
sel_iter->hyp.elmt_left=space->select.num_elem;
+/* Initialize the information needed for non-regular hyperslab I/O */
+ /* Make a copy of the span tree to iterate over */
+ sel_iter->hyp.spans=H5S_hyper_copy_span(space->select.sel_info.hslab.span_lst);
+
+ /* Set the nelem & pstride values according to the element size */
+ H5S_hyper_span_precompute(sel_iter->hyp.spans,elmt_size);
+
+ /* Allocate the span tree pointers, span pointers and positions */
+ sel_iter->hyp.span = H5FL_ARR_ALLOC(H5S_hyper_span_t,space->extent.u.simple.rank,0);
+ sel_iter->hyp.off = H5FL_ARR_ALLOC(hsize_t,space->extent.u.simple.rank,0);
+
+ /* Initialize the starting span_info's and spans */
+ spans=sel_iter->hyp.spans;
+ for(u=0; u<space->extent.u.simple.rank; u++) {
+ /* Set the pointers to the initial span in each dimension */
+ assert(spans);
+ assert(spans->head);
+
+ /* Set the pointer to the first span in the list for this node */
+ sel_iter->hyp.span[u] = spans->head;
+
+ /* Set the initial offset to low bound of span */
+ sel_iter->hyp.off[u]=sel_iter->hyp.span[u]->low;
+
+ /* Get the pointer to the next level down */
+ spans=spans->head->down;
+ } /* end for */
+
+/* Initialize the information needed for regular hyperslab I/O */
/* Allocate the position & initialize to invalid location */
sel_iter->hyp.pos = H5FL_ARR_ALLOC(hsize_t,space->extent.u.simple.rank,0);
sel_iter->hyp.pos[0]=(-1);
H5V_array_fill(sel_iter->hyp.pos, sel_iter->hyp.pos, sizeof(hssize_t),
space->extent.u.simple.rank);
-
+
FUNC_LEAVE (SUCCEED);
} /* H5S_hyper_init() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_sel_iter_release
+ PURPOSE
+ Release "new" hyperslab selection iterator information for a dataspace
+ USAGE
+ herr_t H5S_hyper_sel_iter_release(sel_iter)
+ H5S_sel_iter_t *sel_iter; IN: Pointer to selection iterator
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Releases all information for a dataspace "new" hyperslab selection iterator
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_hyper_sel_iter_release (H5S_sel_iter_t *sel_iter)
+{
+ FUNC_ENTER (H5S_hyper_sel_iter_release, FAIL);
+
+ /* Check args */
+ assert (sel_iter);
+
+/* Release the information needed for non-regular hyperslab I/O */
+ /* Free the copy of the selections span tree */
+ if(sel_iter->hyp.spans!=NULL)
+ H5S_hyper_free_span_info(sel_iter->hyp.spans);
+
+ /* Release the array of pointers to span nodes */
+ if(sel_iter->hyp.span!=NULL)
+ H5FL_ARR_FREE(H5S_hyper_span_t,sel_iter->hyp.span);
+
+ /* Release the array of offsets */
+ if(sel_iter->hyp.off!=NULL)
+ H5FL_ARR_FREE(hsize_t,sel_iter->hyp.off);
+
+/* Release the information needed for regular hyperslab I/O */
+ /* Release the hyperslab position */
+ if(sel_iter->hyp.pos!=NULL)
+ H5FL_ARR_FREE(hsize_t,sel_iter->hyp.pos);
+
+ FUNC_LEAVE (SUCCEED);
+} /* H5S_hyper_sel_iter_release() */
+
/*-------------------------------------------------------------------------
* Function: H5S_hyper_favail
@@ -223,711 +285,541 @@ H5S_hyper_favail (const H5S_t * UNUSED space,
#endif /* QAK */
FUNC_LEAVE (MIN(sel_iter->hyp.elmt_left,max));
} /* H5S_hyper_favail() */
+
/*-------------------------------------------------------------------------
- * Function: H5S_hyper_compare_regions
+ * Function: H5S_hyper_iter_next
*
- * Purpose: Compares two regions for equality (regions must not overlap!)
+ * Purpose: Moves a hyperslab iterator to the beginning of the next sequence
+ * of elements to read. Handles walking off the end in all dimensions.
*
- * Return: an integer less than, equal to, or greater than zero if the
- * first region is considered to be respectively less than,
- * equal to, or greater than the second
+ * Return: Success: non-negative
+ * Failure: negative
*
* Programmer: Quincey Koziol
- * Friday, July 17, 1998
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-int
-H5S_hyper_compare_regions (const void *r1, const void *r2)
-{
- if (((const H5S_hyper_region_t *)r1)->start < ((const H5S_hyper_region_t *)r2)->start)
- return(-1);
- else if (((const H5S_hyper_region_t *)r1)->start > ((const H5S_hyper_region_t *)r2)->start)
- return(1);
- else
- return(0);
-} /* end H5S_hyper_compare_regions */
-
-/*-------------------------------------------------------------------------
- * Function: H5S_hyper_get_regions
- *
- * Purpose: Builds a sorted array of the overlaps in a dimension
- *
- * Return: Success: Pointer to valid array (num_regions parameter
- * set to array size)
- *
- * Failure: 0
+ * Friday, September 8, 2000
*
- * Programmer: Quincey Koziol
- * Monday, June 29, 1998
+ * Notes:
+ * Only used for the optimized hyperslab I/O routines
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
-static H5S_hyper_region_t *
-H5S_hyper_get_regions (size_t *num_regions, unsigned rank, unsigned dim,
- size_t bound_count, H5S_hyper_bound_t **lo_bounds, hssize_t *pos,
- hssize_t *offset)
+static int
+H5S_hyper_iter_next (const H5S_t *file_space, H5S_sel_iter_t *file_iter)
{
- H5S_hyper_region_t *ret_value=NULL; /* Pointer to array of regions to return */
- H5S_hyper_region_t *reg=NULL; /* Pointer to array of regions */
- H5S_hyper_bound_t *lo_bound_dim; /* Pointer to the boundary nodes for a given dimension */
- H5S_hyper_node_t *node; /* Region node for a given boundary */
- hssize_t *node_start,*node_end; /* Extra pointers to node's start & end arrays */
- hssize_t *tmp_pos,*tmp_off; /* Extra pointers into the position and offset arrays */
- hssize_t pos_dim,off_dim; /* The position & offset in the dimension passed in */
- size_t num_reg=0; /* Number of regions in array */
- int curr_reg=-1; /* The current region we are working with */
- int temp_dim; /* Temporary dim. holder */
- size_t i; /* Counters */
-
- FUNC_ENTER (H5S_hyper_get_regions, NULL);
-
- assert(num_regions);
- assert(lo_bounds);
- assert(pos);
-
-#ifdef QAK
- printf("%s: check 1.0, rank=%u, dim=%d\n",FUNC,rank,dim);
- for(i=0; i<rank; i++)
- printf("%s: %d - pos=%d, offset=%d\n",FUNC,i,(int)pos[i],offset!=NULL ? (int)offset[i] : 0);
-#endif /* QAK */
+ hsize_t iter_offset[H5O_LAYOUT_NDIMS];
+ hsize_t iter_count[H5O_LAYOUT_NDIMS];
+ int fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ int temp_dim; /* Temporary rank holder */
+ unsigned i; /* Counters */
+ unsigned ndims; /* Number of dimensions of dataset */
- /* Iterate over the blocks which fit the position, or all of the blocks, if pos[dim]==-1 */
- lo_bound_dim=lo_bounds[dim];
- pos_dim=pos[dim];
- off_dim=offset[dim];
-#ifdef QAK
- printf("%s: check 1.1, bound_count=%d, pos_dim=%d\n",FUNC,bound_count,(int)pos_dim);
-#endif /* QAK */
+ FUNC_ENTER (H5S_hyper_iter_next, FAIL);
- for(i=0; i<bound_count; i++,lo_bound_dim++) {
-#ifdef QAK
- printf("%s: check 1.2, i=%d, num_reg=%d, curr_reg=%d\n",FUNC,(int)i,(int)num_reg,(int)curr_reg);
- printf("%s: check 1.2.1, lo_bound_dim->bound=%d\n",FUNC,(int)lo_bound_dim->bound);
-#endif /* QAK */
- /* Check if each boundary overlaps in the higher dimensions */
- node=lo_bound_dim->node;
- if(pos_dim<0 || (node->end[dim]+off_dim)>=pos_dim) {
- temp_dim=(dim-1);
- if(temp_dim>=0) {
- node_start=node->start+temp_dim;
- node_end=node->end+temp_dim;
- tmp_pos=pos+temp_dim;
- tmp_off=offset+temp_dim;
- while(temp_dim>=0 && *tmp_pos>=(*node_start+*tmp_off) && *tmp_pos<=(*node_end+*tmp_off)) {
- temp_dim--;
- node_start--;
- node_end--;
- tmp_pos--;
- tmp_off--;
- } /* end while */
- } /* end if */
+ /* Set some useful rank information */
+ fast_dim=file_space->extent.u.simple.rank-1;
+ ndims=file_space->extent.u.simple.rank;
-#ifdef QAK
- printf("%s: check 1.3, i=%d, temp_dim=%d\n",FUNC,(int)i,(int)temp_dim);
-#endif /* QAK */
- /* Yes, all previous positions match, this is a valid region */
- if(temp_dim<0) {
-#ifdef QAK
- printf("%s: check 1.4, node->start[%d]=%d, node->end[%d]=%d\n",FUNC,(int)dim,(int)node->start[dim],(int)dim,(int)node->end[dim]);
-#endif /* QAK */
- /* Check if we've allocated the array yet */
- if(num_reg==0) {
- /* Allocate temporary buffer, big enough for worst case size */
- reg=H5FL_ARR_ALLOC(H5S_hyper_region_t,bound_count,0);
-
- /* Initialize with first region */
- reg[num_reg].start=MAX(node->start[dim],pos[dim])+offset[dim];
- reg[num_reg].end=node->end[dim]+offset[dim];
- reg[num_reg].node=node;
-
- /* Increment the number of regions */
- num_reg++;
- curr_reg++;
- } else {
- /* Try to merge regions together in all dimensions, except the final one */
- if(dim<(rank-1) && (node->start[dim]+offset[dim])<=(reg[curr_reg].end+1)) {
-#ifdef QAK
- printf("%s: check 1.4.1\n",FUNC);
-#endif /* QAK */
- reg[curr_reg].end=MAX(node->end[dim],reg[curr_reg].end)+offset[dim];
- } else { /* no overlap with previous region, add new region */
-#ifdef QAK
- printf("%s: check 1.4.2\n",FUNC);
-#endif /* QAK */
- /* Initialize with new region */
- reg[num_reg].start=node->start[dim]+offset[dim];
- reg[num_reg].end=node->end[dim]+offset[dim];
- reg[num_reg].node=node;
-
- /*
- * Increment the number of regions & the current
- * region.
- */
- num_reg++;
- curr_reg++;
- } /* end else */
- } /* end else */
- } /* end if */
- } /* end if */
+ /* Calculate the offset and block count for each dimension */
+ for(i=0; i<ndims; i++) {
+ iter_offset[i]=(file_iter->hyp.pos[i]-file_space->select.sel_info.hslab.diminfo[i].start)%file_space->select.sel_info.hslab.diminfo[i].stride;
+ iter_count[i]=(file_iter->hyp.pos[i]-file_space->select.sel_info.hslab.diminfo[i].start)/file_space->select.sel_info.hslab.diminfo[i].stride;
} /* end for */
- /* Save the number of regions we generated */
- *num_regions=num_reg;
-
- /* Set return value */
- ret_value=reg;
-
-#ifdef QAK
- printf("%s: check 10.0, reg=%p, num_reg=%d\n",
- FUNC,reg,num_reg);
- for(i=0; i<num_reg; i++)
- printf("%s: start[%d]=%d, end[%d]=%d\n",
- FUNC,i,(int)reg[i].start,i,(int)reg[i].end);
-#endif /* QAK */
-
- FUNC_LEAVE (ret_value);
-} /* end H5S_hyper_get_regions() */
-
-
-/*-------------------------------------------------------------------------
- * Function: H5S_hyper_block_cache
- *
- * Purpose: Cache a hyperslab block for reading or writing.
- *
- * Return: Non-negative on success/Negative on failure
- *
- * Programmer: Quincey Koziol
- * Monday, September 21, 1998
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-static herr_t
-H5S_hyper_block_cache (H5S_hyper_node_t *node,
- H5S_hyper_io_info_t *io_info, unsigned block_read)
-{
- hssize_t file_offset[H5O_LAYOUT_NDIMS]; /*offset of slab in file*/
- hsize_t hsize[H5O_LAYOUT_NDIMS]; /*size of hyperslab */
- unsigned u; /* Counters */
+ /* Start with the fastest changing dimension */
+ temp_dim=fast_dim;
+ while(temp_dim>=0) {
+ if(temp_dim==fast_dim) {
+ /* Move to the next block in the current dimension */
+ iter_offset[temp_dim]=0; /* reset the offset in the fastest dimension */
+ iter_count[temp_dim]++;
- FUNC_ENTER (H5S_hyper_block_cache, SUCCEED);
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(iter_count[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].count)
+ break;
+ else
+ iter_count[temp_dim]=0; /* reset back to the beginning of the line */
+ } /* end if */
+ else {
+ /* Move to the next row in the curent dimension */
+ iter_offset[temp_dim]++;
- assert(node);
- assert(io_info);
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(iter_offset[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].block)
+ break;
+ else {
+ /* Move to the next block in the current dimension */
+ iter_offset[temp_dim]=0;
+ iter_count[temp_dim]++;
- /* Allocate temporary buffer of proper size */
- if((node->cinfo.block=H5FL_BLK_ALLOC(hyper_block,(node->cinfo.size*io_info->elmt_size),0))==NULL)
- HRETURN_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
- "can't allocate hyperslab cache block");
+ /* If this block is still in the range of blocks to output for the dimension, break out of loop */
+ if(iter_count[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].count)
+ break;
+ else
+ iter_count[temp_dim]=0; /* reset back to the beginning of the line */
+ } /* end else */
+ } /* end else */
- /* Read in block, if we are read caching */
- if(block_read) {
- /* Copy the location of the region in the file */
- HDmemcpy(file_offset,node->start,(io_info->space->extent.u.simple.rank * sizeof(hssize_t)));
- file_offset[io_info->space->extent.u.simple.rank]=0;
-
- /* Set the hyperslab size to read */
- for(u=0; u<io_info->space->extent.u.simple.rank; u++)
- hsize[u]=(node->end[u]-node->start[u])+1;
- hsize[io_info->space->extent.u.simple.rank]=io_info->elmt_size;
-
- if (H5F_arr_read(io_info->f, io_info->dxpl_id,
- io_info->layout, io_info->pline,
- io_info->fill, io_info->efl, hsize, hsize,
- zero, file_offset, node->cinfo.block/*out*/)<0)
- HRETURN_ERROR (H5E_DATASPACE, H5E_READERROR, FAIL, "read error");
- } /* end if */
- else {
-/* keep information for writing block later? */
- } /* end else */
-
- /* Set up parameters for accessing block (starting the read and write information at the same point) */
- node->cinfo.wleft=node->cinfo.rleft=(unsigned)node->cinfo.size;
- node->cinfo.wpos=node->cinfo.rpos=node->cinfo.block;
+ /* Decrement dimension count */
+ temp_dim--;
+ } /* end while */
- /* Set cached flag */
- node->cinfo.cached=1;
+ /* Translate current iter_offset and iter_count into iterator position */
+ for(i=0; i<ndims; i++)
+ file_iter->hyp.pos[i]=file_space->select.sel_info.hslab.diminfo[i].start+(file_space->select.sel_info.hslab.diminfo[i].stride*iter_count[i])+iter_offset[i];
FUNC_LEAVE (SUCCEED);
-} /* H5S_hyper_block_cache() */
+} /* H5S_hyper_iter_next() */
+
/*-------------------------------------------------------------------------
- * Function: H5S_hyper_block_read
+ * Function: H5S_hyper_fread
*
- * Purpose: Read in data from a cached hyperslab block
+ * Purpose: Performs an optimized gather from the file, based on a hyperslab
+ * span tree.
*
- * Return: Non-negative on success/Negative on failure
+ * Return: Success: Number of elements copied.
+ * Failure: 0
*
* Programmer: Quincey Koziol
- * Monday, September 21, 1998
+ * Friday, September 8, 2000
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
-static herr_t
-H5S_hyper_block_read (H5S_hyper_node_t *node, H5S_hyper_io_info_t *io_info, hsize_t region_size)
+static hsize_t
+H5S_hyper_fread (H5F_t *f, const struct H5O_layout_t *layout,
+ const struct H5O_pline_t *pline,
+ const struct H5O_fill_t *fill,
+ const struct H5O_efl_t *efl, size_t elmt_size,
+ const H5S_t *space, H5S_sel_iter_t *iter,
+ hsize_t nelem, hid_t dxpl_id, void *_buf/*out*/)
{
- FUNC_ENTER (H5S_hyper_block_read, SUCCEED);
-
- assert(node && node->cinfo.cached);
- assert(io_info);
+ uint8_t *dst=(uint8_t *)_buf; /* Alias for pointer arithmetic */
+ H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */
+ H5S_hyper_span_t *curr_span; /* Current hyperslab span node */
+ hsize_t slab[H5O_LAYOUT_NDIMS]; /* Cumulative size of each dimension in bytes */
+ hsize_t acc; /* Accumulator for computing cumulative sizes */
+ hssize_t *abs_arr; /* Absolute hyperslab span position */
+ hssize_t *off_arr; /* Offset within the dataspace extent */
+ int fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ int curr_dim; /* Current dimension being operated on */
+ int ndims; /* Number of dimensions of dataset */
+ hsize_t loc_off; /* Element offset in the dataspace */
+ size_t span_size; /* Number of bytes in current span to actually process */
+ size_t io_bytes_left; /* Number of bytes left to process */
+ int i; /* Index variable */
+ size_t *seq_len_arr=NULL; /* Array of sequence lengths */
+ hsize_t *buf_off_arr=NULL; /* Array of dataset offsets */
+ size_t last_io_bytes_left=0; /* Last I/O bytes left before readv() called */
+ size_t nseq=0; /* Number of sequence/offsets stored in the arrays */
+ size_t vector_size; /* Value for vector size */
+ hssize_t ret_value=FAIL;
- /* Copy the elements into the user's buffer */
- /*
- !! NOTE !! This will need to be changed for different dimension
- permutations from the standard 'C' ordering!
- */
+ FUNC_ENTER (H5S_hyper_fread, 0);
#ifdef QAK
- printf("%s: check 1.0, io_info->dst=%p, node->cinfo.rpos=%p, region_size=%lu, io_info->elmt_size=%lu\n",FUNC,io_info->dst,node->cinfo.rpos,(unsigned long)region_size,(unsigned long)io_info->elmt_size);
+printf("%s: Called!\n",FUNC);
#endif /* QAK */
- HDmemcpy(io_info->dst, node->cinfo.rpos, (size_t)(region_size*io_info->elmt_size));
- /*
- * Decrement the number of elements left in block to read & move the
- * offset
- */
- node->cinfo.rpos+=region_size*io_info->elmt_size;
- node->cinfo.rleft-=region_size;
+ /* Check args */
+ assert(f);
+ assert(layout);
+ assert(pline);
+ assert(fill);
+ assert(efl);
+ assert(elmt_size>0);
+ assert(space);
+ assert(iter);
+ assert(nelem>0);
+ assert(dst);
- /* If we've read in all the elements from the block, throw it away */
- if(node->cinfo.rleft==0 && (node->cinfo.wleft==0 || node->cinfo.wleft==node->cinfo.size)) {
- /* Release the temporary buffer */
- H5FL_BLK_FREE(hyper_block,node->cinfo.block);
+ /* Set the rank of the fastest changing dimension */
+ ndims=space->extent.u.simple.rank;
+ fast_dim=(ndims-1);
+
+ /* Get the pointers to the current span info and span nodes */
+ curr_span=iter->hyp.span[fast_dim];
+ abs_arr=iter->hyp.off;
+ off_arr=space->select.offset;
+ ispan=iter->hyp.span;
+
+ /* Set the amount of elements to perform I/O on, etc. */
+ assert(nelem==(hsize_t)((size_t)(nelem))); /*check for overflow*/
+ io_bytes_left=nelem*elmt_size;
+
+ /* Compute the cumulative size of dataspace dimensions */
+ for(i=fast_dim, acc=elmt_size; i>=0; i--) {
+ slab[i]=acc;
+ acc*=space->extent.u.simple.size[i];
+ } /* end for */
- /* Reset the caching flag for next time */
- node->cinfo.cached=0;
- } /* end if */
+ /* Set the offset of the first element iterated on */
+ for(i=0, loc_off=0; i<ndims; i++)
+ /* Compute the sequential element offset */
+ loc_off+=(abs_arr[i]+space->select.offset[i])*slab[i];
- FUNC_LEAVE (SUCCEED);
-} /* H5S_hyper_block_read() */
-
-/*-------------------------------------------------------------------------
- * Function: H5S_hyper_block_write
- *
- * Purpose: Write out data to a cached hyperslab block
- *
- * Return: Non-negative on success/Negative on failure
- *
- * Programmer: Quincey Koziol
- * Monday, September 21, 1998
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-static herr_t
-H5S_hyper_block_write (H5S_hyper_node_t *node,
- H5S_hyper_io_info_t *io_info,
- hsize_t region_size)
-{
- hssize_t file_offset[H5O_LAYOUT_NDIMS]; /*offset of slab in file*/
- hsize_t hsize[H5O_LAYOUT_NDIMS]; /*size of hyperslab */
- unsigned u; /* Counters */
+ /* Get the hyperslab vector size */
+ if (H5P_get(dxpl_id,H5D_XFER_HYPER_VECTOR_SIZE_NAME,&vector_size)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, 0, "unable to get value");
- FUNC_ENTER (H5S_hyper_block_write, SUCCEED);
+ /* Allocate the vector I/O arrays */
+ if((seq_len_arr = H5FL_ARR_ALLOC(size_t,vector_size,0))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate vector I/O array");
+ if((buf_off_arr = H5FL_ARR_ALLOC(hsize_t,vector_size,0))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate vector I/O array");
- assert(node && node->cinfo.cached);
- assert(io_info);
+ /* Range check against number of elements left in selection */
+ assert(io_bytes_left<=(iter->hyp.elmt_left*elmt_size));
- /* Copy the elements into the user's buffer */
- /*
- !! NOTE !! This will need to be changed for different dimension
- permutations from the standard 'C' ordering!
- */
- HDmemcpy(node->cinfo.wpos, io_info->src, (size_t)(region_size*io_info->elmt_size));
+ /* Take care of any partial spans leftover from previous I/Os */
+ if(abs_arr[fast_dim]!=curr_span->low) {
- /*
- * Decrement the number of elements left in block to read & move the
- * offset
- */
- node->cinfo.wpos+=region_size*io_info->elmt_size;
- node->cinfo.wleft-=region_size;
+ /* Finish the span in the fastest changing dimension */
- /* If we've read in all the elements from the block, throw it away */
- if(node->cinfo.wleft==0 && (node->cinfo.rleft==0 || node->cinfo.rleft==node->cinfo.size)) {
- /* Copy the location of the region in the file */
- HDmemcpy(file_offset, node->start, (io_info->space->extent.u.simple.rank * sizeof(hssize_t)));
- file_offset[io_info->space->extent.u.simple.rank]=0;
+ /* Compute the number of bytes to attempt in this span */
+ span_size=((curr_span->high-abs_arr[fast_dim])+1)*elmt_size;
- /* Set the hyperslab size to write */
- for(u=0; u<io_info->space->extent.u.simple.rank; u++)
- hsize[u]=(node->end[u]-node->start[u])+1;
- hsize[io_info->space->extent.u.simple.rank]=io_info->elmt_size;
+ /* Check number of bytes against upper bounds allowed */
+ if(span_size>io_bytes_left)
+ span_size=io_bytes_left;
- if (H5F_arr_write(io_info->f, io_info->dxpl_id, io_info->layout,
- io_info->pline, io_info->fill, io_info->efl, hsize,
- hsize, zero, file_offset,
- node->cinfo.block/*out*/)<0)
- HRETURN_ERROR (H5E_DATASPACE, H5E_WRITEERROR, FAIL, "write error");
+ if (H5F_seq_read(f, dxpl_id, layout, pline, fill, efl, space,
+ elmt_size, span_size, loc_off, dst/*out*/)<0) {
+ HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error");
+ }
- /* Release the temporary buffer */
- H5FL_BLK_FREE(hyper_block,node->cinfo.block);
+ /* Increment offset in destination */
+ dst+=span_size;
- /* Reset the caching flag for next time */
- node->cinfo.cached=0;
- } /* end if */
+ /* Decrement I/O left to perform */
+ io_bytes_left-=span_size;
- FUNC_LEAVE (SUCCEED);
-} /* H5S_hyper_block_write() */
+ /* Check if we are done */
+ if(io_bytes_left>0) {
+ /* Move to next span in fastest changing dimension */
+ curr_span=curr_span->next;
-
-/*-------------------------------------------------------------------------
- * Function: H5S_hyper_fread
- *
- * Purpose: Recursively gathers data points from a file using the
- * parameters passed to H5S_hyper_fgath.
- *
- * Return: Success: Number of elements copied.
- *
- * Failure: 0
- *
- * Programmer: Quincey Koziol
- * Tuesday, June 16, 1998
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-static hsize_t
-H5S_hyper_fread (int dim, H5S_hyper_io_info_t *io_info)
-{
- hsize_t region_size; /* Size of lowest region */
- unsigned parm_init=0; /* Whether one-shot parameters set up */
- H5S_hyper_region_t *regions; /* Pointer to array of hyperslab nodes overlapped */
- size_t num_regions; /* number of regions overlapped */
- size_t i; /* Counters */
- int j;
-#ifdef QAK
- unsigned u;
-#endif /* QAK */
- hsize_t num_read=0; /* Number of elements read */
- unsigned cache_hyper; /* Hyperslab caching turned on? */
- unsigned block_limit; /* Hyperslab cache limit */
+ if(curr_span!=NULL) {
+ /* Move location offset of destination */
+ loc_off+=(curr_span->low-abs_arr[fast_dim])*elmt_size;
- FUNC_ENTER (H5S_hyper_fread, 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/elmt_size;
- assert(io_info);
+ /* Check if we are still within the span */
+ if(abs_arr[fast_dim]<=curr_span->high) {
+ iter->hyp.span[fast_dim]=curr_span;
- /* Get the hyperslab cache setting and limit */
- if (H5P_get(io_info->dxpl_id,H5D_XFER_HYPER_CACHE_NAME,&cache_hyper)<0)
- HRETURN_ERROR(H5E_PLIST, H5E_CANTGET, 0, "unable to get value");
- if (H5P_get(io_info->dxpl_id,H5D_XFER_HYPER_CACHE_LIM_NAME,&block_limit)<0)
- HRETURN_ERROR(H5E_PLIST, H5E_CANTGET, 0, "unable to get value");
+ goto partial_done; /* finished with partial span */
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span=curr_span->next;
-#ifdef QAK
- printf("%s: check 1.0, dim=%d\n",FUNC,dim);
-#endif /* QAK */
+ /* 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->hyp.span[fast_dim]=curr_span;
- /* Get a sorted list (in the next dimension down) of the regions which */
- /* overlap the current index in this dim */
- if((regions=H5S_hyper_get_regions(&num_regions,io_info->space->extent.u.simple.rank,
- (unsigned)(dim+1),
- io_info->space->select.sel_info.hslab.hyper_lst->count,
- io_info->space->select.sel_info.hslab.hyper_lst->lo_bounds,
- io_info->iter->hyp.pos,io_info->space->select.offset))!=NULL) {
+ goto partial_done; /* finished with partial span */
+ } /* end if */
+ } /* end else */
+ } /* end else */
- /*
- * Check if this is the second to last dimension in dataset (Which
- * means that we've got a list of the regions in the fastest changing
- * dimension and should input those regions).
- */
-#ifdef QAK
- if(dim>=0) {
- printf("%s: check 2.0, rank=%d, ",
- FUNC,(int)io_info->space->extent.u.simple.rank);
- printf("%s: pos={",FUNC);
- for(u=0; u<io_info->space->extent.u.simple.rank; u++) {
- printf("%d",(int)io_info->iter->hyp.pos[u]);
- if(u<io_info->space->extent.u.simple.rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
- } /* end if */
- else
- printf("%s: check 2.0, rank=%d\n",
- FUNC,(int)io_info->space->extent.u.simple.rank);
- for(i=0; i<num_regions; i++)
- printf("%s: check 2.1, region #%d: start=%d, end=%d\n",
- FUNC,i,(int)regions[i].start,(int)regions[i].end);
-#endif /* QAK */
- if((unsigned)(dim+2)==io_info->space->extent.u.simple.rank) {
-#ifdef QAK
- printf("%s: check 2.1.1, num_regions=%d\n",FUNC,(int)num_regions);
-#endif /* QAK */
- /* perform I/O on data from regions */
- for(i=0; i<num_regions && io_info->nelmts>0; i++) {
- /* Compute the size of the region to read */
- H5_CHECK_OVERFLOW(io_info->nelmts,hsize_t,hssize_t);
- region_size=MIN((hssize_t)io_info->nelmts, (regions[i].end-regions[i].start)+1);
+ /* Adjust iterator pointers */
-#ifdef QAK
- printf("%s: check 2.1.2, region=%d, region_size=%d, num_read=%lu\n",FUNC,(int)i,(int)region_size,(unsigned long)num_read);
-#endif /* QAK */
- /* Check if this hyperslab block is cached or could be cached */
- if(!regions[i].node->cinfo.cached &&
- (cache_hyper &&
- (block_limit==0 || block_limit>=(regions[i].node->cinfo.size*io_info->elmt_size)))) {
- /* if we aren't cached, attempt to cache the block */
-#ifdef QAK
- printf("%s: check 2.1.3, caching block\n",FUNC);
-#endif /* QAK */
- H5S_hyper_block_cache(regions[i].node,io_info,1);
- } /* end if */
+ if(curr_span==NULL) {
+/* Same as code in main loop */
+ /* Start at the next fastest dim */
+ curr_dim=fast_dim-1;
- /* Read information from the cached block */
- if(regions[i].node->cinfo.cached) {
-#ifdef QAK
- printf("%s: check 2.1.4, reading block from cache\n",FUNC);
-#endif /* QAK */
- if(H5S_hyper_block_read(regions[i].node,io_info,region_size)<0)
- HRETURN_ERROR (H5E_DATASPACE, H5E_READERROR, 0, "read error");
- }
+ /* Work back up through the dimensions */
+ while(curr_dim>=0) {
+ /* Reset the current span */
+ curr_span=iter->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 {
-#ifdef QAK
- printf("%s: check 2.1.5, reading block from file, parm_init=%d\n",FUNC,(int)parm_init);
-#endif /* QAK */
- /* Set up hyperslab I/O parameters which apply to all regions */
- if(!parm_init) {
- /* Copy the location of the region in the file */
- HDmemcpy(io_info->offset,io_info->iter->hyp.pos,(io_info->space->extent.u.simple.rank * sizeof(hssize_t)));
- io_info->offset[io_info->space->extent.u.simple.rank]=0;
-
- /* Set flag */
- parm_init=1;
- } /* end if */
+ /* Advance span in this dimension */
+ curr_span=curr_span->next;
-#ifdef QAK
- printf("%s: check 2.2, i=%d, region_size=%d\n",FUNC,(int)i,(int)region_size);
-#endif /* QAK */
- /* Fill in the region specific parts of the I/O request */
- io_info->hsize[io_info->space->extent.u.simple.rank-1]=region_size;
- io_info->offset[io_info->space->extent.u.simple.rank-1]=regions[i].start;
-
- /*
- * Gather from file.
- */
- if (H5F_arr_read(io_info->f, io_info->dxpl_id,
- io_info->layout, io_info->pline,
- io_info->fill, io_info->efl,
- io_info->hsize, io_info->hsize,
- zero, io_info->offset,
- io_info->dst/*out*/)<0) {
- HRETURN_ERROR (H5E_DATASPACE, H5E_READERROR, 0,
- "read error");
- }
+ /* Check if we have a valid span in this dimension still */
+ if(curr_span!=NULL) {
+ /* Reset absolute position */
+ abs_arr[curr_dim]=curr_span->low;
+
+ break;
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
} /* end else */
-#ifdef QAK
- printf("%s: check 2.3, region #%d\n",FUNC,(int)i);
- printf("pos={");
- for(u=0; u<io_info->space->extent.u.simple.rank; u++) {
- printf("%d",(int)io_info->iter->hyp.pos[u]);
- if(u<io_info->space->extent.u.simple.rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
-#endif /* QAK */
+ } /* end while */
- /* Advance the pointer in the buffer */
- io_info->dst = ((uint8_t *)io_info->dst) + region_size*io_info->elmt_size;
+ /* 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... */
+ assert(io_bytes_left==0);
- /* Increment the number of elements read */
- num_read+=region_size;
+ goto partial_done; /* finished with partial span */
+ } /* end if */
+ else {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim]=curr_span;
- /* Decrement the buffer left */
- io_info->nelmts-=region_size;
+ /* Walk back down the iterator positions, reseting them */
+ while(curr_dim<fast_dim) {
+ assert(curr_span);
+ assert(curr_span->down);
+ assert(curr_span->down->head);
- /* Set the next position to start at */
- if(region_size==(hsize_t)((regions[i].end-regions[i].start)+1)
- && i==(num_regions-1))
- io_info->iter->hyp.pos[dim+1]=(-1);
- else
- io_info->iter->hyp.pos[dim+1] = regions[i].start + region_size;
-#ifdef QAK
- printf("%s: check 2.3.5, region #%d\n",FUNC,(int)i);
- printf("pos={");
- for(j=0; j<io_info->space->extent.u.simple.rank; j++) {
- printf("%d",(int)io_info->iter->hyp.pos[j]);
- if(j<io_info->space->extent.u.simple.rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
-#endif /* QAK */
+ /* Set the new span_info & span for this dimension */
+ iter->hyp.span[curr_dim+1]=curr_span->down->head;
- /* Decrement the iterator count */
- io_info->iter->hyp.elmt_left-=region_size;
- } /* end for */
- } else { /* recurse on each region to next dimension down */
-#ifdef QAK
- printf("%s: check 3.0, num_regions=%d\n",FUNC,(int)num_regions);
- for(i=0; i<num_regions; i++)
- printf("%s: region %d={%d, %d}\n", FUNC,i,(int)regions[i].start,(int)regions[i].end);
-#endif /* QAK */
+ /* Advance span down the tree */
+ curr_span=curr_span->down->head;
- /* Increment the dimension we are working with */
- dim++;
+ /* Reset the absolute offset for the dim */
+ abs_arr[curr_dim+1]=curr_span->low;
- /* Step through each region in this dimension */
- for(i=0; i<num_regions && io_info->nelmts>0; i++) {
-#ifdef QAK
- printf("%s: check 3.5, dim=%d, region #%d={%d, %d}\n",FUNC,(int)dim,(int)i,(int)regions[i].start,(int)regions[i].end);
-{
- int k;
+ /* Increment current dimension */
+ curr_dim++;
+ } /* end while */
- printf("pos={");
- for(k=0; k<io_info->space->extent.u.simple.rank; k++) {
- printf("%d",(int)io_info->iter->hyp.pos[k]);
- if(k<io_info->space->extent.u.simple.rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
-}
-#endif /* QAK */
- /* Step through each location in each region */
- for(j=MAX(io_info->iter->hyp.pos[dim],regions[i].start); j<=regions[i].end && io_info->nelmts>0; j++) {
-#ifdef QAK
- printf("%s: check 4.0, dim=%d, j=%d, num_read=%lu\n",FUNC,dim,j,(unsigned long)num_read);
-#endif /* QAK */
+ /* Verify that the curr_span points to the fastest dim */
+ assert(curr_span==iter->hyp.span[fast_dim]);
+ } /* end else */
- /* Set the correct position we are working on */
- io_info->iter->hyp.pos[dim]=j;
+ /* Reset the buffer offset */
+ for(i=0, loc_off=0; i<ndims; i++)
+ loc_off+=(abs_arr[i]+off_arr[i])*slab[i];
+ } /* end if */
+ } /* end if */
- /* Go get the regions in the next lower dimension */
- num_read+=H5S_hyper_fread(dim, io_info);
+partial_done: /* Yes, goto's are evil, so sue me... :-) */
+ /* Get the number of bytes left to process currently */
+ last_io_bytes_left=io_bytes_left;
+
+ /* Perform the I/O on the elements, based on the position of the iterator */
+ while(io_bytes_left>0) {
+ /* 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 */
+ assert(curr_span->nelem==(hsize_t)((size_t)(curr_span->nelem))); /*check for overflow*/
+ span_size=curr_span->nelem;
+
+ /* 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 */
+ seq_len_arr[nseq]=span_size;
+ buf_off_arr[nseq]=loc_off;
+
+ /* Increment the number of sequences in arrays */
+ nseq++;
+
+ /* If the sequence & offset arrays are full, read them in */
+ if(nseq>=vector_size) {
+ /* Read in the sequences */
+ if (H5F_seq_readv(f, dxpl_id, layout, pline, fill, efl, space,
+ elmt_size, nseq, seq_len_arr, buf_off_arr, dst/*out*/)<0) {
+ HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error");
+ } /* end if */
- /* Advance to the next row if we got the whole region */
- if(io_info->iter->hyp.pos[dim+1]==(-1))
- io_info->iter->hyp.pos[dim]=j+1;
- } /* end for */
-#ifdef QAK
-{
- printf("%s: check 5.0, dim=%d, j=%d, region #%d={%d, %d}\n",FUNC,(int)dim,(int)j,(int)i,(int)regions[i].start,(int)regions[i].end);
- printf("%s: pos={",FUNC);
- for(u=0; u<io_info->space->extent.u.simple.rank; u++) {
- printf("%d",(int)io_info->iter->hyp.pos[u]);
- if(u<io_info->space->extent.u.simple.rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
-}
-#endif /* QAK */
- if(j>regions[i].end && io_info->iter->hyp.pos[dim+1]==(-1)
- && i==(num_regions-1))
- io_info->iter->hyp.pos[dim]=(-1);
- } /* end for */
-#ifdef QAK
-{
- int k;
-
- printf("%s: check 6.0, dim=%d\n",FUNC,(int)dim);
- printf("pos={");
- for(k=0; k<io_info->space->extent.u.simple.rank; k++) {
- printf("%d",(int)io_info->iter->hyp.pos[k]);
- if(k<io_info->space->extent.u.simple.rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
-}
-#endif /* QAK */
- } /* end else */
+ /* Increment the offset of the destination buffer */
+ dst+=(last_io_bytes_left-io_bytes_left);
- /* Release the temporary buffer */
- H5FL_ARR_FREE(H5S_hyper_region_t,regions);
- } /* end if */
+ /* Keep around the current number of I/O bytes left */
+ last_io_bytes_left=io_bytes_left;
+ nseq=0;
+ } /* end else */
+/* end COMMON */
- FUNC_LEAVE (num_read);
-} /* H5S_hyper_fread() */
+ /* Break out now, we are finished with I/O */
+ break;
+ } /* end if */
+ else {
+ /* Decrement I/O left to perform */
+ io_bytes_left-=span_size;
-
-/*-------------------------------------------------------------------------
- * Function: H5S_hyper_iter_next
- *
- * Purpose: Moves a hyperslab iterator to the beginning of the next sequence
- * of elements to read. Handles walking off the end in all dimensions.
- *
- * Return: Success: non-negative
- * Failure: negative
- *
- * Programmer: Quincey Koziol
- * Friday, September 8, 2000
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-static int
-H5S_hyper_iter_next (const H5S_t *file_space, H5S_sel_iter_t *file_iter)
-{
- hsize_t iter_offset[H5O_LAYOUT_NDIMS];
- hsize_t iter_count[H5O_LAYOUT_NDIMS];
- int fast_dim; /* Rank of the fastest changing dimension for the dataspace */
- int temp_dim; /* Temporary rank holder */
- unsigned i; /* Counters */
- unsigned ndims; /* Number of dimensions of dataset */
+/* COMMON */
+ /* Store the I/O information for the span */
+ seq_len_arr[nseq]=span_size;
+ buf_off_arr[nseq]=loc_off;
+
+ /* Increment the number of sequences in arrays */
+ nseq++;
+
+ /* If the sequence & offset arrays are full, read them in */
+ if(nseq>=vector_size) {
+ /* Read in the sequences */
+ if (H5F_seq_readv(f, dxpl_id, layout, pline, fill, efl, space,
+ elmt_size, nseq, seq_len_arr, buf_off_arr, dst/*out*/)<0) {
+ HGOTO_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error");
+ } /* end if */
- FUNC_ENTER (H5S_hyper_iter_next, FAIL);
+ /* Increment the offset of the destination buffer */
+ dst+=(last_io_bytes_left-io_bytes_left);
- /* Set some useful rank information */
- fast_dim=file_space->extent.u.simple.rank-1;
- ndims=file_space->extent.u.simple.rank;
+ /* Keep around the current number of I/O bytes left */
+ last_io_bytes_left=io_bytes_left;
+ nseq=0;
+ } /* end else */
+/* end COMMON */
+ } /* end else */
- /* Calculate the offset and block count for each dimension */
- for(i=0; i<ndims; i++) {
- iter_offset[i]=(file_iter->hyp.pos[i]-file_space->select.sel_info.hslab.diminfo[i].start)%file_space->select.sel_info.hslab.diminfo[i].stride;
- iter_count[i]=(file_iter->hyp.pos[i]-file_space->select.sel_info.hslab.diminfo[i].start)/file_space->select.sel_info.hslab.diminfo[i].stride;
- } /* end for */
+ /* Move to next span in fastest changing dimension */
+ curr_span=curr_span->next;
+ } /* end while */
- /* Start with the fastest changing dimension */
- temp_dim=fast_dim;
- while(temp_dim>=0) {
- if(temp_dim==fast_dim) {
- /* Move to the next block in the current dimension */
- iter_offset[temp_dim]=0; /* reset the offset in the fastest dimension */
- iter_count[temp_dim]++;
+ /* Check if we are done */
+ if(io_bytes_left==0) {
+ abs_arr[fast_dim]=curr_span->low+(span_size/elmt_size);
- /* If this block is still in the range of blocks to output for the dimension, break out of loop */
- if(iter_count[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].count)
+ /* Check if we are still within the span */
+ if(abs_arr[fast_dim]<=curr_span->high) {
+ iter->hyp.span[fast_dim]=curr_span;
break;
- else
- iter_count[temp_dim]=0; /* reset back to the beginning of the line */
+ } /* 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->hyp.span[fast_dim]=curr_span;
+ break;
+ } /* end if */
+ } /* end else */
} /* end if */
- else {
- /* Move to the next row in the curent dimension */
- iter_offset[temp_dim]++;
- /* If this block is still in the range of blocks to output for the dimension, break out of loop */
- if(iter_offset[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].block)
+ /* Adjust iterator pointers */
+
+ /* Start at the next fastest dim */
+ curr_dim=fast_dim-1;
+
+ /* Work back up through the dimensions */
+ while(curr_dim>=0) {
+ /* Reset the current span */
+ curr_span=iter->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 {
- /* Move to the next block in the current dimension */
- iter_offset[temp_dim]=0;
- iter_count[temp_dim]++;
+ /* 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[curr_dim]=curr_span->low;
- /* If this block is still in the range of blocks to output for the dimension, break out of loop */
- if(iter_count[temp_dim]<file_space->select.sel_info.hslab.diminfo[temp_dim].count)
break;
- else
- iter_count[temp_dim]=0; /* reset back to the beginning of the line */
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
} /* end else */
+ } /* end while */
+
+ /* Check if we are finished with the spans in the tree */
+ if(curr_dim<0) {
+ /* We had better be done with I/O or bad things are going to happen... */
+ assert(io_bytes_left==0);
+ break;
+ } /* end if */
+ else {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim]=curr_span;
+
+ /* Walk back down the iterator positions, reseting them */
+ while(curr_dim<fast_dim) {
+ assert(curr_span);
+ assert(curr_span->down);
+ assert(curr_span->down->head);
+
+ /* Set the new span for the next dimension down */
+ iter->hyp.span[curr_dim+1]=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+1]=curr_span->low;
+
+ /* Increment current dimension */
+ curr_dim++;
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ assert(curr_span==iter->hyp.span[fast_dim]);
} /* end else */
- /* Decrement dimension count */
- temp_dim--;
+ /* Reset the buffer offset */
+ for(i=0, loc_off=0; i<ndims; i++)
+ loc_off+=(abs_arr[i]+off_arr[i])*slab[i];
} /* end while */
+
+ /* Check for any stored sequences which need to be flushed */
+ if(nseq>0) {
+ /* Read in the sequence */
+ if (H5F_seq_readv(f, dxpl_id, layout, pline, fill, efl, space,
+ elmt_size, nseq, seq_len_arr, buf_off_arr, dst/*out*/)<0) {
+ HRETURN_ERROR(H5E_DATASPACE, H5E_READERROR, 0, "read error");
+ } /* end if */
+ } /* end if */
- /* Translate current iter_offset and iter_count into iterator position */
- for(i=0; i<ndims; i++)
- file_iter->hyp.pos[i]=file_space->select.sel_info.hslab.diminfo[i].start+(file_space->select.sel_info.hslab.diminfo[i].stride*iter_count[i])+iter_offset[i];
+ /* Increment amount of I/O performed */
+ iter->hyp.elmt_left-=nelem;
- FUNC_LEAVE (SUCCEED);
-} /* H5S_hyper_iter_next() */
+ /* Success! */
+ ret_value=nelem;
+
+done:
+ if(seq_len_arr!=NULL)
+ H5FL_ARR_FREE(size_t,seq_len_arr);
+ if(buf_off_arr!=NULL)
+ H5FL_ARR_FREE(hsize_t,buf_off_arr);
+
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_fread() */
/*-------------------------------------------------------------------------
@@ -1550,7 +1442,6 @@ H5S_hyper_fgath (H5F_t *f, const struct H5O_layout_t *layout,
const H5S_t *file_space, H5S_sel_iter_t *file_iter,
hsize_t nelmts, hid_t dxpl_id, void *_buf/*out*/)
{
- H5S_hyper_io_info_t io_info; /* Block of parameters to pass into recursive calls */
hsize_t num_read=0; /* number of elements read into buffer */
herr_t ret_value=SUCCEED;
@@ -1565,42 +1456,14 @@ H5S_hyper_fgath (H5F_t *f, const struct H5O_layout_t *layout,
assert (nelmts>0);
assert (_buf);
-#ifdef QAK
- printf("%s: check 1.0\n", FUNC);
-#endif /* QAK */
-
/* Check for the special case of just one H5Sselect_hyperslab call made */
if(file_space->select.sel_info.hslab.diminfo!=NULL) {
/* Use optimized call to read in regular hyperslab */
num_read=H5S_hyper_fread_opt(f,layout,pline,fill,efl,elmt_size,file_space,file_iter,nelmts,dxpl_id,_buf);
} /* end if */
- /* Perform generic hyperslab operation */
else {
- /* Initialize parameter block for recursive calls */
- io_info.f=f;
- io_info.layout=layout;
- io_info.pline=pline;
- io_info.fill=fill;
- io_info.efl=efl;
- io_info.elmt_size=elmt_size;
- io_info.space=file_space;
- io_info.iter=file_iter;
- io_info.nelmts=nelmts;
- io_info.dxpl_id = dxpl_id;
- io_info.src=NULL;
- io_info.dst=_buf;
-
- /* Set the hyperslab size to copy */
- io_info.hsize[0]=1;
- H5V_array_fill(io_info.hsize,io_info.hsize,sizeof(io_info.hsize[0]),file_space->extent.u.simple.rank);
- io_info.hsize[file_space->extent.u.simple.rank]=elmt_size;
-
- /* Recursively input the hyperslabs currently defined */
- /* starting with the slowest changing dimension */
- num_read=H5S_hyper_fread(-1,&io_info);
-#ifdef QAK
- printf("%s: check 5.0, num_read=%d\n",FUNC,(int)num_read);
-#endif /* QAK */
+ /* Perform generic hyperslab operation */
+ num_read=H5S_hyper_fread(f,layout,pline,fill,efl,elmt_size,file_space,file_iter,nelmts,dxpl_id,_buf);
} /* end else */
FUNC_LEAVE (ret_value==SUCCEED ? num_read : 0);
@@ -1610,167 +1473,449 @@ H5S_hyper_fgath (H5F_t *f, const struct H5O_layout_t *layout,
/*-------------------------------------------------------------------------
* Function: H5S_hyper_fwrite
*
- * Purpose: Recursively scatters data points to a file using the parameters
- * passed to H5S_hyper_fscat.
+ * Purpose: Performs an optimized scatter to the file, based on a hyperslab
+ * span selection.
*
* Return: Success: Number of elements copied.
- *
* Failure: 0
*
* Programmer: Quincey Koziol
- * Tuesday, June 16, 1998
+ * Tuesday, September 12, 2000
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
static hsize_t
-H5S_hyper_fwrite (int dim, H5S_hyper_io_info_t *io_info)
+H5S_hyper_fwrite (H5F_t *f, const struct H5O_layout_t *layout,
+ const struct H5O_pline_t *pline,
+ const struct H5O_fill_t *fill,
+ const struct H5O_efl_t *efl, size_t elmt_size,
+ const H5S_t *space, H5S_sel_iter_t *iter,
+ hsize_t nelem, hid_t dxpl_id, const void *_buf)
{
- hsize_t region_size; /* Size of lowest region */
- unsigned parm_init=0; /* Whether one-shot parameters set up */
- H5S_hyper_region_t *regions; /* Pointer to array of hyperslab nodes overlapped */
- size_t num_regions; /* number of regions overlapped */
- size_t i; /* Counters */
- int j;
- hsize_t num_written=0; /* Number of elements read */
- unsigned cache_hyper; /* Hyperslab caching turned on? */
- unsigned block_limit; /* Hyperslab cache limit */
+ const uint8_t *src=(const uint8_t *)_buf; /* Alias for pointer arithmetic */
+ H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */
+ H5S_hyper_span_t *curr_span; /* Current hyperslab span node */
+ hsize_t slab[H5O_LAYOUT_NDIMS]; /* Cumulative size of each dimension in bytes */
+ hsize_t acc; /* Accumulator for computing cumulative sizes */
+ hssize_t *abs_arr; /* Absolute hyperslab span position */
+ hssize_t *off_arr; /* Offset within the dataspace extent */
+ int fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ int curr_dim; /* Current dimension being operated on */
+ int ndims; /* Number of dimensions of dataset */
+ hsize_t loc_off; /* Element offset in the dataspace */
+ size_t span_size; /* Number of bytes in current span to actually process */
+ size_t io_bytes_left; /* Number of bytes left to process */
+ int i; /* Index variable */
+ size_t *seq_len_arr=NULL; /* Array of sequence lengths */
+ hsize_t *buf_off_arr=NULL; /* Array of dataset offsets */
+ size_t last_io_bytes_left=0; /* Last I/O bytes left before readv() called */
+ size_t nseq=0; /* Number of sequence/offsets stored in the arrays */
+ size_t vector_size; /* Value for vector size */
+ hssize_t ret_value=FAIL;
FUNC_ENTER (H5S_hyper_fwrite, 0);
+#ifdef QAK
+printf("%s: Called!\n",FUNC);
+#endif /* QAK */
- assert(io_info);
+ /* Check args */
+ assert(f);
+ assert(layout);
+ assert(pline);
+ assert(fill);
+ assert(efl);
+ assert(elmt_size>0);
+ assert(space);
+ assert(iter);
+ assert(nelem>0);
+ assert(src);
- /* Get the hyperslab cache setting and limit */
- if (H5P_get(io_info->dxpl_id,H5D_XFER_HYPER_CACHE_NAME,&cache_hyper)<0)
- HRETURN_ERROR(H5E_PLIST, H5E_CANTGET, 0, "unable to get value");
- if (H5P_get(io_info->dxpl_id,H5D_XFER_HYPER_CACHE_LIM_NAME,&block_limit)<0)
- HRETURN_ERROR(H5E_PLIST, H5E_CANTGET, 0, "unable to get value");
+ /* Set the rank of the fastest changing dimension */
+ ndims=space->extent.u.simple.rank;
+ fast_dim=(ndims-1);
+
+ /* Get the pointers to the current span info and span nodes */
+ curr_span=iter->hyp.span[fast_dim];
+ abs_arr=iter->hyp.off;
+ off_arr=space->select.offset;
+ ispan=iter->hyp.span;
+
+ /* Set the amount of elements to perform I/O on, etc. */
+ assert(nelem==(hsize_t)((size_t)(nelem))); /*check for overflow*/
+ io_bytes_left=nelem*elmt_size;
+
+ /* Compute the cumulative size of dataspace dimensions */
+ for(i=fast_dim, acc=elmt_size; i>=0; i--) {
+ slab[i]=acc;
+ acc*=space->extent.u.simple.size[i];
+ } /* end for */
+ /* Set the offset of the first element iterated on */
+ for(i=0, loc_off=0; i<ndims; i++)
+ /* Compute the sequential element offset */
+ loc_off+=(abs_arr[i]+space->select.offset[i])*slab[i];
-#ifdef QAK
- printf("%s: check 1.0\n", FUNC);
-#endif /* QAK */
- /* Get a sorted list (in the next dimension down) of the regions which */
- /* overlap the current index in this dim */
- if((regions=H5S_hyper_get_regions(&num_regions,io_info->space->extent.u.simple.rank,
- (unsigned)(dim+1),
- io_info->space->select.sel_info.hslab.hyper_lst->count,
- io_info->space->select.sel_info.hslab.hyper_lst->lo_bounds,
- io_info->iter->hyp.pos,io_info->space->select.offset))!=NULL) {
+ /* Range check against number of elements left in selection */
+ assert(io_bytes_left<=(iter->hyp.elmt_left*elmt_size));
-#ifdef QAK
- printf("%s: check 1.1, regions=%p\n", FUNC,regions);
- printf("%s: check 1.2, rank=%d\n",
- FUNC,(int)io_info->space->extent.u.simple.rank);
- for(i=0; i<num_regions; i++)
- printf("%s: check 2.1, region #%d: start=%d, end=%d\n",
- FUNC,i,(int)regions[i].start,(int)regions[i].end);
-#endif /* QAK */
+ /* Get the hyperslab vector size */
+ if (H5P_get(dxpl_id,H5D_XFER_HYPER_VECTOR_SIZE_NAME,&vector_size)<0)
+ HGOTO_ERROR(H5E_PLIST, H5E_CANTGET, 0, "unable to get value");
+
+ /* Allocate the vector I/O arrays */
+ if((seq_len_arr = H5FL_ARR_ALLOC(size_t,vector_size,0))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate vector I/O array");
+ if((buf_off_arr = H5FL_ARR_ALLOC(hsize_t,vector_size,0))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 0, "can't allocate vector I/O array");
+
+ /* 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 */
+ span_size=((curr_span->high-abs_arr[fast_dim])+1)*elmt_size;
+
+ /* Check number of bytes against upper bounds allowed */
+ if(span_size>io_bytes_left)
+ span_size=io_bytes_left;
+
+ if (H5F_seq_write(f, dxpl_id, layout, pline, fill, efl, space,
+ elmt_size, span_size, loc_off, src)<0) {
+ HRETURN_ERROR(H5E_DATASPACE, H5E_WRITEERROR, 0, "write error");
+ } /* end if */
+
+ /* Increment offset in destination */
+ src+=span_size;
+
+ /* Decrement I/O left to perform */
+ io_bytes_left-=span_size;
+
+ /* Check if we are done */
+ if(io_bytes_left>0) {
+ /* Move to next span in fastest changing dimension */
+ curr_span=curr_span->next;
+
+ if(curr_span!=NULL) {
+ /* Move location offset of destination */
+ loc_off+=(curr_span->low-abs_arr[fast_dim])*elmt_size;
+
+ /* Move iterator for fastest changing dimension */
+ abs_arr[fast_dim]=curr_span->low;
+ } /* end if */
+ } /* end if */
+ else {
+ abs_arr[fast_dim]+=span_size/elmt_size;
+
+ /* Check if we are still within the span */
+ if(abs_arr[fast_dim]<=curr_span->high) {
+ iter->hyp.span[fast_dim]=curr_span;
+
+ goto partial_done; /* finished with partial span */
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span=curr_span->next;
+
+ /* Check if we have a valid span in this dimension still */
+ if(curr_span!=NULL) {
+ /* Reset absolute position */
+ abs_arr[fast_dim]=curr_span->low;
+ iter->hyp.span[fast_dim]=curr_span;
- /* Check if this is the second to last dimension in dataset */
- /* (Which means that we've got a list of the regions in the fastest */
- /* changing dimension and should input those regions) */
- if((unsigned)(dim+2)==io_info->space->extent.u.simple.rank) {
-
- /* perform I/O on data from regions */
- for(i=0; i<num_regions && io_info->nelmts>0; i++) {
- /* Compute the size of the region to read */
- H5_CHECK_OVERFLOW(io_info->nelmts,hsize_t,hssize_t);
- region_size=MIN((hssize_t)io_info->nelmts, (regions[i].end-regions[i].start)+1);
-
- /* Check if this hyperslab block is cached or could be cached */
- if(!regions[i].node->cinfo.cached && (cache_hyper && (block_limit==0 || block_limit>=(regions[i].node->cinfo.size*io_info->elmt_size)))) {
- /* if we aren't cached, attempt to cache the block */
- H5S_hyper_block_cache(regions[i].node,io_info,0);
+ goto partial_done; /* finished with partial span */
} /* end if */
+ } /* end else */
+ } /* end else */
+
+ /* Adjust iterator pointers */
+
+ if(curr_span==NULL) {
+/* Same as code in main loop */
+ /* Start at the next fastest dim */
+ curr_dim=fast_dim-1;
- /* Write information to the cached block */
- if(regions[i].node->cinfo.cached) {
- if(H5S_hyper_block_write(regions[i].node,io_info,region_size)<0)
- HRETURN_ERROR (H5E_DATASPACE, H5E_WRITEERROR, 0, "write error");
- }
+ /* Work back up through the dimensions */
+ while(curr_dim>=0) {
+ /* Reset the current span */
+ curr_span=iter->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 {
- /* Set up hyperslab I/O parameters which apply to all regions */
- if(!parm_init) {
- /* Copy the location of the region in the file */
- HDmemcpy(io_info->offset, io_info->iter->hyp.pos, (io_info->space->extent.u.simple.rank * sizeof(hssize_t)));
- io_info->offset[io_info->space->extent.u.simple.rank]=0;
-
- /* Set flag */
- parm_init=1;
+ /* 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[curr_dim]=curr_span->low;
+
+ break;
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+
+ /* Check if we are finished with the spans in the tree */
+ if(curr_dim<0) {
+ /* We had better be done with I/O or bad things are going to happen... */
+ assert(io_bytes_left==0);
+
+ goto partial_done; /* finished with partial span */
+ } /* end if */
+ else {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim]=curr_span;
+
+ /* Walk back down the iterator positions, reseting them */
+ while(curr_dim<fast_dim) {
+ assert(curr_span);
+ assert(curr_span->down);
+ assert(curr_span->down->head);
+
+ /* Set the new span for this dimension */
+ iter->hyp.span[curr_dim+1]=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+1]=curr_span->low;
+
+ /* Increment current dimension */
+ curr_dim++;
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ assert(curr_span==iter->hyp.span[fast_dim]);
+ } /* end else */
+
+ /* Reset the buffer offset */
+ for(i=0, loc_off=0; i<ndims; i++)
+ loc_off+=(abs_arr[i]+off_arr[i])*slab[i];
+ } /* end if */
+ } /* end if */
+
+partial_done: /* Yes, goto's are evil, so sue me... :-) */
+ /* Get the number of bytes left to process currently */
+ last_io_bytes_left=io_bytes_left;
+
+ /* Perform the I/O on the elements, based on the position of the iterator */
+ while(io_bytes_left>0) {
+ /* 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 */
+ assert(curr_span->nelem==(hsize_t)((size_t)(curr_span->nelem))); /*check for overflow*/
+ span_size=curr_span->nelem;
+
+ /* 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 */
+ seq_len_arr[nseq]=span_size;
+ buf_off_arr[nseq]=loc_off;
+
+ /* Increment the number of sequences in arrays */
+ nseq++;
+
+ /* If the sequence & offset arrays are full, read them in */
+ if(nseq>=vector_size) {
+ /* Write out the sequences */
+ if (H5F_seq_writev(f, dxpl_id, layout, pline, fill, efl, space,
+ elmt_size, nseq, seq_len_arr, buf_off_arr, src)<0) {
+ HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, 0, "write error");
} /* end if */
- io_info->hsize[io_info->space->extent.u.simple.rank-1]=region_size;
- io_info->offset[io_info->space->extent.u.simple.rank-1]=regions[i].start;
-
- /*
- * Scatter to file.
- */
- if (H5F_arr_write(io_info->f, io_info->dxpl_id,
- io_info->layout, io_info->pline,
- io_info->fill, io_info->efl,
- io_info->hsize, io_info->hsize, zero,
- io_info->offset, io_info->src)<0) {
- HRETURN_ERROR (H5E_DATASPACE, H5E_WRITEERROR, 0, "write error");
- }
+ /* Increment the offset of the destination buffer */
+ src+=(last_io_bytes_left-io_bytes_left);
+
+ /* Keep around the current number of I/O bytes left */
+ last_io_bytes_left=io_bytes_left;
+ nseq=0;
} /* end else */
+/* end COMMON */
- /* Advance the pointer in the buffer */
- io_info->src = ((const uint8_t *)io_info->src) +
- region_size*io_info->elmt_size;
+ /* Break out now, we are finished with I/O */
+ break;
+ } /* end if */
+ else {
+ /* Decrement I/O left to perform */
+ io_bytes_left-=span_size;
- /* Increment the number of elements read */
- num_written+=region_size;
+/* COMMON */
+ /* Store the I/O information for the span */
+ seq_len_arr[nseq]=span_size;
+ buf_off_arr[nseq]=loc_off;
+
+ /* Increment the number of sequences in arrays */
+ nseq++;
+
+ /* If the sequence & offset arrays are full, read them in */
+ if(nseq>=vector_size) {
+ /* Write out the sequences */
+ if (H5F_seq_writev(f, dxpl_id, layout, pline, fill, efl, space,
+ elmt_size, nseq, seq_len_arr, buf_off_arr, src)<0) {
+ HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, 0, "write error");
+ } /* end if */
- /* Decrement the buffer left */
- io_info->nelmts-=region_size;
+ /* Increment the offset of the destination buffer */
+ src+=(last_io_bytes_left-io_bytes_left);
- /* Set the next position to start at */
- if(region_size==(hsize_t)((regions[i].end-regions[i].start)+1)
- && i==(num_regions-1))
- io_info->iter->hyp.pos[dim+1]=(-1);
- else
- io_info->iter->hyp.pos[dim+1] = regions[i].start +
- region_size;
+ /* Keep around the current number of I/O bytes left */
+ last_io_bytes_left=io_bytes_left;
+ nseq=0;
+ } /* end else */
+/* end COMMON */
+ } /* end else */
- /* Decrement the iterator count */
- io_info->iter->hyp.elmt_left-=region_size;
- } /* end for */
- } else { /* recurse on each region to next dimension down */
-
- /* Increment the dimension we are working with */
- dim++;
-
- /* Step through each region in this dimension */
- for(i=0; i<num_regions && io_info->nelmts>0; i++) {
- /* Step through each location in each region */
- for(j=MAX(io_info->iter->hyp.pos[dim],regions[i].start); j<=regions[i].end && io_info->nelmts>0; j++) {
- /* Set the correct position we are working on */
- io_info->iter->hyp.pos[dim]=j;
-
- /* Go get the regions in the next lower dimension */
- num_written+=H5S_hyper_fwrite(dim, io_info);
-
- /* Advance to the next row if we got the whole region */
- if(io_info->iter->hyp.pos[dim+1]==(-1))
- io_info->iter->hyp.pos[dim]=j+1;
- } /* end for */
- if(j>regions[i].end && io_info->iter->hyp.pos[dim+1]==(-1)
- && i==(num_regions-1))
- io_info->iter->hyp.pos[dim]=(-1);
- } /* end for */
+ /* Move to next span in fastest changing dimension */
+ curr_span=curr_span->next;
+ } /* end while */
+
+ /* Check if we are done */
+ if(io_bytes_left==0) {
+ abs_arr[fast_dim]=curr_span->low+(span_size/elmt_size);
+
+ /* Check if we are still within the span */
+ if(abs_arr[fast_dim]<=curr_span->high) {
+ iter->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->hyp.span[fast_dim]=curr_span;
+ break;
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
+ /* Adjust iterator pointers */
+
+ /* Start at the next fastest dim */
+ curr_dim=fast_dim-1;
+
+ /* Work back up through the dimensions */
+ while(curr_dim>=0) {
+ /* Reset the current span */
+ curr_span=iter->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 absolute position */
+ abs_arr[curr_dim]=curr_span->low;
+
+ break;
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+
+ /* Check if we are finished with the spans in the tree */
+ if(curr_dim<0) {
+ /* We had better be done with I/O or bad things are going to happen... */
+ assert(io_bytes_left==0);
+ break;
+ } /* end if */
+ else {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim]=curr_span;
+
+ /* Walk back down the iterator positions, reseting them */
+ while(curr_dim<fast_dim) {
+ assert(curr_span);
+ assert(curr_span->down);
+ assert(curr_span->down->head);
+
+ /* Set the new span for the next dimension down */
+ iter->hyp.span[curr_dim+1]=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+1]=curr_span->low;
+
+ /* Increment current dimension */
+ curr_dim++;
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ assert(curr_span==iter->hyp.span[fast_dim]);
} /* end else */
- /* Release the temporary buffer */
- H5FL_ARR_FREE(H5S_hyper_region_t,regions);
+ /* Reset the buffer offset */
+ for(i=0, loc_off=0; i<ndims; i++)
+ loc_off+=(abs_arr[i]+off_arr[i])*slab[i];
+ } /* end while */
+
+ /* Check for any stored sequences which need to be flushed */
+ if(nseq>0) {
+ /* Write out the sequence */
+ if (H5F_seq_writev(f, dxpl_id, layout, pline, fill, efl, space,
+ elmt_size, nseq, seq_len_arr, buf_off_arr, src)<0) {
+ HGOTO_ERROR(H5E_DATASPACE, H5E_WRITEERROR, 0, "write error");
+ } /* end if */
} /* end if */
-#ifdef QAK
- printf("%s: check 2.0\n", FUNC);
-#endif /* QAK */
- FUNC_LEAVE (num_written);
-} /* H5S_hyper_fwrite() */
+ /* Increment amount of I/O performed */
+ iter->hyp.elmt_left-=nelem;
+
+ /* Success! */
+ ret_value=nelem;
+
+done:
+ if(seq_len_arr!=NULL)
+ H5FL_ARR_FREE(size_t,seq_len_arr);
+ if(buf_off_arr!=NULL)
+ H5FL_ARR_FREE(hsize_t,buf_off_arr);
+
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_fwrite() */
/*-------------------------------------------------------------------------
@@ -2387,7 +2532,6 @@ H5S_hyper_fscat (H5F_t *f, const struct H5O_layout_t *layout,
const H5S_t *file_space, H5S_sel_iter_t *file_iter,
hsize_t nelmts, hid_t dxpl_id, const void *_buf)
{
- H5S_hyper_io_info_t io_info; /* Block of parameters to pass into recursive calls */
hsize_t num_written=0; /* number of elements read into buffer */
herr_t ret_value=SUCCEED;
@@ -2402,41 +2546,14 @@ H5S_hyper_fscat (H5F_t *f, const struct H5O_layout_t *layout,
assert (nelmts>0);
assert (_buf);
-#ifdef QAK
- printf("%s: check 1.0\n", FUNC);
-#endif /* QAK */
-
/* Check for the special case of just one H5Sselect_hyperslab call made */
if(file_space->select.sel_info.hslab.diminfo!=NULL) {
/* Use optimized call to write out regular hyperslab */
num_written=H5S_hyper_fwrite_opt(f,layout,pline,fill,efl,elmt_size,file_space,file_iter,nelmts,dxpl_id,_buf);
- }
+ } /* end if */
else {
- /* Initialize parameter block for recursive calls */
- io_info.f=f;
- io_info.layout=layout;
- io_info.pline=pline;
- io_info.fill=fill;
- io_info.efl=efl;
- io_info.elmt_size=elmt_size;
- io_info.space=file_space;
- io_info.iter=file_iter;
- io_info.nelmts=nelmts;
- io_info.dxpl_id = dxpl_id;
- io_info.src=_buf;
- io_info.dst=NULL;
-
- /* Set the hyperslab size to copy */
- io_info.hsize[0]=1;
- H5V_array_fill(io_info.hsize,io_info.hsize,sizeof(io_info.hsize[0]),file_space->extent.u.simple.rank);
- io_info.hsize[file_space->extent.u.simple.rank]=elmt_size;
-
- /* Recursively input the hyperslabs currently defined */
- /* starting with the slowest changing dimension */
- num_written=H5S_hyper_fwrite(-1,&io_info);
-#ifdef QAK
- printf("%s: check 2.0\n", FUNC);
-#endif /* QAK */
+ /* Perform generic hyperslab operation */
+ num_written=H5S_hyper_fwrite(f,layout,pline,fill,efl,elmt_size,file_space,file_iter,nelmts,dxpl_id,_buf);
} /* end else */
FUNC_LEAVE (ret_value==FAIL ? ret_value : (num_written >0) ? SUCCEED : FAIL);
@@ -2446,145 +2563,376 @@ H5S_hyper_fscat (H5F_t *f, const struct H5O_layout_t *layout,
/*-------------------------------------------------------------------------
* Function: H5S_hyper_mread
*
- * Purpose: Recursively gathers data points from memory using the
- * parameters passed to H5S_hyper_mgath.
+ * Purpose: Performs an optimized gather from a memory buffer, based on a
+ * hyperslab span selection.
*
* Return: Success: Number of elements copied.
- *
* Failure: 0
*
* Programmer: Quincey Koziol
- * Tuesday, June 16, 1998
+ * Tuesday, September 12, 2000
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
-static hsize_t
-H5S_hyper_mread (int dim, H5S_hyper_io_info_t *io_info)
+static hssize_t
+H5S_hyper_mread (const void *_buf, size_t elmt_size, const H5S_t *space,
+ H5S_sel_iter_t *iter, hsize_t nelem, void *_tconv_buf/*out*/)
{
- hsize_t region_size; /* Size of lowest region */
- H5S_hyper_region_t *regions; /* Pointer to array of hyperslab nodes overlapped */
- size_t num_regions; /* number of regions overlapped */
- size_t i; /* Counters */
- int j;
- hsize_t num_read=0; /* Number of elements read */
-
- FUNC_ENTER (H5S_hyper_mread, 0);
-
- assert(io_info);
+ const uint8_t *src=(const uint8_t *)_buf; /* Alias for pointer arithmetic */
+ const uint8_t *tmp_src; /* Alias for pointer arithmetic */
+ uint8_t *dst=(uint8_t *)_tconv_buf; /* Alias for pointer arithmetic */
+ H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */
+ H5S_hyper_span_t *curr_span; /* Current hyperslab span node */
+ hsize_t slab[H5O_LAYOUT_NDIMS]; /* Cumulative size of each dimension in bytes */
+ hsize_t acc; /* Accumulator for computing cumulative sizes */
+ hssize_t *abs_arr; /* Absolute hyperslab span position */
+ hssize_t *off_arr; /* Offset within the dataspace extent */
+ int fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ int curr_dim; /* Current dimension being operated on */
+ int ndims; /* Number of dimensions of dataset */
+ size_t span_size; /* Number of bytes in current span to actually process */
+ size_t io_bytes_left; /* Number of bytes left to process */
+ int i; /* Index variable */
+ hssize_t ret_value=FAIL;
+ FUNC_ENTER (H5S_hyper_mread, FAIL);
#ifdef QAK
- printf("%s: check 1.0, dim=%d\n",FUNC,dim);
+printf("%s: Called!\n",FUNC);
#endif /* QAK */
- /* Get a sorted list (in the next dimension down) of the regions which */
- /* overlap the current index in this dim */
- if((regions=H5S_hyper_get_regions(&num_regions,io_info->space->extent.u.simple.rank,
- (unsigned)(dim+1),
- io_info->space->select.sel_info.hslab.hyper_lst->count,
- io_info->space->select.sel_info.hslab.hyper_lst->lo_bounds,
- io_info->iter->hyp.pos,io_info->space->select.offset))!=NULL) {
-
- /* Check if this is the second to last dimension in dataset */
- /* (Which means that we've got a list of the regions in the fastest */
- /* changing dimension and should input those regions) */
-#ifdef QAK
- printf("%s: check 2.0, rank=%d, num_regions=%d\n",
- FUNC, (int)io_info->space->extent.u.simple.rank,
- (int)num_regions);
- for(i=0; i<num_regions; i++)
- printf("%s: check 2.1, region #%d: start=%d, end=%d\n",
- FUNC,i,(int)regions[i].start,(int)regions[i].end);
-#endif /* QAK */
+ /* Check args */
+ assert(src);
+ assert(elmt_size>0);
+ assert(space);
+ assert(iter);
+ assert(nelem>0);
+ assert(dst);
- if((unsigned)(dim+2)==io_info->space->extent.u.simple.rank) {
+ /* Set the rank of the fastest changing dimension */
+ ndims=space->extent.u.simple.rank;
+ fast_dim=(ndims-1);
+
+ /* Get the pointers to the current span info and span nodes */
+ curr_span=iter->hyp.span[fast_dim];
+ abs_arr=iter->hyp.off;
+ off_arr=space->select.offset;
+ ispan=iter->hyp.span;
+
+ /* Set the amount of elements to perform I/O on, etc. */
+ assert(nelem==(hsize_t)((size_t)(nelem))); /*check for overflow*/
+ io_bytes_left=nelem*elmt_size;
+
+ /* Compute the cumulative size of dataspace dimensions */
+ for(i=fast_dim, acc=elmt_size; i>=0; i--) {
+ slab[i]=acc;
+ acc*=space->extent.u.simple.size[i];
+ } /* end for */
- /* Set up hyperslab I/O parameters which apply to all regions */
+ /* Set the offset of the first element iterated on */
+ for(i=0, tmp_src=src; i<ndims; i++)
+ /* Compute the sequential element offset */
+ tmp_src+=(abs_arr[i]+space->select.offset[i])*slab[i];
- /* Copy the location of the region in the file */
- HDmemcpy(io_info->offset, io_info->iter->hyp.pos, (io_info->space->extent.u.simple.rank * sizeof(hssize_t)));
- io_info->offset[io_info->space->extent.u.simple.rank]=0;
+ /* Range check against number of elements left in selection */
+ assert(io_bytes_left<=(iter->hyp.elmt_left*elmt_size));
- /* perform I/O on data from regions */
- for(i=0; i<num_regions && io_info->nelmts>0; i++) {
- H5_CHECK_OVERFLOW(io_info->nelmts,hsize_t,hssize_t);
- region_size=MIN((hssize_t)io_info->nelmts,(regions[i].end-regions[i].start)+1);
- io_info->hsize[io_info->space->extent.u.simple.rank-1]=region_size;
- io_info->offset[io_info->space->extent.u.simple.rank-1]=regions[i].start;
-#ifdef QAK
- printf("%s: check 2.1, i=%d, region_size=%d\n",
- FUNC,(int)i,(int)region_size);
-#endif /* QAK */
+ /* Take care of any partial spans leftover from previous I/Os */
+ if(abs_arr[fast_dim]!=curr_span->low) {
- /*
- * Gather from memory.
- */
- if (H5V_hyper_copy (io_info->space->extent.u.simple.rank+1,
- io_info->hsize, io_info->hsize, zero, io_info->dst,
- io_info->mem_size, io_info->offset, io_info->src)<0) {
- HRETURN_ERROR (H5E_DATASPACE, H5E_READERROR, 0,
- "unable to gather data from memory");
- }
-
- /* Advance the pointer in the buffer */
- io_info->dst = ((uint8_t *)io_info->dst) + region_size*io_info->elmt_size;
-
- /* Increment the number of elements read */
- num_read+=region_size;
-
- /* Decrement the buffer left */
- io_info->nelmts-=region_size;
-
- /* Set the next position to start at */
- if(region_size==(hsize_t)((regions[i].end-regions[i].start)+1)
- && i==(num_regions-1))
- io_info->iter->hyp.pos[dim+1]=(-1);
- else
- io_info->iter->hyp.pos[dim+1] =regions[i].start +
- region_size;
+ /* Finish the span in the fastest changing dimension */
- /* Decrement the iterator count */
- io_info->iter->hyp.elmt_left-=region_size;
- } /* end for */
- } else { /* recurse on each region to next dimension down */
-#ifdef QAK
- printf("%s: check 3.0, num_regions=%d\n",FUNC,(int)num_regions);
-#endif /* QAK */
+ /* Compute the number of bytes to attempt in this span */
+ span_size=((curr_span->high-abs_arr[fast_dim])+1)*elmt_size;
- /* Increment the dimension we are working with */
- dim++;
+ /* Check number of elements against upper bounds allowed */
+ if(span_size>io_bytes_left)
+ span_size=io_bytes_left;
- /* Step through each region in this dimension */
- for(i=0; i<num_regions && io_info->nelmts>0; i++) {
- /* Step through each location in each region */
- for(j=MAX(io_info->iter->hyp.pos[dim],regions[i].start); j<=regions[i].end && io_info->nelmts>0; j++) {
-#ifdef QAK
- printf("%s: check 4.0, dim=%d, location=%d\n",FUNC,dim,j);
-#endif /* QAK */
+ HDmemcpy(dst,tmp_src,(size_t)span_size);
- /* Set the correct position we are working on */
- io_info->iter->hyp.pos[dim]=j;
+ /* Increment offset in destination */
+ dst+=span_size;
- /* Go get the regions in the next lower dimension */
- num_read+=H5S_hyper_mread(dim, io_info);
+ /* Decrement I/O left to perform */
+ io_bytes_left-=span_size;
- /* Advance to the next row if we got the whole region */
- if(io_info->iter->hyp.pos[dim+1]==(-1))
- io_info->iter->hyp.pos[dim]=j+1;
- } /* end for */
- if(j>regions[i].end && io_info->iter->hyp.pos[dim+1]==(-1)
- && i==(num_regions-1))
- io_info->iter->hyp.pos[dim]=(-1);
- } /* end for */
+ /* Check if we are done */
+ if(io_bytes_left>0) {
+ /* Move to next span in fastest changing dimension */
+ curr_span=curr_span->next;
+
+ if(curr_span!=NULL) {
+ /* Move location offset of destination */
+ tmp_src+=(curr_span->low-abs_arr[fast_dim])*elmt_size;
+
+ /* Move iterator for fastest changing dimension */
+ abs_arr[fast_dim]=curr_span->low;
+ } /* end if */
+ } /* end if */
+ else {
+ abs_arr[fast_dim]+=span_size/elmt_size;
+
+ /* Check if we are still within the span */
+ if(abs_arr[fast_dim]<=curr_span->high) {
+ iter->hyp.span[fast_dim]=curr_span;
+
+ goto partial_done; /* finished with partial span */
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span=curr_span->next;
+
+ /* Check if we have a valid span in this dimension still */
+ if(curr_span!=NULL) {
+ /* Reset absolute position */
+ abs_arr[fast_dim]=curr_span->low;
+ iter->hyp.span[fast_dim]=curr_span;
+
+ goto partial_done; /* finished with partial span */
+ } /* end if */
+ } /* end else */
} /* end else */
- /* Release the temporary buffer */
- H5FL_ARR_FREE(H5S_hyper_region_t,regions);
+ /* Adjust iterator pointers */
+
+ if(curr_span==NULL) {
+/* Same as code in main loop */
+ /* Start at the next fastest dim */
+ curr_dim=fast_dim-1;
+
+ /* Work back up through the dimensions */
+ while(curr_dim>=0) {
+ /* Reset the current span */
+ curr_span=iter->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 absolute position */
+ abs_arr[curr_dim]=curr_span->low;
+
+ break;
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+
+ /* Check if we are finished with the spans in the tree */
+ if(curr_dim<0) {
+ /* We had better be done with I/O or bad things are going to happen... */
+ assert(io_bytes_left==0);
+
+ goto partial_done; /* finished with partial span */
+ } /* end if */
+ else {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim]=curr_span;
+
+ /* Walk back down the iterator positions, reseting them */
+ while(curr_dim<fast_dim) {
+ assert(curr_span);
+ assert(curr_span->down);
+ assert(curr_span->down->head);
+
+ /* Set the new span for this dimension */
+ iter->hyp.span[curr_dim+1]=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+1]=curr_span->low;
+
+ /* Increment current dimension */
+ curr_dim++;
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ assert(curr_span==iter->hyp.span[fast_dim]);
+ } /* end else */
+
+ /* Reset the buffer offset */
+ for(i=0, tmp_src=src; i<ndims; i++)
+ tmp_src+=(abs_arr[i]+off_arr[i])*slab[i];
+ } /* end if */
} /* end if */
- FUNC_LEAVE (num_read);
-} /* H5S_hyper_mread() */
+partial_done: /* Yes, goto's are evil, so sue me... :-) */
+
+ /* Perform the I/O on the elements, based on the position of the iterator */
+ while(io_bytes_left>0) {
+ /* Adjust buffer offset of source to compensate for initial increment below */
+ tmp_src-=curr_span->pstride;
+
+ /* Loop over all the spans in the fastest changing dimension */
+ while(curr_span!=NULL) {
+ /* Move buffer offset of source */
+ tmp_src+=curr_span->pstride;
+
+ /* Compute the number of elements to attempt in this span */
+ assert(curr_span->nelem==(hsize_t)((size_t)(curr_span->nelem))); /*check for overflow*/
+ span_size=curr_span->nelem;
+
+ /* 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 */
+ /* "Read" the data from the source buffer */
+ HDmemcpy(dst,tmp_src,(size_t)span_size);
+
+ /* Increment offset in destination */
+ dst+=span_size;
+/* end COMMON */
+
+ /* Break out now, we are finished with I/O */
+ break;
+ } /* end if */
+ else {
+ /* Decrement I/O left to perform */
+ io_bytes_left-=span_size;
+
+/* COMMON */
+ /* "Read" the data from the source buffer */
+ HDmemcpy(dst,tmp_src,(size_t)span_size);
+
+ /* Increment offset in destination */
+ dst+=span_size;
+/* end COMMON */
+ } /* end else */
+
+ /* Move to next span in fastest changing dimension */
+ curr_span=curr_span->next;
+ } /* end while */
+
+ /* Check if we are done */
+ if(io_bytes_left==0) {
+ abs_arr[fast_dim]=curr_span->low+(span_size/elmt_size);
+
+ /* Check if we are still within the span */
+ if(abs_arr[fast_dim]<=curr_span->high) {
+ iter->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->hyp.span[fast_dim]=curr_span;
+ break;
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
+ /* Adjust iterator pointers */
+
+ /* Start at the next fastest dim */
+ curr_dim=fast_dim-1;
+
+ /* Work back up through the dimensions */
+ while(curr_dim>=0) {
+ /* Reset the current span */
+ curr_span=iter->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 absolute position */
+ abs_arr[curr_dim]=curr_span->low;
+
+ break;
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+
+ /* Check if we are finished with the spans in the tree */
+ if(curr_dim<0) {
+ /* We had better be done with I/O or bad things are going to happen... */
+ assert(io_bytes_left==0);
+ break;
+ } /* end if */
+ else {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim]=curr_span;
+
+ /* Walk back down the iterator positions, reseting them */
+ while(curr_dim<fast_dim) {
+ assert(curr_span);
+ assert(curr_span->down);
+ assert(curr_span->down->head);
+
+ /* Set the new span for the next dimension down */
+ iter->hyp.span[curr_dim+1]=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+1]=curr_span->low;
+
+ /* Increment current dimension */
+ curr_dim++;
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ assert(curr_span==iter->hyp.span[fast_dim]);
+ } /* end else */
+
+ /* Reset the buffer offset */
+ for(i=0, tmp_src=src; i<ndims; i++)
+ tmp_src+=(abs_arr[i]+off_arr[i])*slab[i];
+ } /* end while */
+
+ /* Increment amount of I/O performed */
+ iter->hyp.elmt_left-=nelem;
+
+ /* Success! */
+ ret_value=nelem;
+
+#ifdef LATER
+done:
+#endif /* LATER */
+ FUNC_LEAVE (ret_value);
+} /* end H5S_hyper_mread() */
/*-------------------------------------------------------------------------
@@ -3062,18 +3410,10 @@ H5S_hyper_mgath (const void *_buf, size_t elmt_size,
const H5S_t *mem_space, H5S_sel_iter_t *mem_iter,
hsize_t nelmts, void *_tconv_buf/*out*/)
{
- H5S_hyper_io_info_t io_info; /* Block of parameters to pass into recursive calls */
hsize_t num_read; /* number of elements read into buffer */
FUNC_ENTER (H5S_hyper_mgath, 0);
-#ifdef QAK
- printf("%s: check 1.0, elmt_size=%d, mem_space=%p\n",
- FUNC,(int)elmt_size,mem_space);
- printf("%s: check 1.0, mem_iter=%p, nelmts=%d\n",FUNC,mem_iter,nelmts);
- printf("%s: check 1.0, _buf=%p, _tconv_buf=%p\n",FUNC,_buf,_tconv_buf);
-#endif /* QAK */
-
/* Check args */
assert (elmt_size>0);
assert (mem_space);
@@ -3086,31 +3426,10 @@ H5S_hyper_mgath (const void *_buf, size_t elmt_size,
if(mem_space->select.sel_info.hslab.diminfo!=NULL) {
/* Use optimized call to read in regular hyperslab */
num_read=H5S_hyper_mread_opt(_buf,elmt_size,mem_space,mem_iter,nelmts,_tconv_buf);
- }
+ } /* end if */
else {
- /* Initialize parameter block for recursive calls */
- io_info.elmt_size=elmt_size;
- io_info.space=mem_space;
- io_info.iter=mem_iter;
- io_info.nelmts=nelmts;
- io_info.src=_buf;
- io_info.dst=_tconv_buf;
-
- /* Set up the size of the memory space */
- HDmemcpy(io_info.mem_size, mem_space->extent.u.simple.size,mem_space->extent.u.simple.rank*sizeof(hsize_t));
- io_info.mem_size[mem_space->extent.u.simple.rank]=elmt_size;
-
- /* Set the hyperslab size to copy */
- io_info.hsize[0]=1;
- H5V_array_fill(io_info.hsize, io_info.hsize, sizeof(io_info.hsize[0]),mem_space->extent.u.simple.rank);
- io_info.hsize[mem_space->extent.u.simple.rank]=elmt_size;
-
- /* Recursively input the hyperslabs currently defined */
- /* starting with the slowest changing dimension */
- num_read=H5S_hyper_mread(-1,&io_info);
-#ifdef QAK
- printf("%s: check 5.0, num_read=%d\n",FUNC,(int)num_read);
-#endif /* QAK */
+ /* Perform generic hyperslab operation */
+ num_read=H5S_hyper_mread(_buf,elmt_size,mem_space,mem_iter,nelmts,_tconv_buf);
} /* end else */
FUNC_LEAVE (num_read);
@@ -3120,144 +3439,376 @@ H5S_hyper_mgath (const void *_buf, size_t elmt_size,
/*-------------------------------------------------------------------------
* Function: H5S_hyper_mwrite
*
- * Purpose: Recursively scatters data points from memory using the parameters
- * passed to H5S_hyper_mscat.
+ * Purpose: Performs an optimized gather from a memory buffer, based on a
+ * hyperslab span selection.
*
* Return: Success: Number of elements copied.
- *
* Failure: 0
*
* Programmer: Quincey Koziol
- * Tuesday, June 16, 1998
+ * Tuesday, September 12, 2000
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
-static size_t
-H5S_hyper_mwrite (int dim, H5S_hyper_io_info_t *io_info)
+static hssize_t
+H5S_hyper_mwrite (const void *_tconv_buf, size_t elmt_size, const H5S_t *space,
+ H5S_sel_iter_t *iter, hsize_t nelem, void *_buf/*out*/)
{
- hsize_t region_size; /* Size of lowest region */
- H5S_hyper_region_t *regions; /* Pointer to array of hyperslab nodes overlapped */
- size_t num_regions; /* number of regions overlapped */
- size_t i; /* Counters */
- int j;
- hsize_t num_write=0; /* Number of elements written */
-
- FUNC_ENTER (H5S_hyper_mwrite, 0);
+ const uint8_t *src=(const uint8_t *)_tconv_buf; /* Alias for pointer arithmetic */
+ uint8_t *dst=(uint8_t *)_buf; /* Alias for pointer arithmetic */
+ uint8_t *tmp_dst; /* Alias for pointer arithmetic */
+ H5S_hyper_span_t **ispan; /* Iterator's hyperslab span nodes */
+ H5S_hyper_span_t *curr_span; /* Current hyperslab span node */
+ hsize_t slab[H5O_LAYOUT_NDIMS]; /* Cumulative size of each dimension in bytes */
+ hsize_t acc; /* Accumulator for computing cumulative sizes */
+ hssize_t *abs_arr; /* Absolute hyperslab span position */
+ hssize_t *off_arr; /* Offset within the dataspace extent */
+ int fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ int curr_dim; /* Current dimension being operated on */
+ int ndims; /* Number of dimensions of dataset */
+ size_t span_size; /* Number of bytes in current span to actually process */
+ size_t io_bytes_left; /* Number of bytes left to process */
+ int i; /* Index variable */
+ hssize_t ret_value=FAIL;
- assert(io_info);
+ FUNC_ENTER (H5S_hyper_mwrite, FAIL);
#ifdef QAK
- printf("%s: check 1.0\n",FUNC);
+printf("%s: Called!\n",FUNC);
#endif /* QAK */
- /* Get a sorted list (in the next dimension down) of the regions which */
- /* overlap the current index in this dim */
- if((regions=H5S_hyper_get_regions(&num_regions,io_info->space->extent.u.simple.rank,
- (unsigned)(dim+1),
- io_info->space->select.sel_info.hslab.hyper_lst->count,
- io_info->space->select.sel_info.hslab.hyper_lst->lo_bounds,
- io_info->iter->hyp.pos,io_info->space->select.offset))!=NULL) {
+ /* Check args */
+ assert(src);
+ assert(elmt_size>0);
+ assert(space);
+ assert(iter);
+ assert(nelem>0);
+ assert(dst);
-#ifdef QAK
- printf("%s: check 2.0, rank=%d\n",
- FUNC,(int)io_info->space->extent.u.simple.rank);
- for(i=0; i<num_regions; i++)
- printf("%s: check 2.1, region #%d: start=%d, end=%d\n",
- FUNC,i,(int)regions[i].start,(int)regions[i].end);
-#endif /* QAK */
- /* Check if this is the second to last dimension in dataset */
- /* (Which means that we've got a list of the regions in the fastest */
- /* changing dimension and should input those regions) */
- if((unsigned)(dim+2)==io_info->space->extent.u.simple.rank) {
+ /* Set the rank of the fastest changing dimension */
+ ndims=space->extent.u.simple.rank;
+ fast_dim=(ndims-1);
+
+ /* Get the pointers to the current span info and span nodes */
+ curr_span=iter->hyp.span[fast_dim];
+ abs_arr=iter->hyp.off;
+ off_arr=space->select.offset;
+ ispan=iter->hyp.span;
+
+ /* Set the amount of elements to perform I/O on, etc. */
+ assert(nelem==(hsize_t)((size_t)(nelem))); /*check for overflow*/
+ io_bytes_left=nelem*elmt_size;
+
+ /* Compute the cumulative size of dataspace dimensions */
+ for(i=fast_dim, acc=elmt_size; i>=0; i--) {
+ slab[i]=acc;
+ acc*=space->extent.u.simple.size[i];
+ } /* end for */
- /* Set up hyperslab I/O parameters which apply to all regions */
+ /* Set the offset of the first element iterated on */
+ for(i=0, tmp_dst=dst; i<ndims; i++)
+ /* Compute the sequential element offset */
+ tmp_dst+=(abs_arr[i]+space->select.offset[i])*slab[i];
- /* Copy the location of the region in the file */
- HDmemcpy(io_info->offset, io_info->iter->hyp.pos, (io_info->space->extent.u.simple.rank* sizeof(hssize_t)));
- io_info->offset[io_info->space->extent.u.simple.rank]=0;
+ /* Range check against number of elements left in selection */
+ assert(io_bytes_left<=(iter->hyp.elmt_left*elmt_size));
-#ifdef QAK
- printf("%s: check 3.0\n",FUNC);
-#endif /* QAK */
- /* perform I/O on data from regions */
- for(i=0; i<num_regions && io_info->nelmts>0; i++) {
- H5_CHECK_OVERFLOW(io_info->nelmts,hsize_t,hssize_t);
- region_size=MIN((hssize_t)io_info->nelmts, (regions[i].end-regions[i].start)+1);
- io_info->hsize[io_info->space->extent.u.simple.rank-1]=region_size;
- io_info->offset[io_info->space->extent.u.simple.rank-1]=regions[i].start;
-
- /*
- * Scatter to memory
- */
- if (H5V_hyper_copy (io_info->space->extent.u.simple.rank+1,
- io_info->hsize, io_info->mem_size, io_info->offset,
- io_info->dst, io_info->hsize, zero,
- io_info->src)<0) {
- HRETURN_ERROR (H5E_DATASPACE, H5E_READERROR, 0, "unable to gather data from memory");
- }
-
- /* Advance the pointer in the buffer */
- io_info->src = ((const uint8_t *)io_info->src) +
- region_size*io_info->elmt_size;
-
- /* Increment the number of elements read */
- num_write+=region_size;
-
- /* Decrement the buffer left */
- io_info->nelmts-=region_size;
-
- /* Set the next position to start at */
- if(region_size==(hsize_t)((regions[i].end-regions[i].start)+1)
- && i==(num_regions-1))
- io_info->iter->hyp.pos[dim+1]=(-1);
- else
- io_info->iter->hyp.pos[dim+1] = regions[i].start +
- region_size;
+ /* Take care of any partial spans leftover from previous I/Os */
+ if(abs_arr[fast_dim]!=curr_span->low) {
- /* Decrement the iterator count */
- io_info->iter->hyp.elmt_left-=region_size;
- } /* end for */
- } else { /* recurse on each region to next dimension down */
+ /* Finish the span in the fastest changing dimension */
- /* Increment the dimension we are working with */
- dim++;
+ /* Compute the number of bytes to attempt in this span */
+ span_size=((curr_span->high-abs_arr[fast_dim])+1)*elmt_size;
-#ifdef QAK
- printf("%s: check 6.0, num_regions=%d\n",FUNC,(int)num_regions);
-#endif /* QAK */
- /* Step through each region in this dimension */
- for(i=0; i<num_regions && io_info->nelmts>0; i++) {
- /* Step through each location in each region */
-#ifdef QAK
- printf("%s: check 7.0, start[%d]=%d, end[%d]=%d, nelmts=%d\n",
- FUNC, i, (int)regions[i].start, i,
- (int)regions[i].end, (int)io_info->nelmts);
-#endif /* QAK */
- for(j=MAX(io_info->iter->hyp.pos[dim],regions[i].start); j<=regions[i].end && io_info->nelmts>0; j++) {
+ /* Check number of elements against upper bounds allowed */
+ if(span_size>io_bytes_left)
+ span_size=io_bytes_left;
- /* Set the correct position we are working on */
- io_info->iter->hyp.pos[dim]=j;
+ HDmemcpy(tmp_dst,src,(size_t)span_size);
- /* Go get the regions in the next lower dimension */
- num_write+=H5S_hyper_mwrite(dim, io_info);
+ /* Increment offset in destination */
+ src+=span_size;
- /* Advance to the next row if we got the whole region */
- if(io_info->iter->hyp.pos[dim+1]==(-1))
- io_info->iter->hyp.pos[dim]=j+1;
- } /* end for */
- if(j>regions[i].end && io_info->iter->hyp.pos[dim+1]==(-1)
- && i==(num_regions-1))
- io_info->iter->hyp.pos[dim]=(-1);
- } /* end for */
+ /* Decrement I/O left to perform */
+ io_bytes_left-=span_size;
+
+ /* Check if we are done */
+ if(io_bytes_left>0) {
+ /* Move to next span in fastest changing dimension */
+ curr_span=curr_span->next;
+
+ if(curr_span!=NULL) {
+ /* Move location offset of destination */
+ tmp_dst+=(curr_span->low-abs_arr[fast_dim])*elmt_size;
+
+ /* Move iterator for fastest changing dimension */
+ abs_arr[fast_dim]=curr_span->low;
+ } /* end if */
+ } /* end if */
+ else {
+ abs_arr[fast_dim]+=span_size/elmt_size;
+
+ /* Check if we are still within the span */
+ if(abs_arr[fast_dim]<=curr_span->high) {
+ iter->hyp.span[fast_dim]=curr_span;
+
+ goto partial_done; /* finished with partial span */
+ } /* end if */
+ /* If we walked off that span, advance to the next span */
+ else {
+ /* Advance span in this dimension */
+ curr_span=curr_span->next;
+
+ /* Check if we have a valid span in this dimension still */
+ if(curr_span!=NULL) {
+ /* Reset absolute position */
+ abs_arr[fast_dim]=curr_span->low;
+ iter->hyp.span[fast_dim]=curr_span;
+
+ goto partial_done; /* finished with partial span */
+ } /* end if */
+ } /* end else */
} /* end else */
- /* Release the temporary buffer */
- H5FL_ARR_FREE(H5S_hyper_region_t,regions);
+ /* Adjust iterator pointers */
+
+ if(curr_span==NULL) {
+/* Same as code in main loop */
+ /* Start at the next fastest dim */
+ curr_dim=fast_dim-1;
+
+ /* Work back up through the dimensions */
+ while(curr_dim>=0) {
+ /* Reset the current span */
+ curr_span=iter->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 absolute position */
+ abs_arr[curr_dim]=curr_span->low;
+
+ break;
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+
+ /* Check if we are finished with the spans in the tree */
+ if(curr_dim<0) {
+ /* We had better be done with I/O or bad things are going to happen... */
+ assert(io_bytes_left==0);
+
+ goto partial_done; /* finished with partial span */
+ } /* end if */
+ else {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim]=curr_span;
+
+ /* Walk back down the iterator positions, reseting them */
+ while(curr_dim<fast_dim) {
+ assert(curr_span);
+ assert(curr_span->down);
+ assert(curr_span->down->head);
+
+ /* Set the new span_info & span for this dimension */
+ iter->hyp.span[curr_dim+1]=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+1]=curr_span->low;
+
+ /* Increment current dimension */
+ curr_dim++;
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ assert(curr_span==iter->hyp.span[fast_dim]);
+ } /* end else */
+
+ /* Reset the buffer offset */
+ for(i=0, tmp_dst=dst; i<ndims; i++)
+ tmp_dst+=(abs_arr[i]+off_arr[i])*slab[i];
+ } /* end if */
} /* end if */
- FUNC_LEAVE (num_write);
-} /* H5S_hyper_mwrite() */
+partial_done: /* Yes, goto's are evil, so sue me... :-) */
+
+ /* Perform the I/O on the elements, based on the position of the iterator */
+ while(io_bytes_left>0) {
+ /* Adjust buffer offset of destination to compensate for initial increment below */
+ tmp_dst-=(size_t)curr_span->pstride;
+
+ /* Loop over all the spans in the fastest changing dimension */
+ while(curr_span!=NULL) {
+ /* Move buffer offset of destination */
+ tmp_dst+=(size_t)curr_span->pstride;
+
+ /* Compute the number of elements to attempt in this span */
+ assert(curr_span->nelem==(hsize_t)((size_t)(curr_span->nelem))); /*check for overflow*/
+ span_size=curr_span->nelem;
+
+ /* 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 */
+ /* "Write" the data into the destination buffer */
+ HDmemcpy(tmp_dst,src,(size_t)span_size);
+
+ /* Increment offset in destination */
+ src+=span_size;
+/* end COMMON */
+
+ /* Break out now, we are finished with I/O */
+ break;
+ } /* end if */
+ else {
+ /* Decrement I/O left to perform */
+ io_bytes_left-=span_size;
+
+/* COMMON */
+ /* "Write" the data into the destination buffer */
+ HDmemcpy(tmp_dst,src,(size_t)span_size);
+
+ /* Increment offset in destination */
+ src+=span_size;
+/* end COMMON */
+ } /* end else */
+
+ /* Move to next span in fastest changing dimension */
+ curr_span=curr_span->next;
+ } /* end while */
+
+ /* Check if we are done */
+ if(io_bytes_left==0) {
+ abs_arr[fast_dim]=curr_span->low+(span_size/elmt_size);
+
+ /* Check if we are still within the span */
+ if(abs_arr[fast_dim]<=curr_span->high) {
+ iter->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->hyp.span[fast_dim]=curr_span;
+ break;
+ } /* end if */
+ } /* end else */
+ } /* end if */
+
+ /* Adjust iterator pointers */
+
+ /* Start at the next fastest dim */
+ curr_dim=fast_dim-1;
+
+ /* Work back up through the dimensions */
+ while(curr_dim>=0) {
+ /* Reset the current span */
+ curr_span=iter->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 absolute position */
+ abs_arr[curr_dim]=curr_span->low;
+
+ break;
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+
+ /* Check if we are finished with the spans in the tree */
+ if(curr_dim<0) {
+ /* We had better be done with I/O or bad things are going to happen... */
+ assert(io_bytes_left==0);
+ break;
+ } /* end if */
+ else {
+ /* Reset the span in the current dimension */
+ ispan[curr_dim]=curr_span;
+
+ /* Walk back down the iterator positions, reseting them */
+ while(curr_dim<fast_dim) {
+ assert(curr_span);
+ assert(curr_span->down);
+ assert(curr_span->down->head);
+
+ /* Set the new span_info & span for the next dimension down */
+ iter->hyp.span[curr_dim+1]=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+1]=curr_span->low;
+
+ /* Increment current dimension */
+ curr_dim++;
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ assert(curr_span==iter->hyp.span[fast_dim]);
+ } /* end else */
+
+ /* Reset the buffer offset */
+ for(i=0, tmp_dst=dst; i<ndims; i++)
+ tmp_dst+=(abs_arr[i]+off_arr[i])*slab[i];
+ } /* end while */
+
+ /* Increment amount of I/O performed */
+ iter->hyp.elmt_left-=nelem;
+
+ /* Success! */
+ ret_value=nelem;
+
+#ifdef LATER
+done:
+#endif /* LATER */
+ FUNC_LEAVE (ret_value);
+} /* end H5S_hyper_mwrite() */
/*-------------------------------------------------------------------------
@@ -3732,7 +4283,6 @@ H5S_hyper_mscat (const void *_tconv_buf, size_t elmt_size,
const H5S_t *mem_space, H5S_sel_iter_t *mem_iter,
hsize_t nelmts, void *_buf/*out*/)
{
- H5S_hyper_io_info_t io_info; /* Block of parameters to pass into recursive calls */
hsize_t num_written; /* number of elements written into buffer */
FUNC_ENTER (H5S_hyper_mscat, 0);
@@ -3749,34 +4299,10 @@ H5S_hyper_mscat (const void *_tconv_buf, size_t elmt_size,
if(mem_space->select.sel_info.hslab.diminfo!=NULL) {
/* Use optimized call to write out regular hyperslab */
num_written=H5S_hyper_mwrite_opt(_tconv_buf,elmt_size,mem_space,mem_iter,nelmts,_buf);
- }
+ } /* end if */
else {
- /* Initialize parameter block for recursive calls */
- io_info.elmt_size=elmt_size;
- io_info.space=mem_space;
- io_info.iter=mem_iter;
- io_info.nelmts=nelmts;
- io_info.src=_tconv_buf;
- io_info.dst=_buf;
-
- /* Set up the size of the memory space */
- HDmemcpy(io_info.mem_size, mem_space->extent.u.simple.size,mem_space->extent.u.simple.rank*sizeof(hsize_t));
- io_info.mem_size[mem_space->extent.u.simple.rank]=elmt_size;
-
- /* Set the hyperslab size to copy */
- io_info.hsize[0]=1;
- H5V_array_fill(io_info.hsize, io_info.hsize, sizeof(io_info.hsize[0]), mem_space->extent.u.simple.rank);
- io_info.hsize[mem_space->extent.u.simple.rank]=elmt_size;
-
- /* Recursively input the hyperslabs currently defined */
- /* starting with the slowest changing dimension */
-#ifdef QAK
- printf("%s: check 1.0\n",FUNC);
-#endif /* QAK */
- num_written=H5S_hyper_mwrite(-1,&io_info);
-#ifdef QAK
- printf("%s: check 2.0\n",FUNC);
-#endif /* QAK */
+ /* Perform generic hyperslab operation */
+ num_written=H5S_hyper_mwrite(_tconv_buf,elmt_size,mem_space,mem_iter,nelmts,_buf);
} /* end else */
FUNC_LEAVE (num_written>0 ? SUCCEED : FAIL);
@@ -3785,957 +4311,570 @@ H5S_hyper_mscat (const void *_tconv_buf, size_t elmt_size,
/*--------------------------------------------------------------------------
NAME
- H5S_hyper_bound_comp
+ H5S_hyper_npoints
PURPOSE
- Compare two hyperslab boundary elements (for qsort)
+ Compute number of elements in current selection
USAGE
- herr_t H5S_hyper_bound_comp(b1,b2)
- const H5S_hyper_bound_t *b1; IN: Pointer to the first boundary element
- const H5S_hyper_bound_t *b2; IN: Pointer to the first boundary element
+ hsize_t H5S_hyper_npoints(space)
+ H5S_t *space; IN: Pointer to dataspace
RETURNS
- <0 if b1 compares less than b2
- 0 if b1 compares equal to b2
- >0 if b1 compares greater than b2
+ The number of elements in selection on success, 0 on failure
DESCRIPTION
- Callback routine for qsort to compary boundary elements.
+ Compute number of elements in current selection.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-int
-H5S_hyper_bound_comp(const void *_b1, const void *_b2)
+hsize_t
+H5S_hyper_npoints (const H5S_t *space)
{
- const H5S_hyper_bound_t *b1=(const H5S_hyper_bound_t *)_b1; /* Ptr to first boundary element */
- const H5S_hyper_bound_t *b2=(const H5S_hyper_bound_t *)_b2; /* Ptr to second boundary element */
+ FUNC_ENTER (H5S_hyper_npoints, 0);
-#ifdef LATER
- FUNC_ENTER (H5S_hyper_bsearch, FAIL);
-#endif /* LATER */
+ /* Check args */
+ assert (space);
- assert(b1);
- assert(b2);
+ FUNC_LEAVE (space->select.num_elem);
+} /* H5S_hyper_npoints() */
- if(b1->bound<b2->bound)
- return(-1);
- if(b1->bound>b2->bound)
- return(1);
- return(0);
+
+/*--------------------------------------------------------------------------
+ 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)
+ hssize_t low, high; IN: Low and high bounds for new span node
+ H5S_hyper_span_info_t *down; IN: Down span tree for new node
+ H5S_hyper_span_t *next; IN: Next span for new node
+ RETURNS
+ Pointer to next span node on success, NULL on failure
+ DESCRIPTION
+ Allocate and initialize a new hyperslab span node, filling in the low &
+ high bounds, the down span and next span pointers also. Increment the
+ reference count of the 'down span' if applicable.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5S_hyper_span_t *
+H5S_hyper_new_span (hssize_t low, hssize_t high, H5S_hyper_span_info_t *down, H5S_hyper_span_t *next)
+{
+ H5S_hyper_span_t *ret_value=NULL;
+
+ FUNC_ENTER (H5S_hyper_new_span, NULL);
+
+ /* Allocate a new span node */
+ if((ret_value = H5FL_ALLOC(H5S_hyper_span_t,0))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Copy the span's basic information */
+ ret_value->low=low;
+ ret_value->high=high;
+ ret_value->nelem=(high-low)+1;
+ ret_value->pstride=0;
+ ret_value->down=down;
+ ret_value->next=next;
+
+ /* Increment the reference count of the 'down span' if there is one */
+ if(ret_value->down!=NULL)
+ ret_value->down->count++;
-#ifdef LATER
+done:
FUNC_LEAVE (ret_value);
-#endif /* LATER */
-} /* H5S_hyper_bsearch() */
+} /* H5S_hyper_new_span() */
/*--------------------------------------------------------------------------
NAME
- H5S_hyper_node_add
+ H5S_hyper_span_precompute_helper
PURPOSE
- Add a new node to a list of hyperslab nodes
+ Helper routine to precompute the nelem and pstrides in bytes.
USAGE
- herr_t H5S_hyper_node_add(head, start, size)
- H5S_hyper_node_t *head; IN: Pointer to head of hyperslab list
- int endflag; IN: "size" array actually contains "end" array
- unsigned rank; IN: # of dimensions of the node
- const hssize_t *start; IN: Offset of block
- const hsize_t *size; IN: Size of block
+ herr_t H5S_hyper_span_precompute_helper(span_info, elmt_size)
+ H5S_hyper_span_info_t *span_info; IN/OUT: Span tree to work on
+ size_t elmt_size; IN: element size to work with
RETURNS
- Non-negative on success/Negative on failure
+ Non-negative on success, negative on failure
DESCRIPTION
- Adds a new hyperslab node to a list of them.
+ Change the nelem and pstride values in the span tree from elements to
+ bytes using the elmt_size parameter.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-herr_t
-H5S_hyper_node_add (H5S_hyper_node_t **head, int endflag, unsigned rank, const hssize_t *start, const hsize_t *size)
+static herr_t
+H5S_hyper_span_precompute_helper (H5S_hyper_span_info_t *spans, size_t elmt_size)
{
- H5S_hyper_node_t *slab; /* New hyperslab node to add */
- unsigned u; /* Counters */
- herr_t ret_value=SUCCEED;
+ H5S_hyper_span_t *span; /* Hyperslab span */
+ herr_t ret_value=FAIL;
- FUNC_ENTER (H5S_hyper_node_add, FAIL);
+ FUNC_ENTER (H5S_hyper_span_precompute, FAIL);
- /* Check args */
- assert (head);
- assert (start);
- assert (size);
+ assert(spans);
-#ifdef QAK
- printf("%s: check 1.0, head=%p, *head=%p, rank=%u, endflag=%d\n",FUNC,head,*head,rank,endflag);
-#endif /* QAK */
- /* Create new hyperslab node to insert */
- if((slab = H5FL_ALLOC(H5S_hyper_node_t,0))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab node");
- if((slab->start = H5FL_ARR_ALLOC(hsize_t,rank,0))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab start boundary");
- if((slab->end = H5FL_ARR_ALLOC(hsize_t,rank,0))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab end boundary");
+ /* Check if we've already set this down span tree */
+ if(spans->scratch!=(void *)~(NULL)) {
+ /* Set the tree's scratch pointer */
+ spans->scratch=(void *)~(NULL);
-#ifdef QAK
- printf("%s: check 2.0, slab=%p, slab->start=%p, slab->end=%p\n",FUNC,slab,slab->start,slab->end);
-#endif /* QAK */
- /* Set boundary on new node */
- for(u=0; u<rank; u++) {
- slab->start[u]=start[u];
- if(endflag)
- slab->end[u]=size[u];
- else
- slab->end[u]=start[u]+size[u]-1;
- } /* end for */
+ /* Set the scratch pointers in all the nodes */
+ span=spans->head;
+
+ /* Loop over all the spans for this down span tree */
+ while(span!=NULL) {
+ /* If there are down spans, set their scratch value also */
+ if(span->down!=NULL) {
+ if(H5S_hyper_span_precompute_helper(span->down,elmt_size)==FAIL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't reset hyperslab scratch pointer");
+ } /* end if */
- /* Prepend on list of hyperslabs for this selection */
- slab->next=*head;
- *head=slab;
+ /* Change the nelem & pstride values into bytes */
+ span->nelem *= elmt_size;
+ span->pstride *= elmt_size;
+
+ /* Advance to next span */
+ span=span->next;
+ } /* end while */
+ } /* end if */
+
+ /* Success! */
+ ret_value=SUCCEED;
done:
FUNC_LEAVE (ret_value);
-} /* H5S_hyper_node_add() */
+} /* H5S_hyper_span_precompute_helper() */
/*--------------------------------------------------------------------------
NAME
- H5S_hyper_node_prepend
+ H5S_hyper_span_precompute
PURPOSE
- Prepend an existing node to an existing list of hyperslab nodes
+ Precompute the nelem and pstrides in bytes.
USAGE
- herr_t H5S_hyper_node_prepend(head, node)
- H5S_hyper_node_t **head; IN: Pointer to pointer to head of hyperslab list
- H5S_hyper_node_t *node; IN: Pointer to node to prepend
+ herr_t H5S_hyper_span_precompute(span_info, elmt_size)
+ H5S_hyper_span_info_t *span_info; IN/OUT: Span tree to work on
+ size_t elmt_size; IN: element size to work with
RETURNS
- Non-negative on success/Negative on failure
+ Non-negative on success, negative on failure
DESCRIPTION
- Prepends an existing hyperslab node to a list of them.
+ Change the nelem and pstride values in the span tree from elements to
+ bytes using the elmt_size parameter.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
static herr_t
-H5S_hyper_node_prepend (H5S_hyper_node_t **head, H5S_hyper_node_t *node)
+H5S_hyper_span_precompute (H5S_hyper_span_info_t *spans, size_t elmt_size)
{
- herr_t ret_value=SUCCEED;
+ herr_t ret_value=FAIL;
- FUNC_ENTER (H5S_hyper_node_prepend, FAIL);
+ FUNC_ENTER (H5S_hyper_span_precompute, FAIL);
- /* Check args */
- assert (head);
- assert (node);
+ assert(spans);
+
+ /* Call the helper routine to actually do the work */
+ if(H5S_hyper_span_precompute_helper(spans,elmt_size)==FAIL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't precompute span info");
+
+ /* Reset the scratch pointers for the next routine which needs them */
+ if(H5S_hyper_span_scratch(spans,NULL)==FAIL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't reset hyperslab scratch pointer");
- /* Prepend on list of hyperslabs for this selection */
- node->next=*head;
- *head=node;
+ /* Success! */
+ ret_value=SUCCEED;
+done:
FUNC_LEAVE (ret_value);
-} /* H5S_hyper_node_prepend() */
+} /* H5S_hyper_span_precompute() */
+
/*--------------------------------------------------------------------------
NAME
- H5S_hyper_node_release
+ H5S_hyper_span_scratch
PURPOSE
- Free the memory for a hyperslab node
+ Set the scratch pointers on hyperslab span trees
USAGE
- herr_t H5S_hyper_node_release(node)
- H5S_hyper_node_t *node; IN: Pointer to node to free
+ herr_t H5S_hyper_span_scratch(span_info)
+ H5S_hyper_span_info_t *span_info; IN: Span tree to reset
RETURNS
- Non-negative on success/Negative on failure
+ Non-negative on success, negative on failure
DESCRIPTION
- Frees a hyperslab node.
+ Set the scratch pointers on a hyperslab span tree.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
static herr_t
-H5S_hyper_node_release (H5S_hyper_node_t *node)
+H5S_hyper_span_scratch (H5S_hyper_span_info_t *spans, void *scr_value)
{
- herr_t ret_value=SUCCEED;
+ H5S_hyper_span_t *span; /* Hyperslab span */
+ herr_t ret_value=FAIL;
- FUNC_ENTER (H5S_hyper_node_release, FAIL);
+ FUNC_ENTER (H5S_hyper_span_scratch, FAIL);
- /* Check args */
- assert (node);
+ assert(spans);
+
+ /* Check if we've already set this down span tree */
+ if(spans->scratch!=scr_value) {
+ /* Set the tree's scratch pointer */
+ spans->scratch=scr_value;
- /* Free the hyperslab node */
- H5FL_ARR_FREE(hsize_t,node->start);
- H5FL_ARR_FREE(hsize_t,node->end);
- H5FL_FREE(H5S_hyper_node_t,node);
+ /* 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) {
+ if(H5S_hyper_span_scratch(span->down,scr_value)==FAIL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "can't reset hyperslab scratch pointer");
+ } /* end if */
+ /* Advance to next span */
+ span=span->next;
+ } /* end while */
+ } /* end if */
+
+ /* Success! */
+ ret_value=SUCCEED;
+
+done:
FUNC_LEAVE (ret_value);
-} /* H5S_hyper_node_release() */
+} /* H5S_hyper_span_scratch() */
/*--------------------------------------------------------------------------
NAME
- H5S_hyper_add
+ H5S_hyper_copy_span_helper
PURPOSE
- Add a block to hyperslab selection
+ Helper routine to copy a hyperslab span tree
USAGE
- herr_t H5S_hyper_add(space, start, size)
- H5S_t *space; IN: Pointer to dataspace
- const hssize_t *start; IN: Offset of block
- const hsize_t *end; IN: Offset of end of block
+ H5S_hyper_span_info_t * H5S_hyper_copy_span_helper(spans)
+ H5S_hyper_span_info_t *spans; IN: Span tree to copy
RETURNS
- Non-negative on success/Negative on failure
+ Pointer to the copied span tree on success, NULL on failure
DESCRIPTION
- Adds a block to an existing hyperslab selection.
+ Copy a hyperslab span tree, using reference counting as appropriate.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-static herr_t
-H5S_hyper_add (H5S_t *space, H5S_hyper_node_t *piece_lst)
+static H5S_hyper_span_info_t *
+H5S_hyper_copy_span_helper (H5S_hyper_span_info_t *spans)
{
- H5S_hyper_node_t *slab; /* New hyperslab node to insert */
- H5S_hyper_node_t *tmp_slab; /* Temporary hyperslab node */
- H5S_hyper_bound_t *tmp; /* Temporary pointer to an hyperslab bound array */
- size_t elem_count; /* Number of elements in hyperslab selection */
- unsigned piece_count; /* Number of hyperslab pieces being added */
- unsigned u; /* Counters */
- herr_t ret_value=SUCCEED;
-
- FUNC_ENTER (H5S_hyper_add, FAIL);
-
- /* Check args */
- assert (space);
+ H5S_hyper_span_t *span; /* Hyperslab span */
+ H5S_hyper_span_t *new_span; /* Temporary hyperslab span */
+ H5S_hyper_span_t *prev_span; /* Previous hyperslab span */
+ H5S_hyper_span_info_t *new_down; /* New down span tree */
+ H5S_hyper_span_info_t *ret_value=NULL;
- /* Count the number of hyperslab pieces to add to the selection */
- piece_count=0;
- tmp_slab=piece_lst;
- while(tmp_slab!=NULL) {
- piece_count++;
- tmp_slab=tmp_slab->next;
- } /* end while */
-
-#ifdef QAK
- printf("%s: check 1.0, piece_count=%u, lo_bounds=%p\n",
- FUNC, (unsigned)piece_count,space->select.sel_info.hslab.hyper_lst->lo_bounds);
-#endif /* QAK */
- /* Increase size of boundary arrays for dataspace's selection by piece_count */
- for(u=0; u<space->extent.u.simple.rank; u++) {
- tmp=space->select.sel_info.hslab.hyper_lst->lo_bounds[u];
-#ifdef QAK
- printf("%s: check 1.1, u=%u, space->sel_info.count=%d, tmp=%p\n",FUNC,(unsigned)u, space->select.sel_info.hslab.hyper_lst->count,tmp);
-#endif /* QAK */
- if((space->select.sel_info.hslab.hyper_lst->lo_bounds[u]=H5FL_ARR_REALLOC(H5S_hyper_bound_t,tmp,(space->select.sel_info.hslab.hyper_lst->count+piece_count)))==NULL) {
- space->select.sel_info.hslab.hyper_lst->lo_bounds[u]=tmp;
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
- "can't allocate hyperslab lo boundary array");
- } /* end if */
- } /* end for */
+ FUNC_ENTER (H5S_hyper_copy_span_helper, NULL);
- while(piece_lst!=NULL) {
-#ifdef QAK
- printf("%s: check 2.0\n",FUNC);
-#endif /* QAK */
- /* Re-use the current H5S_hyper_node_t */
- slab=piece_lst;
+ assert(spans);
- /* Don't loose place in list of nodes to add.. */
- piece_lst=piece_lst->next;
+ /* Check if the span tree was already copied */
+ if(spans->scratch!=NULL && spans->scratch!=(void *)~NULL) {
+ /* Just return the value of the already copied span tree */
+ ret_value=spans->scratch;
-#ifdef QAK
- printf("%s: check 3.0\n",FUNC);
-#endif /* QAK */
- /* Set boundary on new node */
- for(u=0,elem_count=1; u<space->extent.u.simple.rank; u++) {
-#ifdef QAK
- printf("%s: check 3.1, %u: start=%d, end=%d, elem_count=%d\n",
- FUNC,(unsigned)u,(int)start[u],(int)end[u],(int)elem_count);
-#endif /* QAK */
- elem_count*=(slab->end[u]-slab->start[u])+1;
- } /* end for */
+ /* Increment the reference count of the span tree */
+ ret_value->count++;
+ } /* end if */
+ else {
+ /* Allocate a new span_info node */
+ if((ret_value = H5FL_ALLOC(H5S_hyper_span_info_t,0))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Copy the span_info information */
+ ret_value->count=1;
+ ret_value->scratch=NULL;
+ ret_value->head=NULL;
+
+ /* Set the scratch pointer in the node being copied to the newly allocated node */
+ spans->scratch=ret_value;
+
+ /* Copy over the nodes in the span list */
+ span=spans->head;
+ prev_span=NULL;
+ while(span!=NULL) {
+ /* Allocate a new node */
+ if((new_span = H5S_hyper_new_span(span->low,span->high,NULL,NULL))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Append to list of spans */
+ if(prev_span==NULL)
+ ret_value->head=new_span;
+ else
+ prev_span->next=new_span;
- /* Initialize caching parameters */
- slab->cinfo.cached=0;
- slab->cinfo.size=elem_count;
- slab->cinfo.wleft=slab->cinfo.rleft=0;
- slab->cinfo.block=slab->cinfo.wpos=slab->cinfo.rpos=NULL;
+ /* Copy the pstride */
+ new_span->pstride=span->pstride;
-#ifdef QAK
- printf("%s: check 4.0\n",FUNC);
- {
- unsigned v;
-
- for(u=0; u<space->extent.u.simple.rank; u++) {
- for(v=0; v<space->select.sel_info.hslab.hyper_lst->count; v++) {
- printf("%s: lo_bound[%u][%u]=%d(%p)\n", FUNC,
- u,v,(int)space->select.sel_info.hslab.hyper_lst->lo_bounds[u][v].bound,
- space->select.sel_info.hslab.hyper_lst->lo_bounds[u][v].node);
- }
- }
- }
-#endif /* QAK */
- /* Insert each boundary of the hyperslab into the sorted lists of bounds */
- for(u=0; u<space->extent.u.simple.rank; u++) {
-#ifdef QAK
- printf("%s: check 4.1, start[%u]=%d, end[%u]=%d\n",
- FUNC, u, (int)slab->start[u],u,(int)slab->end[u]);
- printf("%s: check 4.1,.hslab.hyper_lst->count=%d\n",
- FUNC,(int)space->select.sel_info.hslab.hyper_lst->count);
-#endif /* QAK */
- space->select.sel_info.hslab.hyper_lst->lo_bounds[u][space->select.sel_info.hslab.hyper_lst->count].bound=slab->start[u];
- space->select.sel_info.hslab.hyper_lst->lo_bounds[u][space->select.sel_info.hslab.hyper_lst->count].node=slab;
- } /* end for */
+ /* Recurse to copy the 'down' spans, if there are any */
+ if(span->down!=NULL) {
+ if((new_down = H5S_hyper_copy_span_helper(span->down))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+ new_span->down=new_down;
+ } /* end if */
- /* Increment the number of bounds in the array */
- space->select.sel_info.hslab.hyper_lst->count++;
-#ifdef QAK
- printf("%s: check 5.0, count=%d\n",FUNC,(int)space->select.sel_info.hslab.hyper_lst->count);
-#endif /* QAK */
-
- /* Prepend on list of hyperslabs for this selection */
- slab->next=space->select.sel_info.hslab.hyper_lst->head;
- space->select.sel_info.hslab.hyper_lst->head=slab;
+ /* Update the previous (new) span */
+ prev_span=new_span;
- /* Increment the number of elements in the hyperslab selection */
- space->select.num_elem+=elem_count;
-#ifdef QAK
- printf("%s: check 6.0, elem_count=%d\n",FUNC,(int)elem_count);
- {
- unsigned v;
-
- for(u=0; u<space->extent.u.simple.rank; u++) {
- for(v=0; v<space->select.sel_info.hslab.hyper_lst->count; v++) {
- printf("%s: lo_bound[%u][%u]=%d(%p)\n", FUNC,
- u,v,(int)space->select.sel_info.hslab.hyper_lst->lo_bounds[u][v].bound,
- space->select.sel_info.hslab.hyper_lst->lo_bounds[u][v].node);
- }
- }
- }
-#endif /* QAK */
- } /* end while */
-
- /* Sort each dimension's array of bounds, now that they are all in the array */
- for(u=0; u<space->extent.u.simple.rank; u++)
- HDqsort(space->select.sel_info.hslab.hyper_lst->lo_bounds[u],space->select.sel_info.hslab.hyper_lst->count,sizeof(H5S_hyper_bound_t),H5S_hyper_bound_comp);
+ /* Advance to next span */
+ span=span->next;
+ } /* end while */
+ } /* end else */
done:
FUNC_LEAVE (ret_value);
-} /* H5S_hyper_add() */
+} /* H5S_hyper_copy_span_helper() */
/*--------------------------------------------------------------------------
NAME
- H5S_hyper_clip
+ H5S_hyper_copy_span
PURPOSE
- Clip a list of nodes against the current selection
+ Copy a hyperslab span tree
USAGE
- herr_t H5S_hyper_clip(space, nodes, uniq, overlap)
- H5S_t *space; IN: Pointer to dataspace
- H5S_hyper_node_t *nodes; IN: Pointer to list of nodes
- H5S_hyper_node_t **uniq; IN: Handle to list of non-overlapping nodes
- H5S_hyper_node_t **overlap; IN: Handle to list of overlapping nodes
+ H5S_hyper_span_info_t * H5S_hyper_copy_span(span_info)
+ H5S_hyper_span_info_t *span_info; IN: Span tree to copy
RETURNS
- Non-negative on success/Negative on failure
+ Non-negative on success, negative on failure
DESCRIPTION
- Clips a list of hyperslab nodes against the current hyperslab selection.
- The list of non-overlapping and overlapping nodes which are generated from
- this operation are returned in the 'uniq' and 'overlap' pointers. If
- either of those lists are not needed, they may be set to NULL and the
- list will be released.
+ Copy a hyperslab span tree, using reference counting as appropriate.
+ (Which means that just the nodes in the top span tree are duplicated and
+ the reference counts of their 'down spans' are just incremented)
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
- Clipping a multi-dimensional space against another multi-dimensional
- space generates at most 1 overlapping region and 2*<rank> non-overlapping
- regions, falling into the following categories in each dimension:
- Case 1 - A overlaps B on both sides:
- node <----AAAAAAAA--->
- clipped against:
- existing <-----BBBBB----->
- generates:
- overlapping <-----CCCCC----->
- non-overlapping <----D---------->
- non-overlapping <----------EE--->
-
- Case 2 - A overlaps B on one side: (need to check both sides!)
- Case 2a:
- node <------AAAAAA--->
- clipped against:
- existing <-----BBBBB----->
- generates:
- overlapping <------CCCC----->
- non-overlapping <----------EE--->
- Case 2b:
- node <---AAAAA------->
- clipped against:
- existing <-----BBBBB----->
- generates:
- overlapping <-----CCC------->
- non-overlapping <---EE---------->
-
- Case 3 - A is entirely within B:
- node <------AA------->
- clipped against:
- existing <-----BBBBB----->
- generates:
- overlapping <------CC------->
-
- Case 4 - A is entirely outside B: (doesn't matter which side)
- node <-----------AAA->
- clipped against:
- existing <-----BBBBB----->
- generates:
- non-overlapping <-----------AAA->
-
- This algorithm could be sped up by keeping track of the last (existing)
- region the new node was compared against when it was split and resume
- comparing against the region following that one when it's returned to
- later (for non-overlapping blocks).
-
- Another optimization is to build a n-tree (not certain about how many
- times each dimension should be cut, but at least once) for the dataspace
- and build a list of existing blocks which overlap each "n"-tant and only
- compare the new nodes against existing node in the region of the n-tree
- which the are located in.
-
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-herr_t
-H5S_hyper_clip (H5S_t *space, H5S_hyper_node_t *nodes, H5S_hyper_node_t **uniq,
- H5S_hyper_node_t **overlap)
+static H5S_hyper_span_info_t *
+H5S_hyper_copy_span (H5S_hyper_span_info_t *spans)
{
- H5S_hyper_node_t *region, /* Temp. hyperslab selection region pointer */
- *node, /* Temp. hyperslab node pointer */
- *next_node, /* Pointer to next node in node list */
- *new_nodes=NULL; /* List of new nodes added */
- hssize_t *start=NULL; /* Temporary arrays of start & sizes (for splitting nodes) */
- hsize_t *end=NULL; /* Temporary arrays of start & sizes (for splitting nodes) */
- unsigned rank; /* Cached copy of the rank of the dataspace */
- int overlapped; /* Flag for overlapping nodes */
- int non_intersect; /* Flag for non-intersecting nodes */
- unsigned u; /* Counters */
- enum /* Cases for edge overlaps */
- {OVERLAP_BOTH,OVERLAP_LOWER,OVERLAP_UPPER,WITHIN,NO_OVERLAP} clip_case;
- herr_t ret_value=SUCCEED;
+ H5S_hyper_span_info_t *ret_value=NULL;
- FUNC_ENTER (H5S_hyper_clip, FAIL);
+ FUNC_ENTER (H5S_hyper_copy_span, NULL);
- /* Check args */
- assert (space);
- assert (nodes);
- assert (uniq || overlap);
+ assert(spans);
- /* Allocate space for the temporary starts & sizes */
- if((start = H5FL_ARR_ALLOC(hsize_t,space->extent.u.simple.rank,0))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab start array");
- if((end = H5FL_ARR_ALLOC(hsize_t,space->extent.u.simple.rank,0))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab size array");
+ /* Copy the hyperslab span tree */
+ ret_value=H5S_hyper_copy_span_helper(spans);
- /* Set up local variables */
- rank=space->extent.u.simple.rank;
-#ifdef QAK
- printf("%s: check 1.0, start=%p, end=%p\n",FUNC,start,end);
-#endif /* QAK */
+ /* Reset the scratch pointers for the next routine which needs them */
+ if(H5S_hyper_span_scratch(spans,NULL)==FAIL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, NULL, "can't reset span tree scratch pointers");
- /*
- * Cycle through all the hyperslab nodes, clipping them against the
- * existing hyperslab selection.
- */
- node=nodes;
- while(node!=NULL) {
-#ifdef QAK
- printf("%s: check 2.0, node=%p, nodes=%p\n",FUNC,node,nodes);
-#endif /* QAK */
- /* Remove current node from head of list to evaulate it */
- next_node=node->next; /* retain next node in list */
- node->next=NULL; /* just to be safe */
-#ifdef QAK
- printf("%s: check 2.1, node=%p, next_node=%p\n",FUNC,node,next_node);
- printf("node->start={",FUNC);
- for(u=0; u<rank; u++) {
- printf("%d",(int)node->start[u]);
- if(u<rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
- printf("node->end={",FUNC);
- for(u=0; u<rank; u++) {
- printf("%d",(int)node->end[u]);
- if(u<rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
- region=new_nodes;
- while(region!=NULL) {
- printf("new_nodes=%p, new_nodes->next=%p\n",region,region->next);
- printf("\tstart={",FUNC);
- for(u=0; u<rank; u++) {
- printf("%d",(int)region->start[u]);
- if(u<rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
- printf("\tend={",FUNC);
- for(u=0; u<rank; u++) {
- printf("%d",(int)region->end[u]);
- if(u<rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
- region=region->next;
- } /* end while */
+done:
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_copy_span() */
- region=space->select.sel_info.hslab.hyper_lst->head;
- while(region!=NULL) {
- printf("region=%p, region->next=%p\n",region,region->next);
- printf("\tstart={",FUNC);
- for(u=0; u<rank; u++) {
- printf("%d",(int)region->start[u]);
- if(u<rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
- printf("\tend={",FUNC);
- for(u=0; u<rank; u++) {
- printf("%d",(int)region->end[u]);
- if(u<rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
- region=region->next;
- } /* end while */
-#endif /* QAK */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_cmp_spans
+ PURPOSE
+ Check if two hyperslab slabs are the same
+ USAGE
+ htri_d H5S_hyper_cmp_spans(span1, span2)
+ H5S_hyper_span_t *span1; IN: First span tree to compare
+ H5S_hyper_span_t *span2; IN: Second span tree to compare
+ RETURNS
+ TRUE (1) or FALSE (0) on success, negative on failure
+ DESCRIPTION
+ Compare two hyperslab slabs to determine if they refer to the same
+ selection. If span1 & span2 are both NULL, that counts as equal
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_hyper_cmp_spans (H5S_hyper_span_info_t *span_info1, H5S_hyper_span_info_t *span_info2)
+{
+ H5S_hyper_span_t *span1;
+ H5S_hyper_span_t *span2;
+ htri_t nest=FAIL;
+ htri_t ret_value=FAIL;
- overlapped=0; /* Reset overlapped flag */
- region=space->select.sel_info.hslab.hyper_lst->head;
- while(region!=NULL && overlapped==0) {
-#ifdef QAK
- printf("%s: check 3.0, new_nodes=%p, region=%p, head=%p, overlapped=%d\n",FUNC,new_nodes,region,space->select.sel_info.hslab.hyper_lst->head,overlapped);
- printf("region->start={",FUNC);
- for(u=0; u<rank; u++) {
- printf("%d",(int)region->start[u]);
- if(u<rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
- printf("region->end={",FUNC);
- for(u=0; u<rank; u++) {
- printf("%d",(int)region->end[u]);
- if(u<rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
-#endif /* QAK */
- /* Check for intersection */
- for(u=0, non_intersect=0; u<rank && non_intersect==0; u++) {
- if(node->end[u]<region->start[u] || node->start[u]>region->end[u])
- non_intersect=1;
- } /* end for */
+ FUNC_ENTER (H5S_hyper_cmp_spans, FAIL);
-#ifdef QAK
- printf("%s: check 3.0.1, new_nodes=%p, region=%p, head=%p, non_intersect=%d\n",FUNC,new_nodes,region,space->select.sel_info.hslab.hyper_lst->head,non_intersect);
-#endif /* QAK */
- /* Only compare node with regions that actually intersect */
- if(non_intersect==0) {
- /* Compare the boundaries of the two objects in each dimension */
- for(u=0; u<rank && overlapped==0; u++) {
- /* Find overlap case we are in */
-
- /* True if case 1, 4 or 2b */
- if(node->start[u]<region->start[u]) {
-#ifdef QAK
- printf("%s: check 3.1, overlapped=%d\n",FUNC,overlapped);
-#endif /* QAK */
- /* Test for case 4 */
- /* NO_OVERLAP cases could be taken out, but are left in for clarity */
- if(node->end[u]<region->start[u]) {
-#ifdef QAK
- printf("%s: check 3.1.1, overlapped=%d\n",FUNC,overlapped);
-#endif /* QAK */
- clip_case=NO_OVERLAP;
- assert("invalid clipping case" && 0);
- } /* end if */
- else {
-#ifdef QAK
- printf("%s: check 3.1.2, overlapped=%d\n",FUNC,overlapped);
-#endif /* QAK */
- /* Test for case 2b */
- if(node->end[u]<=region->end[u]) {
-#ifdef QAK
- printf("%s: check 3.1.2.1, overlapped=%d\n",FUNC,overlapped);
-#endif /* QAK */
- clip_case=OVERLAP_LOWER;
- } /* end if */
- /* Must be case 1 */
- else {
-#ifdef QAK
- printf("%s: check 3.1.2.2, overlapped=%d\n",FUNC,overlapped);
-#endif /* QAK */
- clip_case=OVERLAP_BOTH;
- } /* end else */
- } /* end else */
+ /* Check for redundant comparison */
+ if(span_info1==span_info2)
+ ret_value=TRUE;
+ else {
+ /* Check for both spans being NULL */
+ if(span_info1==NULL && span_info2==NULL)
+ ret_value=TRUE;
+ else {
+ /* Check for one span being NULL */
+ if(span_info1==NULL || span_info2==NULL)
+ ret_value=FALSE;
+ else {
+ /* Get the pointers to the actual lists of spans */
+ span1=span_info1->head;
+ span2=span_info2->head;
+
+ /* Sanity checking */
+ assert(span1);
+ assert(span2);
+
+ /* infinite loop which must be broken out of */
+ while (1) {
+ /* Check for both spans being NULL */
+ if(span1==NULL && span2==NULL) {
+ ret_value=TRUE;
+ break;
} /* end if */
- /* Case 2a, 3 or 4 (on the other side)*/
else {
-#ifdef QAK
- printf("%s: check 3.2, overlapped=%d\n",FUNC,overlapped);
-#endif /* QAK */
- /* Test for case 4 */
- if(node->start[u]>region->end[u]) {
-#ifdef QAK
- printf("%s: check 3.2.1, overlapped=%d\n",FUNC,overlapped);
-#endif /* QAK */
- clip_case=NO_OVERLAP;
- assert("invalid clipping case" && 0);
+ /* Check for one span being NULL */
+ if(span1==NULL || span2==NULL) {
+ ret_value=FALSE;
+ break;
} /* end if */
- /* Case 2a or 3 */
else {
-#ifdef QAK
- printf("%s: check 3.2.2, overlapped=%d\n",FUNC,overlapped);
-#endif /* QAK */
- /* Test for case 2a */
- if(node->end[u]>region->end[u]) {
-#ifdef QAK
- printf("%s: check 3.2.2.1, overlapped=%d\n",FUNC,overlapped);
-#endif /* QAK */
- clip_case=OVERLAP_UPPER;
+ /* 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 */
- /* Must be case 3 */
else {
-#ifdef QAK
- printf("%s: check 3.2.2.2, overlapped=%d\n",FUNC,overlapped);
-#endif /* QAK */
- clip_case=WITHIN;
+ if(span1->down!=NULL || span2!=NULL) {
+ if((nest=H5S_hyper_cmp_spans(span1->down,span2->down))==FAIL) {
+ ret_value=FAIL;
+ break;
+ } /* end if */
+ else {
+ if(nest==FALSE) {
+ ret_value=FALSE;
+ break;
+ } /* end if */
+ else {
+ /* Keep going... */
+ } /* end else */
+ } /* end else */
+ } /* end if */
+ else {
+ /* Keep going... */
+ } /* end else */
} /* end else */
} /* end else */
} /* end else */
-
- if(clip_case!=WITHIN) {
-#ifdef QAK
- printf("%s: check 3.3, new_nodes=%p\n",FUNC,new_nodes);
-#endif /* QAK */
- /* Copy all the dimensions start & end points */
- HDmemcpy(start,node->start,rank*sizeof(hssize_t));
- HDmemcpy(end,node->end,rank*sizeof(hssize_t));
- } /* end if */
-
- /* Work on upper overlapping block */
- if(clip_case==OVERLAP_BOTH || clip_case==OVERLAP_LOWER) {
-#ifdef QAK
- printf("%s: check 3.4, new_nodes=%p\n",FUNC,new_nodes);
-#endif /* QAK */
- /* Modify the end point in the current dimension of the overlap */
- end[u]=region->start[u]-1;
- /* Clip the existing non-overlapped portion off the current node */
- node->start[u]=region->start[u];
- /* Add the non-overlapping portion to the list of new nodes */
- if(H5S_hyper_node_add(&new_nodes,1,rank,(const hssize_t *)start,(const hsize_t *)end)<0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslab");
-#ifdef QAK
- printf("%s: check 3.4.1, new_nodes=%p\n",FUNC,new_nodes);
-#ifdef QAK
-{
- H5S_hyper_node_t *tmp_reg; /* Temp. hyperslab selection region pointer */
- unsigned v;
-
- tmp_reg=space->select.sel_info.hslab.hyper_lst->head;
- while(tmp_reg!=NULL) {
- printf("tmp_reg=%p\n",tmp_reg);
- printf("\tstart={",FUNC);
- for(v=0; v<rank; v++) {
- printf("%d",(int)tmp_reg->start[v]);
- if(v<rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
- printf("\tend={",FUNC);
- for(v=0; v<rank; v++) {
- printf("%d",(int)tmp_reg->end[v]);
- if(v<rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
- tmp_reg=tmp_reg->next;
- } /* end while */
-}
-#endif /* QAK */
-#endif /* QAK */
- } /* end if */
-#ifdef QAK
- printf("%s: check 3.4.5, new_nodes=%p\n",FUNC,new_nodes);
-#endif /* QAK */
- /* Work on lower overlapping block */
- if(clip_case==OVERLAP_BOTH || clip_case==OVERLAP_UPPER) {
- /* Modify the start & end point in the current dimension of the overlap */
- start[u]=region->end[u]+1;
- end[u]=node->end[u];
- /* Clip the existing non-overlapped portion off the current node */
- node->end[u]=region->end[u];
- /* Add the non-overlapping portion to the list of new nodes */
-#ifdef QAK
- printf("%s: check 3.5, &new_nodes=%p, new_nodes=%p\n",FUNC,&new_nodes,new_nodes);
-#endif /* QAK */
- if(H5S_hyper_node_add(&new_nodes,1,rank,(const hssize_t *)start,(const hsize_t *)end)<0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslab");
-#ifdef QAK
- printf("%s: check 3.5.1, &new_nodes=%p, new_nodes=%p\n",FUNC,&new_nodes,new_nodes);
-#ifdef QAK
-{
- H5S_hyper_node_t *tmp_reg; /* Temp. hyperslab selection region pointer */
- unsigned v;
-
- tmp_reg=space->select.sel_info.hslab.hyper_lst->head;
- while(tmp_reg!=NULL) {
- printf("tmp_reg=%p\n",tmp_reg);
- printf("\tstart={",FUNC);
- for(v=0; v<rank; v++) {
- printf("%d",(int)tmp_reg->start[v]);
- if(v<rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
- printf("\tend={",FUNC);
- for(v=0; v<rank; v++) {
- printf("%d",(int)tmp_reg->end[v]);
- if(v<rank-1)
- printf(", ");
- } /* end for */
- printf("}\n");
- tmp_reg=tmp_reg->next;
- } /* end while */
-}
-#endif /* QAK */
-#endif /* QAK */
- } /* end if */
-
-#ifdef QAK
- printf("%s: check 3.5.5, new_nodes=%p\n",FUNC,new_nodes);
-#endif /* QAK */
- /* Check if this is the last dimension */
- /* Add the block to the "overlapped" list, if so */
- /* Allow the algorithm to proceed to the next dimension otherwise */
- if(u==(rank-1)) {
-#ifdef QAK
- printf("%s: check 3.6, overlapped=%d\n",FUNC,overlapped);
-#endif /* QAK */
- if(overlap!=NULL) {
- if(H5S_hyper_node_prepend(overlap,node)<0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslab");
- }
- else { /* Free the node if we aren't going to keep it */
-#ifdef QAK
- printf("%s: check 3.6.1, node=%p\n",FUNC,node);
-#endif /* QAK */
- H5S_hyper_node_release(node);
- } /* end else */
- overlapped=1; /* stop the algorithm for this block */
- } /* end if */
- } /* end for */
- } /* end if */
-
- /* Advance to next hyperslab region */
- region=region->next;
- } /* end while */
-
- /* Check whether we should add the node to the non-overlapping list */
- if(!overlapped) {
-#ifdef QAK
- printf("%s: check 3.7, node=%p\n",FUNC,node);
-#endif /* QAK */
- if(uniq!=NULL) {
- if(H5S_hyper_node_prepend(uniq,node)<0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslab");
- }
- else { /* Free the node if we aren't going to keep it */
-#ifdef QAK
- printf("%s: check 3.7.1\n",FUNC);
-#endif /* QAK */
- H5S_hyper_node_release(node);
+ /* Advance to the next nodes in the span list */
+ span1=span1->next;
+ span2=span2->next;
+ } /* end while */
} /* end else */
- } /* end if */
-
- /* Advance to next hyperslab node */
- node=next_node;
-
- /* Check if we've added more nodes from splitting to the list */
- if(node==NULL && new_nodes!=NULL) {
- node=new_nodes;
- new_nodes=NULL;
- } /* end if */
- } /* end while */
+ } /* end else */
+ } /* end else */
+#ifdef LATER
done:
- if(start!=NULL)
- H5FL_ARR_FREE(hsize_t,start);
- if(end!=NULL)
- H5FL_ARR_FREE(hsize_t,end);
-
+#endif /* LATER */
FUNC_LEAVE (ret_value);
-} /* H5S_hyper_clip() */
+} /* H5S_hyper_cmp_spans() */
/*--------------------------------------------------------------------------
NAME
- H5S_hyper_release
+ H5S_hyper_free_span_info
PURPOSE
- Release hyperslab selection information for a dataspace
+ Free a hyperslab span info node
USAGE
- herr_t H5S_hyper_release(space)
- H5S_t *space; IN: Pointer to dataspace
+ herr_t H5S_hyper_free_span_info(span_info)
+ H5S_hyper_span_info_t *span_info; IN: Span info node to free
RETURNS
- Non-negative on success/Negative on failure
+ Non-negative on success, negative on failure
DESCRIPTION
- Releases all hyperslab selection information for a dataspace
+ Free a hyperslab span info node, along with all the span nodes and the
+ 'down spans' from the nodes, if reducing their reference count to zero
+ indicates it is appropriate to do so.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
- * Robb Matzke, 1998-08-25
- * The fields which are freed are set to NULL to prevent them from being
- * freed again later. This fixes some allocation problems where
- * changing the hyperslab selection of one data space causes a core dump
- * when closing some other data space.
--------------------------------------------------------------------------*/
-herr_t
-H5S_hyper_release (H5S_t *space)
+static herr_t
+H5S_hyper_free_span_info (H5S_hyper_span_info_t *span_info)
{
- H5S_hyper_node_t *curr,*next; /* Pointer to hyperslab nodes */
- unsigned u; /* Counters */
+ H5S_hyper_span_t *span, *next_span;
+ herr_t ret_value=SUCCEED;
- FUNC_ENTER (H5S_hyper_release, FAIL);
+ FUNC_ENTER (H5S_hyper_free_span_info, FAIL);
- /* Check args */
- assert (space && H5S_SEL_HYPERSLABS==space->select.type);
-#ifdef QAK
- printf("%s: check 1.0\n",FUNC);
-#endif /* QAK */
+ assert(span_info);
- /* Reset the number of points selected */
- space->select.num_elem=0;
+ /* Decrement the span tree's reference count */
+ span_info->count--;
- /* Release the regular selection info */
- if(space->select.sel_info.hslab.diminfo!=NULL) {
- H5FL_ARR_FREE(H5S_hyper_dim_t,space->select.sel_info.hslab.diminfo);
- space->select.sel_info.hslab.diminfo = NULL;
- H5FL_ARR_FREE(H5S_hyper_dim_t,space->select.sel_info.hslab.app_diminfo);
- space->select.sel_info.hslab.app_diminfo = NULL;
- } /* end if */
+ /* Free the span tree if the reference count drops to zero */
+ if(span_info->count==0) {
- /* Release irregular hyperslab information */
- if(space->select.sel_info.hslab.hyper_lst!=NULL) {
- /* Release hi and lo boundary information */
- if(space->select.sel_info.hslab.hyper_lst->lo_bounds!=NULL) {
- for(u=0; u<space->extent.u.simple.rank; u++) {
- H5FL_ARR_FREE(H5S_hyper_bound_t,space->select.sel_info.hslab.hyper_lst->lo_bounds[u]);
- space->select.sel_info.hslab.hyper_lst->lo_bounds[u] = NULL;
- } /* end for */
- H5FL_ARR_FREE(H5S_hyper_bound_ptr_t,space->select.sel_info.hslab.hyper_lst->lo_bounds);
- space->select.sel_info.hslab.hyper_lst->lo_bounds = NULL;
- } /* end if */
-
- /* Release list of selected regions */
- curr=space->select.sel_info.hslab.hyper_lst->head;
- while(curr!=NULL) {
- next=curr->next;
- H5S_hyper_node_release(curr);
- curr=next;
+ /* Work through the list of spans pointed to by this 'info' node */
+ span=span_info->head;
+ while(span!=NULL) {
+ next_span=span->next;
+ if(H5S_hyper_free_span(span)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab span");
+ span=next_span;
} /* end while */
- /* Release hyperslab selection node itself */
- H5FL_FREE(H5S_hyper_list_t,space->select.sel_info.hslab.hyper_lst);
- space->select.sel_info.hslab.hyper_lst=NULL;
+ /* Free this span info */
+ H5FL_FREE(H5S_hyper_span_info_t,span_info);
} /* end if */
-#ifdef QAK
- printf("%s: check 2.0\n",FUNC);
-#endif /* QAK */
+done:
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_free_span_info() */
- FUNC_LEAVE (SUCCEED);
-} /* H5S_hyper_release() */
/*--------------------------------------------------------------------------
NAME
- H5S_hyper_npoints
+ H5S_hyper_free_span
PURPOSE
- Compute number of elements in current selection
+ Free a hyperslab span node
USAGE
- hsize_t H5S_hyper_npoints(space)
- H5S_t *space; IN: Pointer to dataspace
+ herr_t H5S_hyper_free_span(span)
+ H5S_hyper_span_t *span; IN: Span node to free
RETURNS
- The number of elements in selection on success, 0 on failure
+ Non-negative on success, negative on failure
DESCRIPTION
- Compute number of elements in current selection.
+ Free a hyperslab span node, along with the 'down spans' from the node,
+ if reducing their reference count to zero indicates it is appropriate to
+ do so.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-hsize_t
-H5S_hyper_npoints (const H5S_t *space)
+static herr_t
+H5S_hyper_free_span (H5S_hyper_span_t *span)
{
- FUNC_ENTER (H5S_hyper_npoints, 0);
+ herr_t ret_value=SUCCEED;
- /* Check args */
- assert (space);
+ FUNC_ENTER (H5S_hyper_free_span, FAIL);
- FUNC_LEAVE (space->select.num_elem);
-} /* H5S_hyper_npoints() */
-
-/*--------------------------------------------------------------------------
- NAME
- H5S_hyper_sel_iter_release
- PURPOSE
- Release hyperslab selection iterator information for a dataspace
- USAGE
- herr_t H5S_hyper_sel_iter_release(sel_iter)
- H5S_t *space; IN: Pointer to dataspace iterator is for
- H5S_sel_iter_t *sel_iter; IN: Pointer to selection iterator
- RETURNS
- Non-negative on success/Negative on failure
- DESCRIPTION
- Releases all information for a dataspace hyperslab selection iterator
- GLOBAL VARIABLES
- COMMENTS, BUGS, ASSUMPTIONS
- EXAMPLES
- REVISION LOG
---------------------------------------------------------------------------*/
-herr_t
-H5S_hyper_sel_iter_release (H5S_sel_iter_t *sel_iter)
-{
- FUNC_ENTER (H5S_hyper_sel_iter_release, FAIL);
+ assert(span);
- /* Check args */
- assert (sel_iter);
+ /* Decrement the reference count of the 'down spans', freeing them if appropriate */
+ if(span->down!=NULL) {
+ if(H5S_hyper_free_span_info(span->down)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab span tree");
+ } /* end if */
- if(sel_iter->hyp.pos!=NULL)
- H5FL_ARR_FREE(hsize_t,sel_iter->hyp.pos);
+ /* Free this span */
+ H5FL_FREE(H5S_hyper_span_t,span);
+
+done:
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_free_span() */
- FUNC_LEAVE (SUCCEED);
-} /* H5S_hyper_sel_iter_release() */
-
-/*-------------------------------------------------------------------------
- * Function: H5S_hyper_compare_bounds
- *
- * Purpose: Compares two bounds for equality
- *
- * Return: an integer less than, equal to, or greater than zero if the first
- * region is considered to be respectively less than, equal to, or
- * greater than the second
- *
- * Programmer: Quincey Koziol
- * Friday, July 17, 1998
- *
- * Modifications:
- *
- *-------------------------------------------------------------------------
- */
-int
-H5S_hyper_compare_bounds (const void *r1, const void *r2)
-{
- if(((const H5S_hyper_bound_t *)r1)->bound<((const H5S_hyper_bound_t *)r2)->bound)
- return(-1);
- else
- if(((const H5S_hyper_bound_t *)r1)->bound>((const H5S_hyper_bound_t *)r2)->bound)
- return(1);
- else
- return(0);
-} /* end H5S_hyper_compare_bounds */
/*--------------------------------------------------------------------------
NAME
@@ -4759,11 +4898,8 @@ H5S_hyper_compare_bounds (const void *r1, const void *r2)
herr_t
H5S_hyper_copy (H5S_t *dst, const H5S_t *src)
{
- H5S_hyper_list_t *new_hyper=NULL; /* New hyperslab selection */
- H5S_hyper_node_t *curr, *new_node, *new_head; /* Hyperslab information nodes */
H5S_hyper_dim_t *new_diminfo=NULL; /* New per-dimension info array[rank] */
unsigned u; /* Counters */
- size_t v; /* Counters */
herr_t ret_value=SUCCEED; /* return value */
FUNC_ENTER (H5S_hyper_copy, FAIL);
@@ -4771,9 +4907,6 @@ H5S_hyper_copy (H5S_t *dst, const H5S_t *src)
assert(src);
assert(dst);
-#ifdef QAK
- printf("%s: check 3.0\n", FUNC);
-#endif /* QAK */
/* Check if there is regular hyperslab information to copy */
if(src->select.sel_info.hslab.diminfo!=NULL) {
/* Create the per-dimension selection info */
@@ -4807,90 +4940,81 @@ H5S_hyper_copy (H5S_t *dst, const H5S_t *src)
dst->select.sel_info.hslab.app_diminfo = new_diminfo;
} /* end else */
- /* Check if there is irregular hyperslab information to copy */
- if(src->select.sel_info.hslab.hyper_lst!=NULL) {
- /* Create the new hyperslab information node */
- if((new_hyper = H5FL_ALLOC(H5S_hyper_list_t,0))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
- "can't allocate point node");
-
- /* Copy the basic hyperslab selection information */
- *new_hyper=*(src->select.sel_info.hslab.hyper_lst);
-
-#ifdef QAK
- printf("%s: check 4.0\n", FUNC);
-#endif /* QAK */
- /* Allocate space for the low & high bound arrays */
- if((new_hyper->lo_bounds = H5FL_ARR_ALLOC(H5S_hyper_bound_ptr_t,src->extent.u.simple.rank,0))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
- "can't allocate boundary node");
- for(u=0; u<src->extent.u.simple.rank; u++) {
- if((new_hyper->lo_bounds[u] = H5FL_ARR_ALLOC(H5S_hyper_bound_t,src->select.sel_info.hslab.hyper_lst->count,0))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
- "can't allocate boundary list");
- } /* end for */
+ /* Check if there is hyperslab span information to copy */
+ if(src->select.sel_info.hslab.span_lst!=NULL) {
+ /* Copy the hyperslab span information */
+ dst->select.sel_info.hslab.span_lst=H5S_hyper_copy_span(src->select.sel_info.hslab.span_lst);
+ } /* end if */
-#ifdef QAK
- printf("%s: check 5.0\n", FUNC);
-#endif /* QAK */
- /* Copy the hyperslab selection nodes, adding them to the lo & hi bound arrays also */
- curr=src->select.sel_info.hslab.hyper_lst->head;
- new_head=NULL;
- v=0;
- while(curr!=NULL) {
-#ifdef QAK
- printf("%s: check 5.1\n", FUNC);
-#endif /* QAK */
- /* Create each point */
- if((new_node = H5FL_ALLOC(H5S_hyper_node_t,0))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
- "can't allocate point node");
- HDmemcpy(new_node,curr,sizeof(H5S_hyper_node_t)); /* copy caching information */
- if((new_node->start = H5FL_ARR_ALLOC(hsize_t,src->extent.u.simple.rank,0))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
- "can't allocate coordinate information");
- if((new_node->end = H5FL_ARR_ALLOC(hsize_t,src->extent.u.simple.rank,0))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
- "can't allocate coordinate information");
- HDmemcpy(new_node->start,curr->start,(src->extent.u.simple.rank*sizeof(hssize_t)));
- HDmemcpy(new_node->end,curr->end,(src->extent.u.simple.rank*sizeof(hssize_t)));
- new_node->next=NULL;
-
- /* Insert into low & high bound arrays */
- for(u=0; u<src->extent.u.simple.rank; u++) {
- new_hyper->lo_bounds[u][v].bound=new_node->start[u];
- new_hyper->lo_bounds[u][v].node=new_node;
- } /* end for */
- v++; /* Increment the location of the next node in the boundary arrays */
+done:
+ FUNC_LEAVE (ret_value);
+} /* end H5S_hyper_copy() */
- /* Keep the order the same when copying */
- if(new_head==NULL)
- new_head=new_hyper->head=new_node;
- else {
- new_head->next=new_node;
- new_head=new_node;
- } /* end else */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_select_valid_helper
+ PURPOSE
+ Check whether the selection fits within the extent, with the current
+ offset defined.
+ USAGE
+ htri_t H5S_hyper_select_valid_helper(spans, offset, rank);
+ const H5S_hyper_span_info_t *spans; IN: Pointer to current hyperslab span tree
+ const hssize_t *offset; IN: Pointer to offset array
+ const hsize_t *size; IN: Pointer to size array
+ hsize_t rank; IN: Current rank looking at
+ RETURNS
+ TRUE if the selection fits within the extent, FALSE if it does not and
+ Negative on an error.
+ DESCRIPTION
+ Determines if the current selection at the current offet fits within the
+ extent for the dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static htri_t
+H5S_hyper_select_valid_helper (const H5S_hyper_span_info_t *spans, const hssize_t *offset, const hsize_t *size, hsize_t rank)
+{
+ H5S_hyper_span_t *curr; /* Hyperslab information nodes */
+ htri_t tmp; /* temporary return value */
+ htri_t ret_value=TRUE; /* return value */
- curr=curr->next;
- } /* end while */
-#ifdef QAK
- printf("%s: check 6.0\n", FUNC);
-#endif /* QAK */
+ FUNC_ENTER (H5S_hyper_select_valid_helper, FAIL);
+
+ assert(spans);
+ assert(offset);
+ assert(size);
+ assert(rank<H5O_LAYOUT_NDIMS);
+
+ /* Check each point to determine whether selection+offset is within extent */
+ curr=spans->head;
+ while(curr!=NULL && ret_value==TRUE) {
+ /* Check if an offset has been defined */
+ /* Bounds check the selected point + offset against the extent */
+ if(((curr->low+offset[rank])>(hssize_t)size[rank])
+ || ((curr->low+offset[rank])<0)
+ || ((curr->high+offset[rank])>(hssize_t)size[rank])
+ || ((curr->high+offset[rank])<0)) {
+ ret_value=FALSE;
+ break;
+ } /* end if */
- /* Sort the boundary array */
- for(u=0; u<src->extent.u.simple.rank; u++)
- HDqsort(new_hyper->lo_bounds[u], new_hyper->count, sizeof(H5S_hyper_bound_t), H5S_hyper_compare_bounds);
-#ifdef QAK
- printf("%s: check 7.0\n", FUNC);
-#endif /* QAK */
- } /* end if */
+ /* Recurse if this node has down spans */
+ if(curr->down!=NULL) {
+ if((tmp=H5S_hyper_select_valid_helper(curr->down,offset,size,rank+1))!=TRUE) {
+ ret_value=tmp;
+ break;
+ } /* end if */
+ } /* end if */
- /* Attach the hyperslab information to the destination dataspace */
- dst->select.sel_info.hslab.hyper_lst=new_hyper;
+ /* Advance to next node */
+ curr=curr->next;
+ } /* end while */
-done:
FUNC_LEAVE (ret_value);
-} /* end H5S_hyper_copy() */
+} /* end H5S_hyper_select_valid_helper() */
/*--------------------------------------------------------------------------
@@ -4916,7 +5040,6 @@ done:
htri_t
H5S_hyper_select_valid (const H5S_t *space)
{
- H5S_hyper_node_t *curr; /* Hyperslab information nodes */
unsigned u; /* Counter */
htri_t ret_value=TRUE; /* return value */
@@ -4953,28 +5076,64 @@ H5S_hyper_select_valid (const H5S_t *space)
} /* end for */
} /* end if */
else {
- /* Check each point to determine whether selection+offset is within extent */
- curr=space->select.sel_info.hslab.hyper_lst->head;
- while(curr!=NULL && ret_value==TRUE) {
- /* Check each dimension */
- for(u=0; u<space->extent.u.simple.rank; u++) {
- /* Check if an offset has been defined */
- /* Bounds check the selected point + offset against the extent */
- if(((curr->start[u]+space->select.offset[u])>(hssize_t)space->extent.u.simple.size[u])
- || ((curr->start[u]+space->select.offset[u])<0)
- || ((curr->end[u]+space->select.offset[u])>(hssize_t)space->extent.u.simple.size[u])
- || ((curr->end[u]+space->select.offset[u])<0)) {
- ret_value=FALSE;
- break;
- } /* end if */
- } /* end for */
+ /* Call the recursive routine to validate the span tree */
+ ret_value=H5S_hyper_select_valid_helper(space->select.sel_info.hslab.span_lst,space->select.offset,space->extent.u.simple.size,(hsize_t)0);
+ } /* end else */
- curr=curr->next;
+ FUNC_LEAVE (ret_value);
+} /* end H5S_hyper_select_valid() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_span_nblocks
+ PURPOSE
+ Count the number of blocks in a span tree
+ USAGE
+ hssize_t H5S_hyper_span_nblocks(spans)
+ const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of
+ RETURNS
+ Number of blocks in span tree on success; negative on failure
+ DESCRIPTION
+ Counts the number of blocks described by the spans in a span tree.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hssize_t
+H5S_hyper_span_nblocks (H5S_hyper_span_info_t *spans)
+{
+ H5S_hyper_span_t *span; /* Hyperslab span */
+ hssize_t ret_value=FAIL;
+
+ FUNC_ENTER (H5S_hyper_span_nblocks, FAIL);
+
+ /* Count the number of elements in the span tree */
+ if(spans==NULL)
+ ret_value=0;
+ else {
+ span=spans->head;
+ ret_value=0;
+ while(span!=NULL) {
+ /* If there are down spans, add the total down span blocks */
+ if(span->down!=NULL)
+ ret_value+=H5S_hyper_span_nblocks(span->down);
+ /* If there are no down spans, just count the block in this span */
+ else
+ ret_value++;
+
+ /* Advance to next span */
+ span=span->next;
} /* end while */
- } /* end while */
+ } /* end else */
+#ifdef LATER
+done:
+#endif /* LATER */
FUNC_LEAVE (ret_value);
-} /* end H5S_hyper_select_valid() */
+} /* H5S_hyper_span_nblocks() */
+
/*--------------------------------------------------------------------------
NAME
@@ -4998,7 +5157,6 @@ H5S_hyper_select_valid (const H5S_t *space)
hssize_t
H5S_hyper_select_serial_size (const H5S_t *space)
{
- H5S_hyper_node_t *curr; /* Hyperslab information nodes */
unsigned u; /* Counter */
hssize_t block_count; /* block counter for regular hyperslabs */
hssize_t ret_value=FAIL; /* return value */
@@ -5021,17 +5179,92 @@ H5S_hyper_select_serial_size (const H5S_t *space)
ret_value+=8*block_count*space->extent.u.simple.rank;
} /* end if */
else {
- /* Spin through hyperslabs to total the space needed to store them */
- curr=space->select.sel_info.hslab.hyper_lst->head;
- while(curr!=NULL) {
- /* Add 8 bytes times the rank for each element selected */
- ret_value+=8*space->extent.u.simple.rank;
- curr=curr->next;
- } /* end while */
+ /* Spin through hyperslab spans, adding 8 * rank bytes for each block */
+ block_count=H5S_hyper_span_nblocks(space->select.sel_info.hslab.span_lst);
+ ret_value+=8*space->extent.u.simple.rank*block_count;
} /* end else */
FUNC_LEAVE (ret_value);
} /* end H5S_hyper_select_serial_size() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_select_serialize_helper
+ PURPOSE
+ Serialize the current selection into a user-provided buffer.
+ USAGE
+ herr_t H5S_hyper_select_serialize_helper(spans, start, end, rank, buf)
+ H5S_hyper_span_info_t *spans; IN: Hyperslab span tree to serialize
+ hssize_t start[]; IN/OUT: Accumulated start points
+ hssize_t end[]; IN/OUT: Accumulated end points
+ hsize_t rank; IN: Current rank looking at
+ uint8 *buf; OUT: Buffer to put serialized selection into
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Serializes the current element selection into a buffer. (Primarily for
+ storing on disk).
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_select_serialize_helper (const H5S_hyper_span_info_t *spans, hssize_t *start, hssize_t *end, hsize_t rank, uint8_t **buf)
+{
+ H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */
+ hsize_t u; /* Index variable */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER (H5S_hyper_select_serialize_helper, FAIL);
+
+ /* Sanity checks */
+ assert(spans);
+ assert(start);
+ assert(end);
+ assert(rank<H5O_LAYOUT_NDIMS);
+ assert(buf && *buf);
+
+ /* Walk through the list of spans, recursing or outputing them */
+ curr=spans->head;
+ while(curr!=NULL) {
+ /* Recurse if this node has down spans */
+ if(curr->down!=NULL) {
+ /* Add the starting and ending points for this span to the list */
+ start[rank]=curr->low;
+ end[rank]=curr->high;
+
+ /* Recurse down to the next dimension */
+ if(H5S_hyper_select_serialize_helper(curr->down,start,end,rank+1,buf)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans");
+ } /* end if */
+ else {
+ /* Encode all the previous dimensions starting & ending points */
+
+ /* Encode previous starting points */
+ for(u=0; u<rank; u++)
+ UINT32ENCODE(*buf, (uint32_t)start[u]);
+
+ /* Encode starting point for this span */
+ UINT32ENCODE(*buf, (uint32_t)curr->low);
+
+ /* Encode previous ending points */
+ for(u=0; u<rank; u++)
+ UINT32ENCODE(*buf, (uint32_t)end[u]);
+
+ /* Encode starting point for this span */
+ UINT32ENCODE(*buf, (uint32_t)curr->high);
+ } /* end else */
+
+ /* Advance to next node */
+ curr=curr->next;
+ } /* end while */
+
+done:
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_select_serialize_helper() */
+
/*--------------------------------------------------------------------------
NAME
@@ -5058,12 +5291,12 @@ H5S_hyper_select_serialize (const H5S_t *space, uint8_t *buf)
H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */
hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary hyperslab counts */
hssize_t offset[H5O_LAYOUT_NDIMS]; /* Offset of element in dataspace */
+ hssize_t start[H5O_LAYOUT_NDIMS]; /* Location of start of hyperslab */
+ hssize_t end[H5O_LAYOUT_NDIMS]; /* Location of end of hyperslab */
hssize_t temp_off; /* Offset in a given dimension */
- H5S_hyper_node_t *curr; /* Hyperslab information nodes */
uint8_t *lenp; /* pointer to length location for later storage */
uint32_t len=0; /* number of bytes used */
int i; /* local counting variable */
- unsigned u; /* local counting variable */
hssize_t block_count; /* block counter for regular hyperslabs */
int fast_dim; /* Rank of the fastest changing dimension for the dataspace */
int temp_dim; /* Temporary rank holder */
@@ -5071,7 +5304,7 @@ H5S_hyper_select_serialize (const H5S_t *space, uint8_t *buf)
int done; /* Whether we are done with the iteration */
herr_t ret_value=FAIL; /* return value */
- FUNC_ENTER (H5S_point_select_serialize, FAIL);
+ FUNC_ENTER (H5S_hyper_select_serialize, FAIL);
assert(space);
@@ -5093,17 +5326,9 @@ H5S_hyper_select_serialize (const H5S_t *space, uint8_t *buf)
fast_dim=ndims-1;
diminfo=space->select.sel_info.hslab.diminfo;
-#ifdef QAK
- printf("%s: Serializing regular selection\n",FUNC);
- for(i=0; i<ndims; i++)
- printf("%s: (%d) start=%d, stride=%d, count=%d, block=%d\n",FUNC,i,(int)diminfo[i].start,(int)diminfo[i].stride,(int)diminfo[i].count,(int)diminfo[i].block);
-#endif /*QAK */
/* Check each dimension */
for(block_count=1,i=0; i<ndims; i++)
block_count*=diminfo[i].count;
-#ifdef QAK
-printf("%s: block_count=%d\n",FUNC,(int)block_count);
-#endif /*QAK */
/* Encode number of hyperslabs */
UINT32ENCODE(buf, (uint32_t)block_count);
@@ -5127,18 +5352,10 @@ printf("%s: block_count=%d\n",FUNC,(int)block_count);
/* Add 8 bytes times the rank for each hyperslab selected */
len+=8*ndims;
-#ifdef QAK
-for(i=0; i<ndims; i++)
- printf("%s: offset(%d)=%d\n",FUNC,i,(int)offset[i]);
-#endif /*QAK */
/* Encode hyperslab starting location */
for(i=0; i<ndims; i++)
UINT32ENCODE(buf, (uint32_t)offset[i]);
-#ifdef QAK
-for(i=0; i<ndims; i++)
- printf("%s: offset+block-1(%d)=%d\n",FUNC,i,(int)(offset[i]+(diminfo[i].block-1)));
-#endif /*QAK */
/* Encode hyperslab ending location */
for(i=0; i<ndims; i++)
UINT32ENCODE(buf, (uint32_t)(offset[i]+(diminfo[i].block-1)));
@@ -5187,25 +5404,15 @@ for(i=0; i<ndims; i++)
} /* end if */
else {
/* Encode number of hyperslabs */
- UINT32ENCODE(buf, (uint32_t)space->select.sel_info.hslab.hyper_lst->count);
+ block_count=H5S_hyper_span_nblocks(space->select.sel_info.hslab.span_lst);
+ UINT32ENCODE(buf, (uint32_t)block_count);
len+=4;
- /* Encode each hyperslab in selection */
- curr=space->select.sel_info.hslab.hyper_lst->head;
- while(curr!=NULL) {
- /* Add 8 bytes times the rank for each hyperslab selected */
- len+=8*space->extent.u.simple.rank;
-
- /* Encode starting point */
- for(u=0; u<space->extent.u.simple.rank; u++)
- UINT32ENCODE(buf, (uint32_t)curr->start[u]);
-
- /* Encode ending point */
- for(u=0; u<space->extent.u.simple.rank; u++)
- UINT32ENCODE(buf, (uint32_t)curr->end[u]);
+ /* Add 8 bytes times the rank for each hyperslab selected */
+ len+=8*space->extent.u.simple.rank*block_count;
- curr=curr->next;
- } /* end while */
+ /* Encode each hyperslab in selection */
+ H5S_hyper_select_serialize_helper(space->select.sel_info.hslab.span_lst,start,end,(hsize_t)0,&buf);
} /* end else */
/* Encode length */
@@ -5216,6 +5423,7 @@ for(i=0; i<ndims; i++)
FUNC_LEAVE (ret_value);
} /* H5S_hyper_select_serialize() */
+
/*--------------------------------------------------------------------------
NAME
@@ -5294,9 +5502,8 @@ H5S_hyper_select_deserialize (H5S_t *space, const uint8_t *buf)
*tblock=(*tend-*tstart)+1;
/* Select or add the hyperslab to the current selection */
- if((ret_value=H5S_select_hyperslab(space,(i==0 ? H5S_SELECT_SET : H5S_SELECT_OR),start,NULL,count,block))<0) {
+ if((ret_value=H5S_select_hyperslab(space,(i==0 ? H5S_SELECT_SET : H5S_SELECT_OR),start,NULL,count,block))<0)
HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't change selection");
- } /* end if */
} /* end for */
/* Free temporary buffers */
@@ -5308,6 +5515,178 @@ H5S_hyper_select_deserialize (H5S_t *space, const uint8_t *buf)
done:
FUNC_LEAVE (ret_value);
} /* H5S_hyper_select_deserialize() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_span_blocklist
+ PURPOSE
+ Get a list of hyperslab blocks currently selected
+ USAGE
+ herr_t H5S_hyper_span_blocklist(spans, start, end, rank, startblock, numblocks, buf)
+ H5S_hyper_span_info_t *spans; IN: Dataspace pointer of selection to query
+ hssize_t start[]; IN/OUT: Accumulated start points
+ hssize_t end[]; IN/OUT: Accumulated end points
+ hsize_t rank; IN: Rank of dataspace
+ hsize_t *startblock; IN/OUT: Hyperslab block to start with
+ hsize_t *numblocks; IN/OUT: Number of hyperslab blocks to get
+ hsize_t **buf; OUT: List of hyperslab blocks selected
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Puts a list of the hyperslab blocks into the user's buffer. The blocks
+ start with the '*startblock'th block in the list of blocks and put
+ '*numblocks' number of blocks into the user's buffer (or until the end of
+ the list of blocks, whichever happens first)
+ The block coordinates have the same dimensionality (rank) as the
+ dataspace they are located within. The list of blocks is formatted as
+ follows: <"start" coordinate> immediately followed by <"opposite" corner
+ coordinate>, followed by the next "start" and "opposite" coordinate, etc.
+ until all the block information requested has been put into the user's
+ buffer.
+ No guarantee of any order of the blocks is implied.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_hyper_span_blocklist(H5S_hyper_span_info_t *spans, hssize_t start[], hssize_t end[], hsize_t rank, hsize_t *startblock, hsize_t *numblocks, hsize_t **buf)
+{
+ H5S_hyper_span_t *curr; /* Pointer to current hyperslab span */
+ hsize_t u; /* Index variable */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER (H5S_hyper_span_blocklist, FAIL);
+
+ /* Sanity checks */
+ assert(spans);
+ assert(rank<H5O_LAYOUT_NDIMS);
+ assert(start);
+ assert(end);
+ assert(startblock);
+ assert(numblocks && *numblocks>0);
+ assert(buf && *buf);
+
+ /* Walk through the list of spans, recursing or outputing them */
+ curr=spans->head;
+ while(curr!=NULL && *numblocks>0) {
+ /* Recurse if this node has down spans */
+ if(curr->down!=NULL) {
+ /* Add the starting and ending points for this span to the list */
+ start[rank]=curr->low;
+ end[rank]=curr->high;
+
+ /* Recurse down to the next dimension */
+ if(H5S_hyper_span_blocklist(curr->down,start,end,rank+1,startblock,numblocks,buf)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans");
+ } /* end if */
+ else {
+ /* Skip this block if we haven't skipped all the startblocks yet */
+ if(*startblock>0) {
+ /* Decrement the starting block */
+ (*startblock)--;
+ }
+ /* Process this block */
+ else {
+ /* Encode all the previous dimensions starting & ending points */
+
+ /* Copy previous starting points */
+ for(u=0; u<rank; u++, (*buf)++)
+ HDmemcpy(*buf, &start[u], sizeof(hsize_t));
+
+ /* Copy starting point for this span */
+ HDmemcpy(*buf, &curr->low, sizeof(hsize_t));
+ (*buf)++;
+
+ /* Copy previous ending points */
+ for(u=0; u<rank; u++, (*buf)++)
+ HDmemcpy(*buf, &end[u], sizeof(hsize_t));
+
+ /* Copy starting point for this span */
+ HDmemcpy(*buf, &curr->high, sizeof(hsize_t));
+ (*buf)++;
+
+ /* Decrement the number of blocks processed */
+ (*numblocks)--;
+ } /* end else */
+ } /* end else */
+
+ /* Advance to next node */
+ curr=curr->next;
+ } /* end while */
+
+done:
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_span_blocklist() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_bounds_helper
+ PURPOSE
+ Gets the bounding box containing the selection.
+ USAGE
+ htri_t H5S_hyper_bounds_helper(spans, offset, rank);
+ const H5S_hyper_span_info_t *spans; IN: Pointer to current hyperslab span tree
+ const hssize_t *offset; IN: Pointer to offset array
+ hsize_t rank; IN: Current rank looking at
+ hsize_t *start; OUT: Start array bounds
+ hsize_t *end; OUT: End array bounds
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Retrieves the bounding box containing the current selection and places
+ it into the user's buffers. The start and end buffers must be large
+ enough to hold the dataspace rank number of coordinates. The bounding box
+ exactly contains the selection, ie. if a 2-D element selection is currently
+ defined with the following points: (4,5), (6,8) (10,7), the bounding box
+ with be (4, 5), (10, 8).
+ The bounding box calculations _does_ include the current offset of the
+ selection within the dataspace extent.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_bounds_helper (const H5S_hyper_span_info_t *spans, const hssize_t *offset, hsize_t rank, hsize_t *start, hsize_t *end)
+{
+ H5S_hyper_span_t *curr; /* Hyperslab information nodes */
+ herr_t ret_value=SUCCEED; /* return value */
+
+ FUNC_ENTER (H5S_hyper_bounds_helper, FAIL);
+
+ assert(spans);
+ assert(offset);
+ assert(rank<H5O_LAYOUT_NDIMS);
+ assert(start);
+ assert(end);
+
+ /* Check each point to determine whether selection+offset is within extent */
+ curr=spans->head;
+ while(curr!=NULL) {
+ /* Check if the current span extends the bounding box */
+ if((curr->low+offset[rank])<(hssize_t)start[rank])
+ start[rank]=curr->low+offset[rank];
+ if((curr->high+offset[rank])>(hssize_t)end[rank])
+ end[rank]=curr->high+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) {
+ ret_value=FAIL;
+ break;
+ } /* end if */
+ } /* end if */
+
+ /* Advance to next node */
+ curr=curr->next;
+ } /* end while */
+
+ FUNC_LEAVE (ret_value);
+} /* end H5S_hyper_bounds_helper() */
+
/*--------------------------------------------------------------------------
NAME
@@ -5338,9 +5717,6 @@ done:
herr_t
H5S_hyper_bounds(H5S_t *space, hsize_t *start, hsize_t *end)
{
- H5S_hyper_node_t *node; /* Hyperslab node */
- int rank; /* Dataspace rank */
- int i; /* index variable */
herr_t ret_value=SUCCEED; /* return value */
FUNC_ENTER (H5S_hyper_bounds, FAIL);
@@ -5349,12 +5725,14 @@ H5S_hyper_bounds(H5S_t *space, hsize_t *start, hsize_t *end)
assert(start);
assert(end);
- /* Get the dataspace extent rank */
- rank=space->extent.u.simple.rank;
-
/* Check for a "regular" hyperslab selection */
if(space->select.sel_info.hslab.diminfo!=NULL) {
const H5S_hyper_dim_t *diminfo=space->select.sel_info.hslab.diminfo; /* local alias for diminfo */
+ int rank; /* Dataspace rank */
+ int i; /* index variable */
+
+ /* Get the dataspace extent rank */
+ rank=space->extent.u.simple.rank;
/* Check each dimension */
for(i=0; i<rank; i++) {
@@ -5366,17 +5744,8 @@ H5S_hyper_bounds(H5S_t *space, hsize_t *start, hsize_t *end)
} /* end for */
} /* end if */
else {
- /* Iterate through the node, copying each hyperslab's information */
- node=space->select.sel_info.hslab.hyper_lst->head;
- while(node!=NULL) {
- for(i=0; i<rank; i++) {
- if(start[i]>(hsize_t)(node->start[i]+space->select.offset[i]))
- start[i]=node->start[i]+space->select.offset[i];
- if(end[i]<(hsize_t)(node->end[i]+space->select.offset[i]))
- end[i]=node->end[i]+space->select.offset[i];
- } /* end for */
- node=node->next;
- } /* end while */
+ /* Call the recursive routine to get the bounds for the span tree */
+ ret_value=H5S_hyper_bounds_helper(space->select.sel_info.hslab.span_lst,space->select.offset,(hsize_t)0,start,end);
} /* end if */
FUNC_LEAVE (ret_value);
@@ -5405,15 +5774,15 @@ htri_t
H5S_hyper_select_contiguous(const H5S_t *space)
{
htri_t ret_value=FAIL; /* return value */
- H5S_hyper_node_t *node; /* Hyperslab node */
- unsigned rank; /* Dataspace rank */
+ H5S_hyper_span_info_t *spans; /* Hyperslab span info node */
+ H5S_hyper_span_t *span; /* Hyperslab span node */
unsigned u; /* index variable */
FUNC_ENTER (H5S_hyper_select_contiguous, FAIL);
assert(space);
- /* Check for a "regular" hyperslab selection */
+ /* Quicker check for a "regular" hyperslab selection */
if(space->select.sel_info.hslab.diminfo != NULL) {
/*
* For a regular hyperslab to be contiguous, it must have only one
@@ -5430,33 +5799,1861 @@ H5S_hyper_select_contiguous(const H5S_t *space)
} /* end for */
} /* end if */
else {
- /* If there is more than one hyperslab in the selection, they are not contiguous */
- if(space->select.sel_info.hslab.hyper_lst->count>1)
+ /*
+ * For a hyperslab to be contiguous, it's size must be the same as the
+ * dataspace extent's in all but the slowest changing dimension
+ */
+ ret_value=TRUE; /* assume true and reset if the dimensions don't match */
+
+ /* Get information for slowest changing information */
+ spans=space->select.sel_info.hslab.span_lst;
+ span=spans->head;
+
+ /* If there are multiple spans in the slowest changing dimension, the selection isn't contiguous */
+ if(span->next!=NULL)
ret_value=FALSE;
- else { /* If there is one hyperslab, then it might be contiguous */
- /* Get the dataspace extent rank */
- rank=space->extent.u.simple.rank;
-
- /* Get the hyperslab node */
- node=space->select.sel_info.hslab.hyper_lst->head;
-
- /*
- * For a hyperslab to be contiguous, it's size must be the same as the
- * dataspace extent's in all but the slowest changing dimension
- */
- ret_value=TRUE; /* assume true and reset if the dimensions don't match */
- for(u=1; u<rank; u++) {
- if(((node->end[u]-node->start[u])+1)!=(hssize_t)space->extent.u.simple.size[u]) {
- ret_value=FALSE;
+ else {
+ /* Now check the rest of the dimensions */
+ if(span->down!=NULL) {
+ u=1; /* Current dimension working on */
+
+ /* Get the span information for the next fastest dimension */
+ spans=span->down;
+
+ /* Cycle down the spans until we run out of down spans or find a non-contiguous span */
+ while(spans!=NULL) {
+ span=spans->head;
+
+ /* Check that this is the only span and it spans the entire dimension */
+ if(span->next!=NULL) {
+ ret_value=FALSE;
+ break;
+ } /* end if */
+ else {
+ /* If this span doesn't cover the entire dimension, then this selection isn't contiguous */
+ if(((span->high-span->low)+1)!=(hssize_t)space->extent.u.simple.size[u]) {
+ ret_value=FALSE;
+ break;
+ } /* end if */
+ else {
+ /* Walk down to the next span */
+ spans=span->down;
+
+ /* Increment dimension */
+ u++;
+ } /* end else */
+ } /* end else */
+ } /* end while */
+ } /* end if */
+ } /* end else */
+ } /* end else */
+
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_select_contiguous() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_select_iterate_helper
+ PURPOSE
+ Internal routine to iterate over the elements of a span tree hyperslab selection
+ USAGE
+ herr_t H5S_iterate_hyperslab_io(iter_info)
+ H5S_hyper_iter_info_t *iter_info; IN/OUT: Block of iteration parameters to pass into recursive calls
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Iterates over the elements in a hyperslab span tree selection, calling a
+ user's callback routine for each element.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_select_iterate_helper(H5S_hyper_iter_info_t *iter_info)
+{
+ const H5S_t *space; /* Dataspace operating with */
+ H5S_sel_iter_t *iter; /* Selection iterator */
+ H5S_hyper_span_t *curr_span; /* Current hyperslab span node */
+ hsize_t slab[H5O_LAYOUT_NDIMS]; /* Cumulative size of each dimension in bytes */
+ hsize_t acc; /* Accumulator for computing cumulative sizes */
+ hssize_t off_arr[H5O_LAYOUT_NDIMS]; /* Current hyperslab span position */
+ int fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ int curr_dim; /* Current dimension being operated on */
+ int ndims; /* Number of dimensions of dataset */
+ hsize_t span_io; /* Number of elements in current span to actually process */
+ herr_t user_ret=0; /* User's return value */
+ uint8_t *loc; /* Current element location pointer */
+ hsize_t loc_off; /* Element offset in the dataspace */
+ int i; /* Index variable */
+ unsigned u; /* Index variable */
+ hssize_t ret_value=FAIL;
+
+ FUNC_ENTER (H5S_hyper_select_iterate_helper, FAIL);
+
+ /* Check args */
+ assert(iter_info);
+
+ /* Retrieve some information from the interation info */
+ space=iter_info->space;
+ iter=iter_info->iter;
+
+ /* Set the rank of the fastest changing dimension */
+ ndims=space->extent.u.simple.rank;
+ fast_dim=(ndims-1);
+
+ /* Get the pointers to the current span info and span nodes */
+ curr_span=iter->hyp.span[fast_dim];
+
+ /* Compute the cumulative size of dataspace dimensions */
+ for(i=fast_dim, acc=iter_info->elem_size; i>=0; i--) {
+ slab[i]=acc;
+ acc*=space->extent.u.simple.size[i];
+ } /* end for */
+
+ /* Set the offset of the first element iterated on */
+ for(i=0, loc_off=0; i<ndims; i++) {
+ /* Set the location */
+ off_arr[i]=iter->hyp.span[i]->low;
+
+ /* Compute the sequential element offset */
+ loc_off+=off_arr[i]*slab[i];
+ } /* end for */
+
+ /* Perform the I/O on the elements, based on the position of the iterator */
+ user_ret=0;
+ while(curr_span!=NULL && user_ret==0) {
+ /* Compute the number of elements to attempt in this span */
+ span_io=(curr_span->high-curr_span->low)+1;
+
+ /* Iterate through all the span elements */
+ for(u=0, loc=(uint8_t *)iter_info->src+loc_off; u<span_io && user_ret==0; u++) {
+ /* Call the user's callback routine */
+ user_ret=(*(iter_info->op))(loc,iter_info->dt,(hsize_t)ndims,off_arr,iter_info->op_data);
+
+ /* Increment the element location */
+ off_arr[fast_dim]++;
+
+ /* Increment the buffer offset */
+ loc+=slab[fast_dim];
+ } /* end for */
+
+ /* Get out now for user return values not zero */
+ if(user_ret!=0)
+ break;
+
+ /* Adjust iterator pointers */
+
+ /* Advance span in fastest dimension */
+ curr_span=curr_span->next;
+
+ /* See if we are still in the fastest changing dimension */
+ if(curr_span!=NULL) {
+ /* Move the buffer offset */
+ loc_off+=(span_io+(curr_span->low-off_arr[fast_dim]))*iter_info->elem_size;
+
+ /* Move the element location */
+ off_arr[fast_dim]=curr_span->low;
+ } /* end if */
+ /* We walked off the spans for the fastest dimension, work our way back up */
+ else {
+ /* Start at the fastest dim */
+ curr_dim=fast_dim-1;
+
+ /* Get the pointer to the correct dimension */
+ curr_span=iter->hyp.span[curr_dim];
+
+ /* Work back up through the dimensions */
+ while(curr_dim>=0) {
+ /* Increment position in span */
+ off_arr[curr_dim]++;
+
+ /* Check if we are still within the span */
+ if(off_arr[curr_dim]<=curr_span->high) {
break;
} /* end if */
- } /* end for */
+ /* 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 offset for the dim */
+ off_arr[curr_dim]=curr_span->low;
+
+ break;
+ } /* end if */
+ else {
+ /* If we finished the span list in this dimension, decrement the dimension worked on and loop again */
+ curr_dim--;
+
+ /* Reset the curr_span to the next dim */
+ if(curr_dim>=0)
+ curr_span=iter->hyp.span[curr_dim];
+ } /* end else */
+ } /* end else */
+ } /* end while */
+
+ /* Check if we are finished with the spans in the tree */
+ if(curr_dim<0) {
+ /* We had better be done with I/O or bad things are going to happen... */
+ break;
+ } /* end if */
+ else {
+ /* Reset the span in the current dimension */
+ iter->hyp.span[curr_dim]=curr_span;
+
+ /* Walk back down the iterator positions, reseting them */
+ while(curr_dim<fast_dim) {
+ assert(curr_span);
+ assert(curr_span->down);
+ assert(curr_span->down->head);
+
+ /* Set the new span for this dimension */
+ iter->hyp.span[curr_dim+1]=curr_span->down->head;
+
+ /* Advance span down the tree */
+ curr_span=curr_span->down->head;
+
+ /* Reset the offset for the dim */
+ off_arr[curr_dim+1]=curr_span->low;
+
+ /* Increment current dimension */
+ curr_dim++;
+ } /* end while */
+
+ /* Verify that the curr_span points to the fastest dim */
+ assert(curr_span==iter->hyp.span[fast_dim]);
+
+ /* Verify that the offset is correct for the fastest dim */
+ assert(off_arr[fast_dim]==curr_span->low);
+ } /* end else */
+
+ /* Reset the buffer offset */
+ for(i=0, loc_off=0; i<ndims; i++)
+ loc_off+=off_arr[i]*slab[i];
} /* end else */
+ } /* end while */
+
+ /* Success! */
+ ret_value=(user_ret==0 ? SUCCEED : user_ret);
+
+#ifdef LATER
+done:
+#endif /* LATER */
+ FUNC_LEAVE (ret_value);
+} /* end H5S_hyper_select_iterate_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_select_iterate_mem_opt
+ PURPOSE
+ Iterate over the data points in a regular hyperslab selection, calling a
+ user's function for each element.
+ USAGE
+ herr_t H5S_hyper_select_iterate_mem_opt(buf, type_id, space, op, operator_data)
+ H5S_sel_iter_t *iter; IN/OUT: Selection iterator
+ void *buf; IN/OUT: Buffer containing elements to iterate over
+ hid_t type_id; IN: Datatype ID of BUF array.
+ H5S_t *space; IN: Dataspace object containing selection to iterate over
+ H5D_operator_t op; IN: Function pointer to the routine to be
+ called for each element in BUF iterated over.
+ void *op_data; IN/OUT: Pointer to any user-defined data associated
+ with the operation.
+ RETURNS
+ Returns the return value of the last operator if it was non-zero, or zero
+ if all elements were processed. Otherwise returns a negative value.
+ DESCRIPTION
+ Iterates over the selected elements in a memory buffer, calling the user's
+ callback function for each element. The selection in the dataspace is
+ modified so that any elements already iterated over are removed from the
+ selection if the iteration is interrupted (by the H5D_operator_t function
+ returning non-zero) in the "middle" of the iteration and may be re-started
+ by the user where it left off.
+
+ NOTE: Until "subtracting" elements from a selection is implemented,
+ the selection is not modified.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_select_iterate_mem_opt(H5S_sel_iter_t * UNUSED iter, void *buf, hid_t type_id, H5S_t *space, H5D_operator_t op,
+ void *op_data)
+{
+ H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */
+ hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary hyperslab counts */
+ hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary hyperslab blocks */
+ hssize_t offset[H5O_LAYOUT_NDIMS]; /* Offset of element in dataspace */
+ hsize_t slab[H5O_LAYOUT_NDIMS]; /* Size of objects in buffer */
+ size_t elem_size; /* Size of data element in buffer */
+ hssize_t temp_off; /* Offset in a given dimension */
+ uint8_t *loc; /* Current element location */
+ int i; /* Counter */
+ unsigned u; /* Counter */
+ int fast_dim; /* Rank of the fastest changing dimension for the dataspace */
+ int temp_dim; /* Temporary rank holder */
+ unsigned ndims; /* Rank of the dataspace */
+ herr_t user_ret=0; /* User's return value */
+
+ FUNC_ENTER (H5S_hyper_select_iterate_mem_opt, FAIL);
+
+ /* Set some convienence values */
+ ndims=space->extent.u.simple.rank;
+ fast_dim=ndims-1;
+ diminfo=space->select.sel_info.hslab.diminfo;
+
+ /* Get the data element size */
+ elem_size=H5Tget_size(type_id);
+
+ /* Elements in the fastest dimension are 'elem_size' */
+ slab[ndims-1]=elem_size;
+
+ /* If we have two or more dimensions, build the other dimension's element sizes */
+ if(ndims>=2) {
+ /* Build the table of next-dimension down 'element' sizes */
+ for(i=ndims-2; i>=0; i--)
+ slab[i]=slab[i+1]*space->extent.u.simple.size[i+1];
+ } /* end if */
+
+ /* Build the tables of count & block sizes as well as the initial offset */
+ for(u=0; u<ndims; u++) {
+ tmp_count[u]=diminfo[u].count;
+ tmp_block[u]=diminfo[u].block;
+ offset[u]=diminfo[u].start;
+ } /* end for */
+
+ /* Initialize the starting location */
+ for(loc=buf,u=0; u<ndims; u++)
+ loc+=diminfo[u].start*slab[u];
+
+ /* Go iterate over the hyperslabs */
+ while(user_ret==0) {
+ /* Iterate over the blocks in the fastest dimension */
+ while(tmp_count[fast_dim]>0 && user_ret==0) {
+
+ /* Iterate over the elements in the fastest dimension */
+ while(tmp_block[fast_dim]>0 && user_ret==0) {
+ user_ret=(*op)(loc,type_id,(hsize_t)ndims,offset,op_data);
+
+ /* Increment the buffer location */
+ loc+=slab[fast_dim];
+
+ /* Increment the offset in the dataspace */
+ offset[fast_dim]++;
+
+ /* Decrement the sequence count */
+ tmp_block[fast_dim]--;
+ } /* end while */
+
+ /* Reset the sequence count */
+ tmp_block[fast_dim]=diminfo[fast_dim].block;
+
+ /* Move the location to the next sequence to start */
+ loc+=(diminfo[fast_dim].stride-diminfo[fast_dim].block)*slab[fast_dim];
+
+ /* Move the offset to the next sequence to start */
+ offset[fast_dim]+=(diminfo[fast_dim].stride-diminfo[fast_dim].block);
+
+ /* Decrement the block count */
+ tmp_count[fast_dim]--;
+ } /* end while */
+
+ /* Check for getting out of iterator, we're done in the 1-D case */
+ if(ndims==1)
+ goto done; /* Yes, an evil goto.. :-) -QAK */
+
+ /* Work on other dimensions if necessary */
+ if(fast_dim>0 && user_ret==0) {
+ /* Reset the sequence and block counts */
+ tmp_block[fast_dim]=diminfo[fast_dim].block;
+ tmp_count[fast_dim]=diminfo[fast_dim].count;
+
+ /* Bubble up the decrement to the slower changing dimensions */
+ temp_dim=fast_dim-1;
+ while(temp_dim>=0) {
+ /* Decrement the sequence count in this dimension */
+ tmp_block[temp_dim]--;
+
+ /* Check if we are still in the sequence */
+ if(tmp_block[temp_dim]>0)
+ break;
+
+ /* Reset the sequence count in this dimension */
+ tmp_block[temp_dim]=diminfo[temp_dim].block;
+
+ /* Decrement the block count */
+ tmp_count[temp_dim]--;
+
+ /* Check if we have more blocks left */
+ if(tmp_count[temp_dim]>0)
+ break;
+
+ /* Check for getting out of iterator */
+ if(temp_dim==0)
+ goto done; /* Yes, an evil goto.. :-) -QAK */
+
+ /* 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 buffer location & offset array */
+ for(loc=buf,u=0; u<ndims; u++) {
+ temp_off=diminfo[u].start
+ +diminfo[u].stride*(diminfo[u].count-tmp_count[u])
+ +(diminfo[u].block-tmp_block[u]);
+ loc+=temp_off*slab[u];
+ offset[u]=temp_off;
+ } /* end for */
+ } /* end while */
+
+done:
+ FUNC_LEAVE (user_ret);
+} /* end H5S_hyper_select_iterate_mem_opt() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_select_iterate
+ PURPOSE
+ Iterate over a hyperslab selection, calling a user's function for each
+ element.
+ USAGE
+ herr_t H5S_hyper_select_iterate(buf, type_id, space, op, operator_data)
+ void *buf; IN/OUT: Buffer containing elements to iterate over
+ hid_t type_id; IN: Datatype ID of BUF array.
+ H5S_t *space; IN: Dataspace object containing selection to iterate over
+ H5D_operator_t op; IN: Function pointer to the routine to be
+ called for each element in BUF iterated over.
+ void *operator_data; IN/OUT: Pointer to any user-defined data
+ associated with the operation.
+ RETURNS
+ Returns the return value of the last operator if it was non-zero, or zero
+ if all elements were processed. Otherwise returns a negative value.
+ DESCRIPTION
+ Iterates over the selected elements in a memory buffer, calling the user's
+ callback function for each element. The selection in the dataspace is
+ modified so that any elements already iterated over are removed from the
+ selection if the iteration is interrupted (by the H5D_operator_t function
+ returning non-zero) in the "middle" of the iteration and may be re-started
+ by the user where it left off.
+
+ NOTE: Until "subtracting" elements from a selection is implemented,
+ the selection is not modified.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+herr_t
+H5S_hyper_select_iterate(void *buf, hid_t type_id, H5S_t *space, H5D_operator_t op,
+ void *operator_data)
+{
+ H5S_hyper_iter_info_t iter_info; /* Block of parameters to pass into recursive calls */
+ H5S_sel_iter_t iter; /* selection iteration info*/
+ size_t elmt_size; /* Datatype size */
+ herr_t ret_value=FAIL; /* return value */
+
+ FUNC_ENTER (H5S_hyper_select_iterate, FAIL);
+
+ assert(buf);
+ assert(space);
+ assert(op);
+ assert(H5I_DATATYPE == H5I_get_type(type_id));
+
+ /* Initialize iterator */
+ HDmemset(&iter,0,sizeof(H5S_sel_iter_t));
+
+ /* Get the datatype size */
+ elmt_size=H5Tget_size(type_id);
+
+ /* Construct iterator for hyperslab selection */
+ if (H5S_hyper_init(space, elmt_size, &iter)<0)
+ HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to initialize selection information");
+
+ /* Check for the special case of just one H5Sselect_hyperslab call made */
+ if(space->select.sel_info.hslab.diminfo!=NULL) {
+ /* Use optimized call to iterate over regular hyperslab */
+ ret_value=H5S_hyper_select_iterate_mem_opt(&iter,buf,type_id,space,op,operator_data);
+ }
+ else {
+ /* Initialize parameter block for recursive calls */
+ iter_info.dt=type_id;
+ iter_info.elem_size=elmt_size;
+ iter_info.space=space;
+ iter_info.iter=&iter;
+ iter_info.src=buf;
+
+ /* Copy the location of the region in the file */
+ iter_info.op=op;
+ iter_info.op_data=operator_data;
+
+ /* Call the recursive iterator routine */
+ ret_value=H5S_hyper_select_iterate_helper(&iter_info);
} /* end else */
+
+ /* Release selection iterator */
+ H5S_sel_iter_release(space,&iter);
+
+done:
FUNC_LEAVE (ret_value);
-} /* H5S_hyper_select_contiguous() */
+} /* H5S_hyper_select_iterate() */
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_release
+ PURPOSE
+ Release hyperslab selection information for a dataspace
+ USAGE
+ herr_t H5S_hyper_release(space)
+ H5S_t *space; IN: Pointer to dataspace
+ RETURNS
+ Non-negative on success/Negative on failure
+ DESCRIPTION
+ Releases all hyperslab selection information for a dataspace
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+ * Robb Matzke, 1998-08-25
+ * The fields which are freed are set to NULL to prevent them from being
+ * freed again later. This fixes some allocation problems where
+ * changing the hyperslab selection of one data space causes a core dump
+ * when closing some other data space.
+--------------------------------------------------------------------------*/
+herr_t
+H5S_hyper_release (H5S_t *space)
+{
+ herr_t ret_value=FAIL;
+
+ FUNC_ENTER (H5S_hyper_release, FAIL);
+
+ /* Check args */
+ assert (space && H5S_SEL_HYPERSLABS==space->select.type);
+
+ /* Reset the number of points selected */
+ space->select.num_elem=0;
+
+ /* Release the regular selection info */
+ if(space->select.sel_info.hslab.diminfo!=NULL) {
+ H5FL_ARR_FREE(H5S_hyper_dim_t,space->select.sel_info.hslab.diminfo);
+ space->select.sel_info.hslab.diminfo = NULL;
+ H5FL_ARR_FREE(H5S_hyper_dim_t,space->select.sel_info.hslab.app_diminfo);
+ space->select.sel_info.hslab.app_diminfo = NULL;
+ } /* end if */
+
+ /* Release irregular hyperslab information */
+ 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");
+ space->select.sel_info.hslab.span_lst=NULL;
+ } /* end if */
+
+ /* Success! */
+ ret_value=SUCCEED;
+
+done:
+ FUNC_LEAVE (SUCCEED);
+} /* H5S_hyper_release() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_recover_span
+ PURPOSE
+ Recover a generated span, if appropriate
+ USAGE
+ herr_t H5S_hyper_recover_span(recover, curr_span, next_span)
+ unsigned *recover; IN/OUT: Pointer recover flag
+ H5S_hyper_span_t **curr_span; IN/OUT: Pointer to current span in list
+ H5S_hyper_span_t *next_span; IN: Pointer to next span
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Check if the current span needs to be recovered and free it if so.
+ Set the current span to the next span in any case.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_recover_span (unsigned *recover, H5S_hyper_span_t **curr_span, H5S_hyper_span_t *next_span)
+{
+ herr_t ret_value=FAIL;
+
+ FUNC_ENTER (H5S_hyper_recover_span, FAIL);
+
+ assert(recover);
+ assert(curr_span);
+
+ /* Check if the span should be recovered */
+ if(*recover) {
+ H5S_hyper_free_span(*curr_span);
+ *recover=0;
+ } /* end if */
+
+ /* Set the current span to next span */
+ *curr_span=next_span;
+
+ /* Success! */
+ ret_value=SUCCEED;
+
+#ifdef LATER
+done:
+#endif /* LATER */
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_recover_span() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_append_span
+ PURPOSE
+ Create a new span and append to span list
+ USAGE
+ herr_t H5S_hyper_append_span(prev_span, span_tree, low, high, down, next)
+ H5S_hyper_span_t **prev_span; IN/OUT: Pointer to previous span in list
+ H5S_hyper_span_info_t **span_tree; IN/OUT: Pointer to span tree to append to
+ hssize_t low, high; IN: Low and high bounds for new span node
+ H5S_hyper_span_info_t *down; IN: Down span tree for new node
+ H5S_hyper_span_t *next; IN: Next span for new node
+ RETURNS
+ Non-negative on success, negative on failure
+ DESCRIPTION
+ Create a new span node and append to a span list. Update the previous
+ span in the list also.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_append_span (H5S_hyper_span_t **prev_span, H5S_hyper_span_info_t ** span_tree, hssize_t low, hssize_t high, H5S_hyper_span_info_t *down, H5S_hyper_span_t *next)
+{
+ H5S_hyper_span_t *new_span;
+ herr_t ret_value=FAIL;
+
+ FUNC_ENTER (H5S_hyper_append_span, FAIL);
+
+ assert(prev_span);
+ assert(span_tree);
+
+ /* Check for adding first node to merged spans */
+ if(*prev_span==NULL) {
+ /* Allocate new span node to append to list */
+ if((new_span = H5S_hyper_new_span(low,high,down,next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span");
+
+ /* Make first node in span list */
+
+ /* Check that we haven't already allocated a span tree */
+ assert(*span_tree==NULL);
+
+ /* Allocate a new span_info node */
+ if((*span_tree = H5FL_ALLOC(H5S_hyper_span_info_t,0))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span");
+
+ /* Set the span tree's basic information */
+ (*span_tree)->count=1;
+ (*span_tree)->scratch=NULL;
+ (*span_tree)->head=new_span;
+
+ /* Update previous merged span */
+ *prev_span=new_span;
+ } /* end if */
+ /* Merge or append to existing merged spans list */
+ else {
+ /* Check if span can just extend the previous merged span */
+ if((((*prev_span)->high+1)==low) &&
+ H5S_hyper_cmp_spans(down,(*prev_span)->down)==TRUE) {
+ /* Extend previous merged span to include new high bound */
+ (*prev_span)->high=high;
+ (*prev_span)->nelem+=(high-low)+1;
+ } /* end if */
+ else {
+ /* Allocate new span node to append to list */
+ if((new_span = H5S_hyper_new_span(low,high,down,next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span");
+
+ /* Check if there is actually a down span */
+ if(new_span->down) {
+ /* Check if the down spans for the new span node are the same as the previous span node */
+ if(H5S_hyper_cmp_spans(new_span->down,(*prev_span)->down)==TRUE) {
+ /* Release the down span for the new node */
+ H5S_hyper_free_span_info(new_span->down);
+
+ /* Point the new node's down span at the previous node's down span */
+ new_span->down=(*prev_span)->down;
+
+ /* Increment the reference count to the shared down span */
+ new_span->down->count++;
+ } /* end if */
+ } /* end if */
+
+ /* Indicate elements to previous span */
+ new_span->pstride=low-(*prev_span)->low;
+
+ /* Append to end of merged spans list */
+ (*prev_span)->next=new_span;
+ *prev_span=new_span;
+ } /* end else */
+ } /* end else */
+
+done:
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_append_span() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_clip_spans
+ PURPOSE
+ Clip a new span tree against the current spans in the hyperslab selection
+ USAGE
+ herr_t H5S_hyper_clip_spans(span_a, span_b, a_not_b, a_and_b, b_not_a)
+ H5S_hyper_span_t *a_spans; IN: Span tree 'a' to clip with.
+ H5S_hyper_span_t *b_spans; IN: Span tree 'b' to clip with.
+ H5S_hyper_span_t **a_not_b; OUT: Span tree of 'a' hyperslab spans which
+ doesn't overlap with 'b' hyperslab
+ spans.
+ H5S_hyper_span_t **a_and_b; OUT: Span tree of 'a' hyperslab spans which
+ overlaps with 'b' hyperslab spans.
+ H5S_hyper_span_t **b_not_a; OUT: Span tree of 'b' hyperslab spans which
+ doesn't overlap with 'a' hyperslab
+ spans.
+ RETURNS
+ non-negative on success, negative on failure
+ DESCRIPTION
+ Clip one span tree ('a') against another span tree ('b'). Creates span
+ trees for the area defined by the 'a' span tree which does not overlap the
+ 'b' span tree, the area defined by the overlap of the 'a' hyperslab span
+ tree and the 'b' span tree, and the area defined by the 'b' hyperslab span
+ tree which does not overlap the 'a' span tree.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_clip_spans (H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans,
+ H5S_hyper_span_info_t **a_not_b, H5S_hyper_span_info_t **a_and_b,
+ H5S_hyper_span_info_t **b_not_a)
+{
+ H5S_hyper_span_t *span_a; /* Pointer to a node in span tree 'a' */
+ H5S_hyper_span_t *span_b; /* Pointer to a node in span tree 'b' */
+ H5S_hyper_span_t *tmp_span; /* Temporary pointer to new span */
+ H5S_hyper_span_t *last_a_not_b; /* Pointer to previous node in span tree 'a_not_b' */
+ H5S_hyper_span_t *last_a_and_b; /* Pointer to previous node in span tree 'a_and_b' */
+ H5S_hyper_span_t *last_b_not_a; /* Pointer to previous node in span tree 'b_not_a' */
+ H5S_hyper_span_info_t *down_a_not_b; /* Temporary pointer to a_not_b span tree of down spans for overlapping nodes */
+ H5S_hyper_span_info_t *down_a_and_b; /* Temporary pointer to a_and_b span tree of down spans for overlapping nodes */
+ H5S_hyper_span_info_t *down_b_not_a; /* Temporary pointer to b_and_a span tree of down spans for overlapping nodes */
+ unsigned recover_a, recover_b; /* Flags to indicate when to recover temporary spans */
+ herr_t ret_value=FAIL;
+
+ FUNC_ENTER (H5S_hyper_clip_spans, FAIL);
+
+ /* Check args */
+ assert (a_spans);
+ assert (b_spans);
+ assert (a_not_b);
+ assert (a_and_b);
+ assert (b_not_a);
+
+#ifdef QAK
+printf("%s: a_spans=%p, b_spans=%p\n",FUNC,a_spans,b_spans);
+#endif /* QAK */
+ /* Check if both span trees are not defined */
+ if(a_spans==NULL && b_spans==NULL) {
+#ifdef QAK
+printf("%s: check 1.0\n",FUNC);
+#endif /* QAK */
+ *a_not_b=NULL;
+ *a_and_b=NULL;
+ *b_not_a=NULL;
+ } /* end if */
+ /* If span 'a' is not defined, but 'b' is, copy 'b' and set the other return span trees to empty */
+ else if(a_spans==NULL) {
+#ifdef QAK
+printf("%s: check 2.0\n",FUNC);
+#endif /* QAK */
+ *a_not_b=NULL;
+ *a_and_b=NULL;
+ if((*b_not_a=H5S_hyper_copy_span(b_spans))==NULL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree");
+ } /* end if */
+ /* If span 'b' is not defined, but 'a' is, copy 'a' and set the other return span trees to empty */
+ else if(b_spans==NULL) {
+#ifdef QAK
+printf("%s: check 3.0\n",FUNC);
+#endif /* QAK */
+ if((*a_not_b=H5S_hyper_copy_span(a_spans))==NULL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree");
+ *a_and_b=NULL;
+ *b_not_a=NULL;
+ } /* end if */
+ /* If span 'a' and 'b' are both defined, calculate the proper span trees */
+ else {
+#ifdef QAK
+printf("%s: check 4.0\n",FUNC);
+#endif /* QAK */
+ /* Check if both span trees completely overlap */
+ if(H5S_hyper_cmp_spans(a_spans,b_spans)==TRUE) {
+#ifdef QAK
+printf("%s: check 4.1\n",FUNC);
+#endif /* QAK */
+ *a_not_b=NULL;
+ if((*a_and_b=H5S_hyper_copy_span(a_spans))==NULL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, FAIL, "can't copy hyperslab span tree");
+ *b_not_a=NULL;
+ } /* end if */
+ else {
+#ifdef QAK
+printf("%s: check 4.2\n",FUNC);
+#endif /* QAK */
+ /* Get the pointers to the new and old span lists */
+ span_a=a_spans->head;
+ span_b=b_spans->head;
+
+ /* Set the pointer to the previous spans */
+ last_a_not_b=NULL;
+ last_a_and_b=NULL;
+ last_b_not_a=NULL;
+
+ /* No spans to recover yet */
+ recover_a=recover_b=0;
+
+ /* Work through the list of spans in the new list */
+ while(span_a!=NULL && span_b!=NULL) {
+#ifdef QAK
+printf("%s: check 4.3, span_a=%p, span_b=%p\n",FUNC,span_a,span_b);
+#endif /* QAK */
+ /* Check if span 'a' is completely before span 'b' */
+ /* AAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ if(span_a->high<span_b->low) {
+#ifdef QAK
+printf("%s: check 4.3.1, span_a->(low, high)=(%ld, %ld), span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Advance span 'a', leave span 'b' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ } /* end if */
+ /* Check if span 'a' overlaps only the lower bound */
+ /* of span 'b' , up to the upper bound of span 'b' */
+ /* AAAAAAAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if(span_a->low<span_b->low && (span_a->high>=span_b->low && span_a->high<=span_b->high)) {
+#ifdef QAK
+printf("%s: check 4.3.2, span_a->(low, high)=(%ld, %ld), span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Check for overlaps between upper part of span 'a' and lower part of span 'b' */
+
+ /* Make certain both spans either have a down span or both don't have one */
+ assert((span_a->down!=NULL && span_b->down!=NULL) || (span_a->down==NULL && span_b->down==NULL));
+
+ /* If there are no down spans, just add the overlapping area to the a_and_b list */
+ if(span_a->down==NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_b->low,span_a->high,NULL,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+ } /* end if */
+ /* If there are down spans, check for the overlap in them and add to each appropriate list */
+ else {
+ /* NULL out the temporary pointers to clipped areas in down spans */
+ down_a_not_b=NULL;
+ down_a_and_b=NULL;
+ down_b_not_a=NULL;
+
+ /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
+ if(H5S_hyper_clip_spans(span_a->down,span_b->down,&down_a_not_b,&down_a_and_b,&down_b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information");
+
+ /* Check for additions to the a_not_b list */
+ if(down_a_not_b!=NULL) {
+ /* Merge/add overlapped part with/to a_not_b list */
+ if(H5S_hyper_append_span(&last_a_not_b,a_not_b,span_b->low,span_a->high,down_a_not_b,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_not_b);
+ } /* end if */
+
+ /* Check for additions to the a_and_b list */
+ if(down_a_and_b!=NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_b->low,span_a->high,down_a_and_b,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_and_b);
+ } /* end if */
+
+ /* Check for additions to the b_not_a list */
+ if(down_b_not_a!=NULL) {
+ /* Merge/add overlapped part with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_a->high,down_b_not_a,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_b_not_a);
+ } /* end if */
+ } /* end else */
+
+ /* Split off upper part of span 'b' at upper span of span 'a' */
+
+ /* Check if there is actually an upper part of span 'b' to split off */
+ if(span_a->high<span_b->high) {
+ /* Allocate new span node for upper part of span 'b' */
+ if((tmp_span = H5S_hyper_new_span(span_a->high+1,span_b->high,span_b->down,span_b->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span");
+
+ /* Advance span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+
+ /* Make upper part of span 'b' into new span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,tmp_span);
+ recover_b=1;
+ } /* end if */
+ /* No upper part of span 'b' to split */
+ else {
+ /* Advance both 'a' and 'b' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end else */
+ } /* end if */
+ /* Check if span 'a' overlaps the lower & upper bound */
+ /* of span 'b' */
+ /* AAAAAAAAAAAAAAAAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if(span_a->low<span_b->low && span_a->high>span_b->high) {
+#ifdef QAK
+printf("%s: check 4.3.3, span_a->(low, high)=(%ld, %ld), span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Check for overlaps between middle part of span 'a' and span 'b' */
+
+ /* Make certain both spans either have a down span or both don't have one */
+ assert((span_a->down!=NULL && span_b->down!=NULL) || (span_a->down==NULL && span_b->down==NULL));
+
+ /* If there are no down spans, just add the overlapping area to the a_and_b list */
+ if(span_a->down==NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_b->low,span_b->high,NULL,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+ } /* end if */
+ /* If there are down spans, check for the overlap in them and add to each appropriate list */
+ else {
+ /* NULL out the temporary pointers to clipped areas in down spans */
+ down_a_not_b=NULL;
+ down_a_and_b=NULL;
+ down_b_not_a=NULL;
+
+ /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
+ if(H5S_hyper_clip_spans(span_a->down,span_b->down,&down_a_not_b,&down_a_and_b,&down_b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information");
+
+ /* Check for additions to the a_not_b list */
+ if(down_a_not_b!=NULL) {
+ /* Merge/add overlapped part with/to a_not_b list */
+ if(H5S_hyper_append_span(&last_a_not_b,a_not_b,span_b->low,span_b->high,down_a_not_b,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_not_b);
+ } /* end if */
+
+ /* Check for additions to the a_and_b list */
+ if(down_a_and_b!=NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_b->low,span_b->high,down_a_and_b,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_and_b);
+ } /* end if */
+
+ /* Check for additions to the b_not_a list */
+ if(down_b_not_a!=NULL) {
+ /* Merge/add overlapped part with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_b->high,down_b_not_a,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_b_not_a);
+ } /* end if */
+ } /* end else */
+
+ /* Split off upper part of span 'a' at upper span of span 'b' */
+
+ /* Allocate new span node for upper part of span 'a' */
+ if((tmp_span = H5S_hyper_new_span(span_b->high+1,span_a->high,span_a->down,span_a->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span");
+
+ /* Make upper part of span 'a' the new span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,tmp_span);
+ recover_a=1;
+
+ /* Advance span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end if */
+ /* Check if span 'a' is entirely within span 'b' */
+ /* AAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if(span_a->low>=span_b->low && span_a->high<=span_b->high) {
+#ifdef QAK
+printf("%s: check 4.3.4, span_a->(low, high)=(%ld, %ld), span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* Split off lower part of span 'b' at lower span of span 'a' */
+
+ /* Check if there is actually a lower part of span 'b' to split off */
+ if(span_a->low>span_b->low) {
+ /* Merge/add lower part of span 'b' with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_a->low-1,span_b->down,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+ } /* end if */
+ else {
+ /* Keep going, nothing to split off */
+ } /* end else */
+
+ /* Check for overlaps between span 'a' and midle of span 'b' */
+
+ /* Make certain both spans either have a down span or both don't have one */
+ assert((span_a->down!=NULL && span_b->down!=NULL) || (span_a->down==NULL && span_b->down==NULL));
+
+ /* If there are no down spans, just add the overlapping area to the a_and_b list */
+ if(span_a->down==NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_a->low,span_a->high,NULL,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+ } /* end if */
+ /* If there are down spans, check for the overlap in them and add to each appropriate list */
+ else {
+ /* NULL out the temporary pointers to clipped areas in down spans */
+ down_a_not_b=NULL;
+ down_a_and_b=NULL;
+ down_b_not_a=NULL;
+
+ /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
+ if(H5S_hyper_clip_spans(span_a->down,span_b->down,&down_a_not_b,&down_a_and_b,&down_b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information");
+
+ /* Check for additions to the a_not_b list */
+ if(down_a_not_b!=NULL) {
+ /* Merge/add overlapped part with/to a_not_b list */
+ if(H5S_hyper_append_span(&last_a_not_b,a_not_b,span_a->low,span_a->high,down_a_not_b,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_not_b);
+ } /* end if */
+
+ /* Check for additions to the a_and_b list */
+ if(down_a_and_b!=NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_a->low,span_a->high,down_a_and_b,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_and_b);
+ } /* end if */
+
+ /* Check for additions to the b_not_a list */
+ if(down_b_not_a!=NULL) {
+ /* Merge/add overlapped part with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_a->low,span_a->high,down_b_not_a,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_b_not_a);
+ } /* end if */
+ } /* end else */
+
+ /* Check if there is actually an upper part of span 'b' to split off */
+ if(span_a->high<span_b->high) {
+ /* Split off upper part of span 'b' at upper span of span 'a' */
+
+ /* Allocate new span node for upper part of spans 'a' */
+ if((tmp_span = H5S_hyper_new_span(span_a->high+1,span_b->high,span_b->down,span_b->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span");
+
+ /* And advance span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+
+ /* Make upper part of span 'b' the new span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,tmp_span);
+ recover_b=1;
+ } /* end if */
+ else {
+ /* Advance both span 'a' & span 'b' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end else */
+ } /* end if */
+ /* Check if span 'a' overlaps only the upper bound */
+ /* of span 'b' */
+ /* AAAAAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if((span_a->low>=span_b->low && span_a->low<=span_b->high) && span_a->high>span_b->high) {
+#ifdef QAK
+printf("%s: check 4.3.5, span_a->(low, high)=(%ld, %ld), span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* Check if there is actually a lower part of span 'b' to split off */
+ if(span_a->low>span_b->low) {
+ /* Split off lower part of span 'b' at lower span of span 'a' */
+
+ /* Merge/add lower part of span 'b' with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_b->low,span_a->low-1,span_b->down,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+ } /* end if */
+ else {
+ /* Keep going, nothing to split off */
+ } /* end else */
+
+ /* Check for overlaps between lower part of span 'a' and upper part of span 'b' */
+
+ /* Make certain both spans either have a down span or both don't have one */
+ assert((span_a->down!=NULL && span_b->down!=NULL) || (span_a->down==NULL && span_b->down==NULL));
+
+ /* If there are no down spans, just add the overlapping area to the a_and_b list */
+ if(span_a->down==NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_a->low,span_b->high,NULL,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+ } /* end if */
+ /* If there are down spans, check for the overlap in them and add to each appropriate list */
+ else {
+ /* NULL out the temporary pointers to clipped areas in down spans */
+ down_a_not_b=NULL;
+ down_a_and_b=NULL;
+ down_b_not_a=NULL;
+
+ /* Check for overlaps in the 'down spans' of span 'a' & 'b' */
+ if(H5S_hyper_clip_spans(span_a->down,span_b->down,&down_a_not_b,&down_a_and_b,&down_b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information");
+
+ /* Check for additions to the a_not_b list */
+ if(down_a_not_b!=NULL) {
+ /* Merge/add overlapped part with/to a_not_b list */
+ if(H5S_hyper_append_span(&last_a_not_b,a_not_b,span_a->low,span_b->high,down_a_not_b,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_not_b);
+ } /* end if */
+
+ /* Check for additions to the a_and_b list */
+ if(down_a_and_b!=NULL) {
+ /* Merge/add overlapped part with/to a_and_b list */
+ if(H5S_hyper_append_span(&last_a_and_b,a_and_b,span_a->low,span_b->high,down_a_and_b,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_a_and_b);
+ } /* end if */
+
+ /* Check for additions to the b_not_a list */
+ if(down_b_not_a!=NULL) {
+ /* Merge/add overlapped part with/to b_not_a list */
+ if(H5S_hyper_append_span(&last_b_not_a,b_not_a,span_a->low,span_b->high,down_b_not_a,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release the down span tree generated */
+ H5S_hyper_free_span_info(down_b_not_a);
+ } /* end if */
+ } /* end else */
+
+ /* Split off upper part of span 'a' at upper span of span 'b' */
+
+ /* Allocate new span node for upper part of span 'a' */
+ if((tmp_span = H5S_hyper_new_span(span_b->high+1,span_a->high,span_a->down,span_a->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab span");
+
+ /* Make upper part of span 'a' into new span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,tmp_span);
+ recover_a=1;
+
+ /* Advance span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end if */
+ /* span 'a' must be entirely above span 'b' */
+ /* AAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else {
+#ifdef QAK
+printf("%s: check 4.3.6, span_a->(low, high)=(%ld, %ld), span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Advance span 'b', leave span 'a' */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end else */
+ } /* end while */
+#ifdef QAK
+printf("%s: check 5.0, span_a=%p, span_b=%p\n",FUNC,span_a,span_b);
+#endif /* QAK */
+
+ /* Clean up 'a' spans which haven't been covered yet */
+ if(span_a!=NULL && span_b==NULL) {
+#ifdef QAK
+printf("%s: check 6.0, span_a=%p, span_b=%p\n",FUNC,span_a,span_b);
+#endif /* QAK */
+ 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Advance to the next 'a' span */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ } /* end while */
+ } /* end if */
+ /* Clean up 'b' spans which haven't been covered yet */
+ else if(span_a==NULL && span_b!=NULL) {
+#ifdef QAK
+printf("%s: check 7.0, span_a=%p, span_b=%p\n",FUNC,span_a,span_b);
+#endif /* QAK */
+ 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Advance to the next 'b' span */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end while */
+ } /* end if */
+ } /* end else */
+ } /* end else */
+
+ /* Success! */
+ ret_value=SUCCEED;
+
+done:
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_clip_spans() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_merge_spans_helper
+ PURPOSE
+ Merge two hyperslab span tree together
+ USAGE
+ H5S_hyper_span_info_t *H5S_hyper_merge_spans_helper(a_spans, b_spans)
+ H5S_hyper_span_info_t *a_spans; IN: First hyperslab spans to merge
+ together
+ H5S_hyper_span_info_t *b_spans; IN: Second hyperslab spans to merge
+ together
+ RETURNS
+ Pointer to span tree containing the merged spans on success, NULL on failure
+ DESCRIPTION
+ Merge two sets of hyperslab spans together and return the span tree from
+ the merged set.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5S_hyper_span_info_t *
+H5S_hyper_merge_spans_helper (H5S_hyper_span_info_t *a_spans, H5S_hyper_span_info_t *b_spans)
+{
+ H5S_hyper_span_info_t *merged_spans=NULL; /* Pointer to the merged span tree */
+ H5S_hyper_span_info_t *tmp_spans; /* Pointer to temporary new span tree */
+ H5S_hyper_span_t *tmp_span; /* Pointer to temporary new span */
+ H5S_hyper_span_t *span_a; /* Pointer to current span 'a' working on */
+ H5S_hyper_span_t *span_b; /* Pointer to current span 'b' working on */
+ H5S_hyper_span_t *prev_span_merge; /* Pointer to previous merged span */
+ unsigned recover_a, recover_b; /* Flags to indicate when to recover temporary spans */
+ H5S_hyper_span_info_t *ret_value=NULL;
+
+ FUNC_ENTER (H5S_hyper_merge_spans_helper, NULL);
+
+#ifdef QAK
+printf("%s: a_spans=%p, b_spans=%p\n",FUNC,a_spans,b_spans);
+#endif /* QAK */
+
+ /* Make certain both 'a' & 'b' spans have down span trees or neither does */
+ assert((a_spans!=NULL && b_spans!=NULL) || (a_spans==NULL && b_spans==NULL));
+
+ /* Check if the span trees for the 'a' span and the 'b' span are the same */
+ if(H5S_hyper_cmp_spans(a_spans,b_spans)==TRUE) {
+#ifdef QAK
+printf("%s: check 0.5\n",FUNC);
+#endif /* QAK */
+ if(a_spans==NULL)
+ merged_spans=NULL;
+ else {
+ /* Copy one of the span trees to return */
+ if((merged_spans=H5S_hyper_copy_span(a_spans))==NULL)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTCOPY, NULL, "can't copy hyperslab span tree");
+ } /* end else */
+ } /* end if */
+ else {
+#ifdef QAK
+printf("%s: check 1.0\n",FUNC);
+#endif /* QAK */
+ /* Get the pointers to the 'a' and 'b' span lists */
+ span_a=a_spans->head;
+ span_b=b_spans->head;
+
+ /* Set the pointer to the previous spans */
+ prev_span_merge=NULL;
+
+ /* No spans to recover yet */
+ recover_a=recover_b=0;
+
+ /* Work through the list of spans in the new list */
+ while(span_a!=NULL && span_b!=NULL) {
+#ifdef QAK
+printf("%s: check 3.0, span_a=%p, span_b=%p\n",FUNC,span_a,span_b);
+#endif /* QAK */
+ /* Check if the 'a' span is completely before 'b' span */
+ /* AAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ if(span_a->high<span_b->low) {
+#ifdef QAK
+printf("%s: check 3.1, span_a->(low, high)=(%ld, %ld), span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Advance span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ } /* end if */
+ /* Check if span 'a' overlaps only the lower bound */
+ /* of span 'b', up to the upper bound of span 'b' */
+ /* AAAAAAAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if(span_a->low<span_b->low && (span_a->high>=span_b->low && span_a->high<=span_b->high)) {
+#ifdef QAK
+printf("%s: check 3.2, span_a->(low, high)=(%ld, %ld), span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* Check if span 'a' and span 'b' down spans are equal */
+ if(H5S_hyper_cmp_spans(span_a->down,span_b->down)==TRUE) {
+ /* Merge/add copy of span 'a' with/to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,span_a->down,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Get merged span tree for overlapped section */
+ tmp_spans=H5S_hyper_merge_spans_helper(span_a->down,span_b->down);
+
+ /* Merge/add overlapped section to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->high,tmp_spans,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release merged span tree for overlapped section */
+ H5S_hyper_free_span_info(tmp_spans);
+ } /* end else */
+
+ /* Check if there is an upper part of span 'b' */
+ if(span_a->high<span_b->high) {
+ /* Copy upper part of span 'b' as new span 'b' */
+
+ /* Allocate new span node to append to list */
+ if((tmp_span = H5S_hyper_new_span(span_a->high+1,span_b->high,span_b->down,span_b->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Advance span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+
+ /* Set new span 'b' to tmp_span */
+ H5S_hyper_recover_span(&recover_b,&span_b,tmp_span);
+ recover_b=1;
+ } /* end if */
+ else {
+ /* Advance both span 'a' & 'b' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end else */
+ } /* end if */
+ /* Check if span 'a' overlaps the lower & upper bound */
+ /* of span 'b' */
+ /* AAAAAAAAAAAAAAAAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if(span_a->low<span_b->low && span_a->high>span_b->high) {
+#ifdef QAK
+printf("%s: check 3.3, span_a->(low, high)=(%ld, %ld), span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* Check if span 'a' and span 'b' down spans are equal */
+ if(H5S_hyper_cmp_spans(span_a->down,span_b->down)==TRUE) {
+ /* Merge/add copy of lower & middle parts of span 'a' to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->high,span_a->down,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Get merged span tree for overlapped section */
+ tmp_spans=H5S_hyper_merge_spans_helper(span_a->down,span_b->down);
+
+ /* Merge/add overlapped section to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,tmp_spans,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release merged span tree for overlapped section */
+ H5S_hyper_free_span_info(tmp_spans);
+ } /* end else */
+
+ /* Copy upper part of span 'a' as new span 'a' (remember to free) */
+
+ /* Allocate new span node to append to list */
+ if((tmp_span = H5S_hyper_new_span(span_b->high+1,span_a->high,span_a->down,span_a->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Set new span 'a' to tmp_span */
+ H5S_hyper_recover_span(&recover_a,&span_a,tmp_span);
+ recover_a=1;
+
+ /* Advance span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end if */
+ /* Check if span 'a' is entirely within span 'b' */
+ /* AAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if(span_a->low>=span_b->low && span_a->high<=span_b->high) {
+#ifdef QAK
+printf("%s: check 3.4, span_a->(low, high)=(%ld, %ld), span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* Check if span 'a' and span 'b' down spans are equal */
+ if(H5S_hyper_cmp_spans(span_a->down,span_b->down)==TRUE) {
+ /* Merge/add copy of lower & middle parts of span 'b' to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_a->high,span_a->down,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+ } /* end if */
+ else {
+ /* No lower part of span 'b' , keep going... */
+ } /* end else */
+
+ /* Get merged span tree for overlapped section */
+ tmp_spans=H5S_hyper_merge_spans_helper(span_a->down,span_b->down);
+
+ /* Merge/add overlapped section to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_a->high,tmp_spans,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release merged span tree for overlapped section */
+ H5S_hyper_free_span_info(tmp_spans);
+ } /* end else */
+
+ /* Check if there is an upper part of span 'b' */
+ if(span_a->high<span_b->high) {
+ /* Copy upper part of span 'b' as new span 'b' (remember to free) */
+
+ /* Allocate new span node to append to list */
+ if((tmp_span = H5S_hyper_new_span(span_a->high+1,span_b->high,span_b->down,span_b->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Advance span 'a' */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+
+ /* Set new span 'b' to tmp_span */
+ H5S_hyper_recover_span(&recover_b,&span_b,tmp_span);
+ recover_b=1;
+ } /* end if */
+ else {
+ /* Advance both spans */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end else */
+ } /* end if */
+ /* Check if span 'a' overlaps only the upper bound */
+ /* of span 'b' */
+ /* AAAAAAAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else if((span_a->low>=span_b->low && span_a->low<=span_b->high) && span_a->high>span_b->high) {
+#ifdef QAK
+printf("%s: check 3.5, span_a->(low, high)=(%ld, %ld), span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* Check if span 'a' and span 'b' down spans are equal */
+ if(H5S_hyper_cmp_spans(span_a->down,span_b->down)==TRUE) {
+ /* Merge/add copy of span 'b' to merged spans if so */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_b->low,span_b->high,span_b->down,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+ } /* end if */
+ else {
+ /* No lower part of span 'b' , keep going... */
+ } /* end else */
+
+ /* Get merged span tree for overlapped section */
+ tmp_spans=H5S_hyper_merge_spans_helper(span_a->down,span_b->down);
+
+ /* Merge/add overlapped section to merged spans */
+ if(H5S_hyper_append_span(&prev_span_merge,&merged_spans,span_a->low,span_b->high,tmp_spans,NULL)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Release merged span tree for overlapped section */
+ H5S_hyper_free_span_info(tmp_spans);
+ } /* end else */
+
+ /* Copy upper part of span 'a' as new span 'a' */
+
+ /* Allocate new span node to append to list */
+ if((tmp_span = H5S_hyper_new_span(span_b->high+1,span_a->high,span_a->down,span_a->next))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Set new span 'a' to tmp_span */
+ H5S_hyper_recover_span(&recover_a,&span_a,tmp_span);
+ recover_a=1;
+
+ /* Advance span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end if */
+ /* Span 'a' must be entirely above span 'b' */
+ /* AAAAA */
+ /* <-----------------------------------> */
+ /* BBBBBBBBBB */
+ else {
+#ifdef QAK
+printf("%s: check 3.6, span_a->(low, high)=(%ld, %ld), span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Advance span 'b' */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end else */
+ } /* end while */
+#ifdef QAK
+printf("%s: check 4.0, span_a=%p, span_b=%p\n",FUNC,span_a,span_b);
+#endif /* QAK */
+
+ /* Clean up 'a' spans which haven't been added to the list of merged spans */
+ if(span_a!=NULL && span_b==NULL) {
+ while(span_a!=NULL) {
+#ifdef QAK
+printf("%s: check 5.0, span_a->(low, high)=(%ld, %ld)\n",FUNC,(long)span_a->low,(long)span_a->high);
+#endif /* QAK */
+ /* 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Advance to next 'a' span, until all processed */
+ H5S_hyper_recover_span(&recover_a,&span_a,span_a->next);
+ } /* end while */
+ } /* end if */
+
+ /* Clean up 'b' spans which haven't been added to the list of merged spans */
+ if(span_a==NULL && span_b!=NULL) {
+ while(span_b!=NULL) {
+#ifdef QAK
+printf("%s: check 6.0, span_b->(low, high)=(%ld, %ld)\n",FUNC,(long)span_b->low,(long)span_b->high);
+#endif /* QAK */
+ /* 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)==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Advance to next 'b' span, until all processed */
+ H5S_hyper_recover_span(&recover_b,&span_b,span_b->next);
+ } /* end while */
+ } /* end if */
+#ifdef QAK
+printf("%s: check 7.0, span_a=%p, span_b=%p\n",FUNC,span_a,span_b);
+#endif /* QAK */
+ } /* end else */
+
+ /* Success! */
+ ret_value=merged_spans;
+
+done:
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_merge_spans_helper() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_merge_spans
+ PURPOSE
+ Merge new hyperslab spans to existing hyperslab selection
+ USAGE
+ herr_t H5S_hyper_merge_spans(space, new_spans)
+ 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 to be non-overlapping with the existing spans in
+ the dataspace's current hyperslab selection.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static herr_t
+H5S_hyper_merge_spans (H5S_t *space, H5S_hyper_span_info_t *new_spans)
+{
+ herr_t ret_value=FAIL;
+
+ FUNC_ENTER (H5S_hyper_merge_spans, FAIL);
+
+ /* Check args */
+ assert (space);
+ assert (new_spans);
+
+#ifdef QAK
+printf("%s: space->select.sel_info.hslab.span_lst=%p, new_spans=%p\n",FUNC,space->select.sel_info.hslab.span_lst,new_spans);
+#endif /* QAK */
+ /* If this is the first span tree in the hyperslab selection, just use it */
+ if(space->select.sel_info.hslab.span_lst==NULL) {
+ space->select.sel_info.hslab.span_lst=H5S_hyper_copy_span(new_spans);
+ } /* end if */
+ else {
+ H5S_hyper_span_info_t *merged_spans;
+
+ /* Get the merged spans */
+ merged_spans=H5S_hyper_merge_spans_helper(space->select.sel_info.hslab.span_lst, new_spans);
+
+ /* Sanity checking since we started with some spans, we should still have some after the merge */
+ assert(merged_spans);
+
+ /* Free the previous spans */
+ H5S_hyper_free_span_info(space->select.sel_info.hslab.span_lst);
+
+ /* Point to the new merged spans */
+ space->select.sel_info.hslab.span_lst=merged_spans;
+ } /* end else */
+
+ /* Success! */
+ ret_value=SUCCEED;
+
+#ifdef LATER
+done:
+#endif /* LATER */
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_merge_spans() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_spans_nelem
+ PURPOSE
+ Count the number of elements in a span tree
+ USAGE
+ hssize_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 hssize_t
+H5S_hyper_spans_nelem (H5S_hyper_span_info_t *spans)
+{
+ H5S_hyper_span_t *span; /* Hyperslab span */
+ hssize_t ret_value=FAIL;
+
+ FUNC_ENTER (H5S_hyper_spans_nelem, FAIL);
+
+ /* Count the number of elements in the span tree */
+ if(spans==NULL)
+ ret_value=0;
+ else {
+ span=spans->head;
+ ret_value=0;
+ while(span!=NULL) {
+ /* If there are down spans, multiply the size of this span by the total down span elements */
+ if(span->down!=NULL)
+ ret_value+=span->nelem*H5S_hyper_spans_nelem(span->down);
+ /* If there are no down spans, just count the elements in this span */
+ else
+ ret_value+=span->nelem;
+
+ /* Advance to next span */
+ span=span->next;
+ } /* end while */
+ } /* end else */
+
+#ifdef LATER
+done:
+#endif /* LATER */
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_spans_nelem() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5S_hyper_make_spans
+ PURPOSE
+ Create a span tree
+ USAGE
+ H5S_hyper_span_t *H5S_hyper_make_spans(rank, start, stride, count, block)
+ unsigned rank; IN: # of dimensions of the space
+ const hssize_t *start; IN: Starting location of the hyperslabs
+ const hsize_t *stride; IN: Stride from the beginning of one block to
+ the next
+ const hsize_t *count; IN: Number of blocks
+ const hsize_t *block; IN: Size of hyperslab block
+ RETURNS
+ Pointer to new span tree on success, NULL on failure
+ DESCRIPTION
+ Generates a new span tree for the hyperslab parameters specified.
+ Each span tree has a list of the elements spanned in each dimension, with
+ each span node containing a pointer to the list of spans in the next
+ dimension down.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+static H5S_hyper_span_info_t *
+H5S_hyper_make_spans (unsigned rank, const hssize_t *start, const hsize_t *stride,
+ const hsize_t *count, const hsize_t *block)
+{
+ H5S_hyper_span_info_t *down;/* Pointer to spans in next dimension down */
+ H5S_hyper_span_t *span; /* New hyperslab span */
+ H5S_hyper_span_t *last_span;/* Current position in hyperslab span list */
+ H5S_hyper_span_t *head; /* Head of new hyperslab span list */
+ int i; /* Counters */
+ unsigned u; /* Counters */
+ H5S_hyper_span_info_t *ret_value=NULL;
+
+ FUNC_ENTER (H5S_hyper_make_spans, NULL);
+
+ /* Check args */
+ assert (rank>0);
+ assert (start);
+ assert (stride);
+ assert (count);
+ assert (block);
+
+ /* Start creating spans in fastest changing dimension */
+ down=NULL;
+ for(i=(rank-1); i>=0; i--) {
+
+ /* Start a new list in this dimension */
+ head=last_span=NULL;
+
+ /* Generate all the spans segments for this dimension */
+ for(u=0; u<count[i]; u++) {
+ /* Allocate a span node */
+ if((span = H5FL_ALLOC(H5S_hyper_span_t,0))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Set the span's basic information */
+ span->low=start[i]+(stride[i]*u);
+ span->high=span->low+(block[i]-1);
+ span->nelem=block[i];
+ span->pstride=stride[i];
+ span->next=NULL;
+
+ /* Append to the list of spans in this dimension */
+ if(head==NULL)
+ head=span;
+ else
+ last_span->next=span;
+
+ /* Move current pointer */
+ last_span=span;
+
+ /* Set the information for the next dimension down's spans, if appropriate */
+ if(down!=NULL) {
+ span->down=down;
+ down->count++; /* Increment reference count for shared span */
+ } /* end if */
+ else {
+ span->down=NULL;
+ } /* end else */
+ } /* end for */
+
+ /* Allocate a span info node */
+ if((down = H5FL_ALLOC(H5S_hyper_span_info_t,0))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate hyperslab span");
+
+ /* Set the reference count */
+ down->count=0;
+
+ /* Reset the scratch pad space */
+ down->scratch=0;
+
+ /* Keep the pointer to the next dimension down's completed list */
+ down->head=head;
+ } /* end for */
+
+ /* Indicate that there is a pointer to this tree */
+ down->count=1;
+
+ /* Success! Return the head of the list in the slowest changing dimension */
+ ret_value=down;
+
+done:
+ FUNC_LEAVE (ret_value);
+} /* H5S_hyper_make_spans() */
+
+#ifndef NEW_HYPERSLAB_API
+
/*-------------------------------------------------------------------------
* Function: H5S_generate_hyperlab
*
@@ -5473,163 +7670,198 @@ H5S_hyper_select_contiguous(const H5S_t *space)
*/
static herr_t
H5S_generate_hyperslab (H5S_t *space, H5S_seloper_t op,
- const hssize_t start[/*space_id*/],
- const hsize_t stride[/*space_id*/],
- const hsize_t count[/*space_id*/],
- const hsize_t block[/*space_id*/])
+ const hssize_t start[],
+ const hsize_t _stride[],
+ const hsize_t _count[],
+ const hsize_t _block[])
{
- hssize_t slab[H5O_LAYOUT_NDIMS]; /* Location of the block to add for strided selections */
- size_t slice[H5O_LAYOUT_NDIMS]; /* Size of preceding dimension's slice */
- H5S_hyper_node_t *add=NULL, /* List of hyperslab nodes to add */
- *uniq=NULL; /* List of unique hyperslab nodes */
- unsigned acc; /* Accumulator for building slices */
- unsigned contig; /* whether selection is contiguous or not */
- int i; /* Counters */
- unsigned u,v; /* Counters */
+ hsize_t stride[H5O_LAYOUT_NDIMS]; /* Optimized stride information */
+ hsize_t count[H5O_LAYOUT_NDIMS]; /* Optimized count information */
+ hsize_t block[H5O_LAYOUT_NDIMS]; /* Optimized block information */
+ H5S_hyper_span_info_t *new_spans; /* 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 */
+ hssize_t nelem; /* Number of elements in hyperslab span tree */
+ unsigned u; /* Counters */
herr_t ret_value=FAIL; /* return value */
FUNC_ENTER (H5S_generate_hyperslab, FAIL);
/* Check args */
- assert(block);
- assert(stride);
assert(space);
- assert(start);
- assert(count);
assert(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID);
+ assert(start);
+ assert(_stride);
+ assert(_count);
+ assert(_block);
- /* Determine if selection is contiguous */
- /* assume hyperslab is contiguous, until proven otherwise */
- contig=1;
+#ifdef QAK
+printf("%s: space=%p\n",FUNC,space);
+#endif /* QAK */
+ /* Optimize hyperslab selection to merge contiguous blocks */
for(u=0; u<space->extent.u.simple.rank; u++) {
/* contiguous hyperslabs have the block size equal to the stride */
- if(stride[u]!=block[u]) {
- contig=0; /* hyperslab isn't contiguous */
- break; /* no use looking further */
+ if(_stride[u]==_block[u]) {
+ count[u]=1;
+ stride[u]=1;
+ block[u]=_block[u]*_count[u];
+ }
+ else {
+ stride[u]=_stride[u];
+ count[u]=_count[u];
+ block[u]=_block[u];
} /* end if */
} /* end for */
+ /* Generate span tree for new hyperslab information */
+ if((new_spans=H5S_hyper_make_spans(space->extent.u.simple.rank,start,stride,count,block))==NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information");
#ifdef QAK
- printf("%s: check 1.0, contig=%d, op=%s\n",FUNC,(int)contig,(op==H5S_SELECT_SET? "H5S_SELECT_SET" : (op==H5S_SELECT_OR ? "H5S_SELECT_OR" : "Unknown")));
+printf("%s: new_spans=%p\n",FUNC,new_spans);
#endif /* QAK */
-#ifdef QAK
- printf("%s: check 2.0, rank=%d\n",FUNC,(int)space->extent.u.simple.rank);
-#endif /* QAK */
- /* Allocate space for the hyperslab selection information if necessary */
- if(space->select.type!=H5S_SEL_HYPERSLABS || space->select.sel_info.hslab.hyper_lst==NULL) {
- if((space->select.sel_info.hslab.hyper_lst = H5FL_ALLOC(H5S_hyper_list_t,0))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab information");
-
- /* Set the fields for the hyperslab list */
- space->select.sel_info.hslab.hyper_lst->count=0;
- space->select.sel_info.hslab.hyper_lst->head=NULL;
- if((space->select.sel_info.hslab.hyper_lst->lo_bounds = H5FL_ARR_ALLOC(H5S_hyper_bound_ptr_t,space->extent.u.simple.rank,1))==NULL)
- HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab lo bound information");
+ /* Generate list of blocks to add/remove based on selection operation */
+ if(op==H5S_SELECT_SET) {
+ /* Add new spans to current selection */
+ if(H5S_hyper_merge_spans(space,new_spans)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+
+ /* Set the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(new_spans))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ space->select.num_elem=nelem;
} /* end if */
+ else {
+ /* Generate lists of spans which overlap and don't overlap */
+ if(H5S_hyper_clip_spans(space->select.sel_info.hslab.span_lst,new_spans,&a_not_b,&a_and_b,&b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information");
+
+ switch(op) {
+ case H5S_SELECT_OR:
+ /* Add any new spans from b_not_a to current selection */
+ if(b_not_a!=NULL) {
+ if(H5S_hyper_merge_spans(space,b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(b_not_a))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ space->select.num_elem+=nelem;
+ } /* end if */
+ break;
-#ifdef QAK
- printf("%s: check 3.0\n",FUNC);
-#endif /* QAK */
- /* Generate list of blocks to add/remove based on selection operation */
- switch(op) {
- case H5S_SELECT_SET:
- case H5S_SELECT_OR:
-#ifdef QAK
- printf("%s: check 4.0\n",FUNC);
-#endif /* QAK */
- /* Generate list of blocks to add to selection */
- if(contig) { /* Check for trivial case */
-#ifdef QAK
- printf("%s: check 4.1\n",FUNC);
-#endif /* QAK */
+ 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;
- /* Account for strides & blocks being equal, but larger than one */
- /* (Why someone would torture us this way, I don't know... -QAK :-) */
- for(u=0; u<space->extent.u.simple.rank; u++)
- slab[u]=count[u]*stride[u];
-#ifdef QAK
- printf("%s: check 4.2\n",FUNC);
- printf("%s: start = {",FUNC);
- for(u=0; u<space->extent.u.simple.rank; u++) {
- printf("%d",(int)start[u]);
- if(u<(space->extent.u.simple.rank-1))
- printf(", ");
- else
- printf("}\n");
- }
- printf("%s: slab = {",FUNC);
- for(u=0; u<space->extent.u.simple.rank; u++) {
- printf("%d",(int)slab[u]);
- if(u<(space->extent.u.simple.rank-1))
- printf(", ");
- else
- printf("}\n");
- }
-#endif /* QAK */
+ /* Reset the number of items in selection */
+ space->select.num_elem=0;
- /* Add the contiguous hyperslab to the selection */
- if(H5S_hyper_node_add(&add,0,space->extent.u.simple.rank,start,(const hsize_t *)slab)<0) {
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslab");
- }
- } else {
-#ifdef QAK
- printf("%s: check 4.3\n",FUNC);
-#endif /* QAK */
- /* Build the slice sizes for each dimension */
- for(u=0, acc=1; u<space->extent.u.simple.rank; u++) {
- slice[u]=acc;
- acc*=count[u];
- } /* end for */
-
- /* Step through all the blocks to add */
- /* (reuse the count in ACC above) */
- /* Adding the blocks in reverse order reduces the time spent moving memory around in H5S_hyper_add() */
- for(i=(int)acc-1; i>=0; i--) {
- /* Build the location of the block */
- for(v=0; v<space->extent.u.simple.rank; v++)
- slab[v]=start[v]+((i/slice[v])%count[v])*stride[v];
-
- /* Add the block to the list of hyperslab selections */
- if(H5S_hyper_node_add(&add,0,space->extent.u.simple.rank,(const hssize_t *)slab, (const hsize_t *)block)<0) {
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslab");
- } /* end if */
- } /* end for */
- } /* end else */
+ /* Check if there are any overlapped selections */
+ if(a_and_b!=NULL) {
+ if(H5S_hyper_merge_spans(space,a_and_b)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
-#ifdef QAK
- printf("%s: check 4.5\n",FUNC);
-#endif /* QAK */
- /* Clip list of new blocks to add against current selection */
- if(op==H5S_SELECT_OR) {
-#ifdef QAK
- printf("%s: check 4.5.1\n",FUNC);
-#endif /* QAK */
- H5S_hyper_clip(space,add,&uniq,NULL);
- add=uniq;
- } /* end if */
-#ifdef QAK
- printf("%s: check 4.5.5\n",FUNC);
-#endif /* QAK */
- break;
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(a_and_b))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ space->select.num_elem=nelem;
+ } /* end if */
+ break;
- default:
- HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
- } /* end switch */
+ 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;
-#ifdef QAK
- printf("%s: check 5.0\n",FUNC);
-#endif /* QAK */
- /* Add new blocks to current selection */
- if(H5S_hyper_add(space,add)<0)
- HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+ /* 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)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(a_not_b))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ space->select.num_elem=nelem;
+ } /* end if */
+ if(b_not_a!=NULL) {
+ if(H5S_hyper_merge_spans(space,b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(b_not_a))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ space->select.num_elem+=nelem;
+ } /* end if */
+ break;
+
+ case H5S_SELECT_NOTB:
+ /* Free the current selection */
+ if(H5S_hyper_free_span_info(space->select.sel_info.hslab.span_lst)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans");
+ space->select.sel_info.hslab.span_lst=NULL;
+
+ /* Reset the number of items in selection */
+ space->select.num_elem=0;
- /* Merge blocks for better I/O performance */
- /* Regenerate lo/hi bounds arrays? */
+ /* Check if there are any non-overlapped selections */
+ if(a_not_b!=NULL) {
+ if(H5S_hyper_merge_spans(space,a_not_b)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(a_not_b))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ space->select.num_elem=nelem;
+ } /* end if */
+ break;
+
+ case H5S_SELECT_NOTA:
+ /* Free the current selection */
+ if(H5S_hyper_free_span_info(space->select.sel_info.hslab.span_lst)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release hyperslab spans");
+ space->select.sel_info.hslab.span_lst=NULL;
+
+ /* Reset the number of items in selection */
+ space->select.num_elem=0;
+
+ /* Check if there are any non-overlapped selections */
+ if(b_not_a!=NULL) {
+ if(H5S_hyper_merge_spans(space,b_not_a)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(b_not_a))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ space->select.num_elem=nelem;
+ } /* end if */
+ break;
+
+ default:
+ HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
+ } /* end switch */
#ifdef QAK
- printf("%s: check 6.0\n",FUNC);
+printf("%s: a_not_b=%p, a_and_b=%p, b_not_a=%p\n",FUNC,a_not_b,a_and_b,b_not_a);
#endif /* QAK */
+ /* 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);
+ } /* end else */
+
+ /* Free the new spans */
+ if(H5S_hyper_free_span_info(new_spans)<0)
+ HGOTO_ERROR(H5E_INTERNAL, H5E_CANTFREE, FAIL, "failed to release temporary hyperslab spans");
/* Set return value */
ret_value=SUCCEED;
@@ -5646,8 +7878,8 @@ done:
*
* Return: Non-negative on success/Negative on failure
*
- * Programmer: Robb Matzke (split from HSselect_hyperslab()).
- * Tuesday, August 25, 1998
+ * Programmer: Quincey Koziol
+ * Wednesday, January 10, 2001
*
* Modifications:
*
@@ -5655,10 +7887,10 @@ done:
*/
herr_t
H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op,
- const hssize_t start[/*space_id*/],
- const hsize_t stride[/*space_id*/],
- const hsize_t count[/*space_id*/],
- const hsize_t block[/*space_id*/])
+ const hssize_t start[],
+ const hsize_t stride[],
+ const hsize_t count[],
+ const hsize_t block[])
{
hsize_t *_stride=NULL; /* Stride array */
hsize_t *_block=NULL; /* Block size array */
@@ -5680,8 +7912,7 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op,
/* Allocate temporary buffer */
if ((_stride=H5FL_ARR_ALLOC(hsize_t,space->extent.u.simple.rank,0))==NULL)
- HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL,
- "memory allocation failed for stride buffer");
+ HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for stride buffer");
H5V_array_fill(_stride,&fill,sizeof(hssize_t),space->extent.u.simple.rank);
stride = _stride;
}
@@ -5692,8 +7923,7 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op,
/* Allocate temporary buffer */
if ((_block=H5FL_ARR_ALLOC(hsize_t,space->extent.u.simple.rank,0))==NULL)
- HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL,
- "memory allocation failed for stride buffer");
+ HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for stride buffer");
H5V_array_fill(_block,&fill,sizeof(hssize_t),space->extent.u.simple.rank);
block = _block;
}
@@ -5706,35 +7936,22 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op,
if(space->select.type==H5S_SEL_NONE && op==H5S_SELECT_OR)
op=H5S_SELECT_SET;
-#ifdef QAK
- printf("%s: check 1.0, op=%s\n",FUNC,(op==H5S_SELECT_SET? "H5S_SELECT_SET" : (op==H5S_SELECT_OR ? "H5S_SELECT_OR" : "Unknown")));
-#endif /* QAK */
if(op==H5S_SELECT_SET) {
/*
- * Check for overlapping hyperslab blocks in new selection
- * (remove when real block-merging algorithm is in place? -QAK).
+ * Check for overlapping hyperslab blocks in new selection.
*/
-#ifdef QAK
-for(u=0; u<space->extent.u.simple.rank; u++)
- printf("%s: (%u) start=%d, stride=%d, count=%d, block=%d\n",FUNC,u,(int)start[u],(int)stride[u],(int)count[u],(int)block[u]);
-#endif /* QAK */
for(u=0; u<space->extent.u.simple.rank; u++) {
- if(count[u]>1 && stride[u]<block[u]) {
- HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL,
- "hyperslab blocks overlap");
- } /* end if */
+ if(count[u]>1 && stride[u]<block[u])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab blocks overlap");
} /* end for */
/* 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");
- } /* end if */
+ if(H5S_select_release(space)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release hyperslab");
/* Copy all the application per-dimension selection info into the space descriptor */
- if((diminfo = H5FL_ARR_ALLOC(H5S_hyper_dim_t,space->extent.u.simple.rank,0))==NULL) {
+ if((diminfo = H5FL_ARR_ALLOC(H5S_hyper_dim_t,space->extent.u.simple.rank,0))==NULL)
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate per-dimension vector");
- } /* end if */
for(u=0; u<space->extent.u.simple.rank; u++) {
diminfo[u].start = start[u];
diminfo[u].stride = stride[u];
@@ -5744,9 +7961,8 @@ for(u=0; u<space->extent.u.simple.rank; u++)
space->select.sel_info.hslab.app_diminfo = diminfo;
/* Allocate room for the optimized per-dimension selection info */
- if((diminfo = H5FL_ARR_ALLOC(H5S_hyper_dim_t,space->extent.u.simple.rank,0))==NULL) {
+ if((diminfo = H5FL_ARR_ALLOC(H5S_hyper_dim_t,space->extent.u.simple.rank,0))==NULL)
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate per-dimension vector");
- } /* end if */
/* Optimize the hyperslab selection to detect contiguously selected block/stride information */
/* Modify the stride, block & count for contiguous hyperslab selections */
@@ -5768,11 +7984,11 @@ for(u=0; u<space->extent.u.simple.rank; u++)
} /* end for */
space->select.sel_info.hslab.diminfo = diminfo;
- /* Set the number of elements in the hyperslab selection */
- for(space->select.num_elem=1,u=0; u<space->extent.u.simple.rank; u++)
- space->select.num_elem*=block[u]*count[u];
+ /* Build the hyperslab information also */
+ if(H5S_generate_hyperslab (space, H5S_SELECT_SET, start, stride, count, block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs");
} /* end if */
- else if(op==H5S_SELECT_OR) {
+ else if(op>=H5S_SELECT_OR && op<=H5S_SELECT_NOTA) {
switch(space->select.type) {
case H5S_SEL_ALL:
/* break out now, 'or'ing with an all selection leaves the all selection */
@@ -5781,29 +7997,6 @@ for(u=0; u<space->extent.u.simple.rank; u++)
case H5S_SEL_HYPERSLABS:
/* Is this the first 'or' operation? */
if(space->select.sel_info.hslab.diminfo != NULL) {
- /* yes, a "regular" hyperslab is selected currently */
-
- hssize_t tmp_start[H5O_LAYOUT_NDIMS];
- hsize_t tmp_stride[H5O_LAYOUT_NDIMS];
- hsize_t tmp_count[H5O_LAYOUT_NDIMS];
- hsize_t tmp_block[H5O_LAYOUT_NDIMS];
-
- /* Generate the hyperslab information for the regular hyperslab */
-
- /* Copy over the 'diminfo' information */
- for(u=0; u<space->extent.u.simple.rank; u++) {
- tmp_start[u]=space->select.sel_info.hslab.diminfo[u].start;
- tmp_stride[u]=space->select.sel_info.hslab.diminfo[u].stride;
- tmp_count[u]=space->select.sel_info.hslab.diminfo[u].count;
- tmp_block[u]=space->select.sel_info.hslab.diminfo[u].block;
- } /* end for */
-
- /* Reset the number of selection elements */
- space->select.num_elem=0;
-
- /* Build the hyperslab information */
- H5S_generate_hyperslab (space, H5S_SELECT_SET, tmp_start, tmp_stride, tmp_count, tmp_block);
-
/* Remove the 'diminfo' information, since we're adding to it */
H5FL_ARR_FREE(H5S_hyper_dim_t,space->select.sel_info.hslab.diminfo);
space->select.sel_info.hslab.diminfo = NULL;
@@ -5811,24 +8004,19 @@ for(u=0; u<space->extent.u.simple.rank; u++)
/* Remove the 'app_diminfo' information also, since we're adding to it */
H5FL_ARR_FREE(H5S_hyper_dim_t,space->select.sel_info.hslab.app_diminfo);
space->select.sel_info.hslab.app_diminfo = NULL;
-
- /* Add in the new hyperslab information */
- H5S_generate_hyperslab (space, op, start, stride, count, block);
} /* end if */
- else {
- /* nope, an "irregular" hyperslab is selected currently */
- /* Add in the new hyperslab information */
- H5S_generate_hyperslab (space, op, start, stride, count, block);
- } /* end else */
+
+ /* Add in the new hyperslab information */
+ if(H5S_generate_hyperslab (space, op, start, stride, count, block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs");
break;
default:
HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
} /* end switch() */
} /* end if */
- else {
+ else
HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
- } /* end else */
/* Set selection type */
space->select.type=H5S_SEL_HYPERSLABS;
@@ -5863,417 +8051,788 @@ done:
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). Currently, only the
- H5S_SELECT_SET & H5S_SELECT_OR operations are supported. If STRIDE or
- BLOCK is NULL, they are assumed to be set to all '1'.
+ 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 hssize_t start[/*space_id*/],
- const hsize_t _stride[/*space_id*/],
- const hsize_t count[/*space_id*/],
- const hsize_t _block[/*space_id*/])
+H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, const hssize_t start[],
+ const hsize_t stride[], const hsize_t count[], const hsize_t block[])
{
H5S_t *space = NULL; /* Dataspace to modify selection of */
FUNC_ENTER (H5Sselect_hyperslab, FAIL);
- H5TRACE6("e","iSs*[a0]Hs*[a0]h*[a0]h*[a0]h",space_id,op,start,_stride,
- count,_block);
+ H5TRACE6("e","iSs*[a0]Hs*[a0]h*[a0]h*[a0]h",space_id,op,start,stride,
+ count,block);
/* Check args */
if (H5I_DATASPACE != H5I_get_type(space_id) ||
NULL == (space=H5I_object(space_id))) {
HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space");
}
- if(start==NULL || count==NULL) {
+ if(start==NULL || count==NULL)
HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified");
- } /* end if */
- if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID)) {
+ if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID))
HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
- } /* end if */
- if (H5S_select_hyperslab(space, op, start, _stride, count, _block)<0) {
- HRETURN_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL,
- "unable to set hyperslab selection");
- }
+ if (H5S_select_hyperslab(space, op, start, stride, count, block)<0)
+ HRETURN_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection");
FUNC_LEAVE (SUCCEED);
-}
+} /* end H5Sselect_hyperslab() */
+#else /* OLD_WAY */ /* 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)
+{
+ 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 */
+ hssize_t nelem; /* Number of elements in hyperslab span tree */
+ herr_t ret_value=FAIL; /* return value */
+
+ FUNC_ENTER (H5S_operate_hyperslab, NULL);
+
+ /* Check args */
+ assert(result);
+ assert(spans2);
+ assert(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID);
+
+ /* Free the current selection for the result space */
+ if(H5S_select_release(result)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTDELETE, FAIL, "can't release result selection");
+
+ /* 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)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(spans2))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ result->select.num_elem=nelem;
+ } /* end if */
+ else {
+ assert(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)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(spans1))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ result->select.num_elem=nelem;
+ } /* 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)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(b_not_a))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ result->select.num_elem+=nelem;
+ } /* 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)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(a_and_b))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ result->select.num_elem=nelem;
+ } /* 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)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(a_not_b))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ result->select.num_elem=nelem;
+ } /* end if */
+ if(b_not_a!=NULL) {
+ 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 */
+ if((nelem=H5S_hyper_spans_nelem(b_not_a))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ result->select.num_elem+=nelem;
+ } /* 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)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(a_not_b))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ result->select.num_elem=nelem;
+ } /* 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)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslabs");
+
+ /* Update the number of elements in current selection */
+ if((nelem=H5S_hyper_spans_nelem(b_not_a))<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCOUNT, FAIL, "can't count hyperslab span elements");
+ result->select.num_elem=nelem;
+ } /* end if */
+ break;
+
+ default:
+ HRETURN_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);
+ } /* end else */
+
+ /* Set selection type */
+ result->select.type=H5S_SEL_HYPERSLABS;
+
+ /* Set the return value */
+ ret_value=SUCCEED;
+
+done:
+
+ FUNC_LEAVE (ret_value);
+} /* end H5S_operate_hyperslab() */
/*-------------------------------------------------------------------------
- * Function: H5S_hyper_select_iterate_mem
+ * Function: H5S_generate_hyperlab
*
- * Purpose: Recursively iterates over data points in memory using the parameters
- * passed to H5S_hyper_select_iterate.
+ * Purpose: Generate hyperslab information from H5S_select_hyperslab()
*
- * Return: Success: Number of elements copied.
+ * Return: Non-negative on success/Negative on failure
*
- * Failure: 0
+ * 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 hssize_t start[],
+ const hsize_t _stride[],
+ const hsize_t _count[],
+ const hsize_t _block[])
+{
+ hsize_t stride[H5O_LAYOUT_NDIMS]; /* Optimized stride information */
+ hsize_t count[H5O_LAYOUT_NDIMS]; /* Optimized count information */
+ hsize_t block[H5O_LAYOUT_NDIMS]; /* Optimized block information */
+ 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 */
+ unsigned u; /* Counters */
+ herr_t ret_value=FAIL; /* return value */
+
+ FUNC_ENTER (H5S_generate_hyperslab, FAIL);
+
+ /* Check args */
+ assert(space);
+ assert(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID);
+ assert(start);
+ assert(_stride);
+ assert(_count);
+ assert(_block);
+
+ /* Optimize hyperslab selection to merge contiguous blocks */
+ for(u=0; u<space->extent.u.simple.rank; u++) {
+ /* contiguous hyperslabs have the block size equal to the stride */
+ if(_stride[u]==_block[u]) {
+ count[u]=1;
+ stride[u]=1;
+ block[u]=_block[u]*_count[u];
+ }
+ else {
+ stride[u]=_stride[u];
+ count[u]=_count[u];
+ block[u]=_block[u];
+ } /* end if */
+ } /* end for */
+
+ /* Generate span tree for new hyperslab information */
+ if((new_spans=H5S_hyper_make_spans(space->extent.u.simple.rank,start,stride,count,block))==NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't create hyperslab information");
+
+ /* Copy the original dataspace */
+ if(space->select.sel_info.hslab.span_lst!=NULL)
+ if (NULL==(tmp_spans=H5S_hyper_copy_span(space->select.sel_info.hslab.span_lst)))
+ HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy data space");
+
+ /* Combine tmp_space (really space) & new_space, with the result in space */
+ if(H5S_operate_hyperslab(space,tmp_spans,op,new_spans)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information");
+
+ /* Set return value */
+ ret_value=SUCCEED;
+
+done:
+ /* Free temporary data structures */
+ if(tmp_spans!=NULL)
+ H5S_hyper_free_span_info(tmp_spans);
+ if(new_spans!=NULL)
+ H5S_hyper_free_span_info(new_spans);
+
+ FUNC_LEAVE (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
- * Tuesday, June 22, 1999
+ * Wednesday, January 10, 2001
*
* Modifications:
*
*-------------------------------------------------------------------------
*/
-static herr_t
-H5S_hyper_select_iterate_mem (int dim, H5S_hyper_iter_info_t *iter_info)
+herr_t
+H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op,
+ const hssize_t start[],
+ const hsize_t stride[],
+ const hsize_t count[],
+ const hsize_t block[])
{
- hsize_t offset; /* offset of region in buffer */
- void *tmp_buf; /* temporary location of the element in the buffer */
- H5S_hyper_region_t *regions; /* Pointer to array of hyperslab nodes overlapped */
- size_t num_regions; /* number of regions overlapped */
- herr_t user_ret=0; /* User's return value */
- size_t i; /* Counters */
- int j;
+ hsize_t *_stride=NULL; /* Stride array */
+ hsize_t *_block=NULL; /* Block size array */
+ unsigned u; /* Counters */
+ H5S_hyper_dim_t *diminfo; /* per-dimension info for the selection */
+ herr_t ret_value=FAIL; /* return value */
- FUNC_ENTER (H5S_hyper_select_iterate_mem, 0);
+ FUNC_ENTER (H5S_select_hyperslab, FAIL);
- assert(iter_info);
+ /* Check args */
+ assert(space);
+ assert(start);
+ assert(count);
+ assert(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID);
+
+ /* Fill in the correct stride values */
+ if(stride==NULL) {
+ hssize_t fill=1;
- /* Get a sorted list (in the next dimension down) of the regions which */
- /* overlap the current index in this dim */
- if((regions=H5S_hyper_get_regions(&num_regions,iter_info->space->extent.u.simple.rank,
- (unsigned)(dim+1),
- iter_info->space->select.sel_info.hslab.hyper_lst->count,
- iter_info->space->select.sel_info.hslab.hyper_lst->lo_bounds,
- iter_info->iter->hyp.pos,iter_info->space->select.offset))!=NULL) {
-
- /* Check if this is the second to last dimension in dataset */
- /* (Which means that we've got a list of the regions in the fastest */
- /* changing dimension and should input those regions) */
- if((unsigned)(dim+2)==iter_info->space->extent.u.simple.rank) {
- HDmemcpy(iter_info->mem_offset, iter_info->iter->hyp.pos,(iter_info->space->extent.u.simple.rank*sizeof(hssize_t)));
- iter_info->mem_offset[iter_info->space->extent.u.simple.rank]=0;
-
- /* Iterate over data from regions */
- for(i=0; i<num_regions && user_ret==0; i++) {
- /* Set the location of the current hyperslab */
- iter_info->mem_offset[iter_info->space->extent.u.simple.rank-1]=regions[i].start;
-
- /* Get the offset in the memory buffer */
- offset=H5V_array_offset(iter_info->space->extent.u.simple.rank+1,
- iter_info->mem_size,iter_info->mem_offset);
- tmp_buf=((char *)iter_info->src+offset);
-
- /* Iterate over each element in the current region */
- for(j=regions[i].start; j<=regions[i].end && user_ret==0; j++) {
- /* Call the user's function */
- user_ret=(*(iter_info->op))(tmp_buf,iter_info->dt,(hsize_t)iter_info->space->extent.u.simple.rank,iter_info->mem_offset,iter_info->op_data);
-
- /* Subtract the element from the selected region (not implemented yet) */
-
- /* Increment the coordinate offset */
- iter_info->mem_offset[iter_info->space->extent.u.simple.rank-1]=j;
-
- /* Advance the pointer in the buffer */
- tmp_buf=((char *)tmp_buf+iter_info->elem_size);
- } /* end for */
-
- /* Decrement the iterator count */
- iter_info->iter->hyp.elmt_left-=((regions[i].end-regions[i].start)+1);
- } /* end for */
+ /* Allocate temporary buffer */
+ if ((_stride=H5FL_ARR_ALLOC(hsize_t,space->extent.u.simple.rank,0))==NULL)
+ HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for stride buffer");
+ H5V_array_fill(_stride,&fill,sizeof(hssize_t),space->extent.u.simple.rank);
+ stride = _stride;
+ }
- /* Set the next position to start at */
- iter_info->iter->hyp.pos[dim+1]=(-1);
- } else { /* recurse on each region to next dimension down */
+ /* Fill in the correct block values */
+ if(block==NULL) {
+ hssize_t fill=1;
- /* Increment the dimension we are working with */
- dim++;
+ /* Allocate temporary buffer */
+ if ((_block=H5FL_ARR_ALLOC(hsize_t,space->extent.u.simple.rank,0))==NULL)
+ HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed for stride buffer");
+ H5V_array_fill(_block,&fill,sizeof(hssize_t),space->extent.u.simple.rank);
+ block = _block;
+ }
- /* Step through each region in this dimension */
- for(i=0; i<num_regions && user_ret==0; i++) {
- /* Step through each location in each region */
- for(j=regions[i].start; j<=regions[i].end && user_ret==0; j++) {
+ /* Fixup operation if selection is 'none' and operation is an OR */
+ /* (Allows for 'or'ing a sequence of hyperslab into a 'none' selection to */
+ /* have same affect as setting the first hyperslab in the sequence to have */
+ /* the 'set' operation and the rest of the hyperslab sequence to be 'or'ed */
+ /* after that */
+ if(space->select.type==H5S_SEL_NONE && op==H5S_SELECT_OR)
+ op=H5S_SELECT_SET;
- /*
- * If we are moving to a new position in this dim, reset
- * the next lower dim. location.
- */
- if(iter_info->iter->hyp.pos[dim]!=j)
- iter_info->iter->hyp.pos[dim+1]=(-1);
+ if(op==H5S_SELECT_SET) {
+ /*
+ * Check for overlapping hyperslab blocks in new selection.
+ */
+ for(u=0; u<space->extent.u.simple.rank; u++) {
+ if(count[u]>1 && stride[u]<block[u])
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab blocks overlap");
+ } /* end for */
- /* Set the correct position we are working on */
- iter_info->iter->hyp.pos[dim]=j;
+ /* 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");
- /* Go get the regions in the next lower dimension */
- user_ret=H5S_hyper_select_iterate_mem(dim, iter_info);
- } /* end for */
- } /* end for */
- } /* end else */
+ /* Copy all the application per-dimension selection info into the space descriptor */
+ if((diminfo = H5FL_ARR_ALLOC(H5S_hyper_dim_t,space->extent.u.simple.rank,0))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate per-dimension vector");
+ for(u=0; u<space->extent.u.simple.rank; u++) {
+ diminfo[u].start = start[u];
+ diminfo[u].stride = stride[u];
+ diminfo[u].count = count[u];
+ diminfo[u].block = block[u];
+ } /* end for */
+ space->select.sel_info.hslab.app_diminfo = diminfo;
+
+ /* Allocate room for the optimized per-dimension selection info */
+ if((diminfo = H5FL_ARR_ALLOC(H5S_hyper_dim_t,space->extent.u.simple.rank,0))==NULL)
+ HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate per-dimension vector");
- /* Release the temporary buffer */
- H5FL_ARR_FREE(H5S_hyper_region_t,regions);
+ /* Optimize the hyperslab selection to detect contiguously selected block/stride information */
+ /* Modify the stride, block & count for contiguous hyperslab selections */
+ for(u=0; u<space->extent.u.simple.rank; u++) {
+ /* Starting location doesn't get optimized */
+ diminfo[u].start = start[u];
+
+ /* contiguous hyperslabs have the block size equal to the stride */
+ if(stride[u]==block[u]) {
+ diminfo[u].stride=1;
+ diminfo[u].count=1;
+ diminfo[u].block=count[u]*block[u];
+ } /* end if */
+ else {
+ diminfo[u].stride=stride[u];
+ diminfo[u].count=count[u];
+ diminfo[u].block=block[u];
+ } /* end else */
+ } /* end for */
+ space->select.sel_info.hslab.diminfo = diminfo;
+
+ /* Build the hyperslab information also */
+ if(H5S_generate_hyperslab (space, H5S_SELECT_SET, start, stride, count, block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs");
} /* end if */
+ else if(op>=H5S_SELECT_OR && op<=H5S_SELECT_NOTA) {
+ switch(space->select.type) {
+ case H5S_SEL_HYPERSLABS:
+ /* Is this the first 'or' operation? */
+ if(space->select.sel_info.hslab.diminfo != NULL) {
+ /* Remove the 'diminfo' information, since we're adding to it */
+ H5FL_ARR_FREE(H5S_hyper_dim_t,space->select.sel_info.hslab.diminfo);
+ space->select.sel_info.hslab.diminfo = NULL;
- FUNC_LEAVE (user_ret);
-} /* H5S_hyper_select_iterate_mem() */
+ /* Remove the 'app_diminfo' information also, since we're adding to it */
+ H5FL_ARR_FREE(H5S_hyper_dim_t,space->select.sel_info.hslab.app_diminfo);
+ space->select.sel_info.hslab.app_diminfo = NULL;
+ } /* end if */
+
+ /* Add in the new hyperslab information */
+ if(H5S_generate_hyperslab (space, op, start, stride, count, block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't generate hyperslabs");
+ break;
+
+ default:
+ HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
+ } /* end switch() */
+ } /* end if */
+ else
+ HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
+
+ ret_value=SUCCEED;
+
+done:
+ if(_stride!=NULL)
+ H5FL_ARR_FREE(hsize_t,_stride);
+ if(_block!=NULL)
+ H5FL_ARR_FREE(hsize_t,_block);
+ FUNC_LEAVE (ret_value);
+} /* end H5S_select_hyperslab() */
/*--------------------------------------------------------------------------
NAME
- H5S_hyper_select_iterate_mem_opt
+ H5Sselect_hyperslab
PURPOSE
- Iterate over the data points in a regular hyperslab selection, calling a
- user's function for each element.
+ Specify a hyperslab to combine with the current hyperslab selection
USAGE
- herr_t H5S_hyper_select_iterate_mem_opt(buf, type_id, space, op, operator_data)
- H5S_sel_iter_t *iter; IN/OUT: Selection iterator
- void *buf; IN/OUT: Buffer containing elements to iterate over
- hid_t type_id; IN: Datatype ID of BUF array.
- H5S_t *space; IN: Dataspace object containing selection to iterate over
- H5D_operator_t op; IN: Function pointer to the routine to be
- called for each element in BUF iterated over.
- void *op_data; IN/OUT: Pointer to any user-defined data associated
- with the operation.
+ 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 hssize_t *start; IN: Offset of start of hyperslab
+ const hssize_t *stride; IN: Hyperslab stride
+ const hssize_t *count; IN: Number of blocks included in hyperslab
+ const hssize_t *block; IN: Size of block in hyperslab
RETURNS
- Returns the return value of the last operator if it was non-zero, or zero
- if all elements were processed. Otherwise returns a negative value.
+ Non-negative on success/Negative on failure
DESCRIPTION
- Iterates over the selected elements in a memory buffer, calling the user's
- callback function for each element. The selection in the dataspace is
- modified so that any elements already iterated over are removed from the
- selection if the iteration is interrupted (by the H5D_operator_t function
- returning non-zero) in the "middle" of the iteration and may be re-started
- by the user where it left off.
+ 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 hssize_t start[],
+ const hsize_t stride[], const hsize_t count[], const hsize_t block[])
+{
+ H5S_t *space = NULL; /* Dataspace to modify selection of */
- NOTE: Until "subtracting" elements from a selection is implemented,
- the selection is not modified.
+ FUNC_ENTER (H5Sselect_hyperslab, FAIL);
+ H5TRACE6("e","iSs*[a0]Hs*[a0]h*[a0]h*[a0]h",space_id,op,start,stride,
+ count,block);
+
+ /* Check args */
+ if (H5I_DATASPACE != H5I_get_type(space_id) ||
+ NULL == (space=H5I_object(space_id))) {
+ HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space");
+ }
+ if(start==NULL || count==NULL)
+ HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified");
+
+ if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID))
+ HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
+
+ if (H5S_select_hyperslab(space, op, start, stride, count, block)<0)
+ HRETURN_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection");
+
+ FUNC_LEAVE (SUCCEED);
+} /* end H5Sselect_hyperslab() */
+
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Scombine_hyperslab
+ PURPOSE
+ Specify a hyperslab to combine with the current hyperslab selection and
+ return a new dataspace with the combined selection as the selection in the
+ new dataspace.
+ USAGE
+ hid_t H5Srefine_hyperslab(dsid, op, start, stride, count, block)
+ hid_t dsid; IN: Dataspace ID of selection to use
+ H5S_seloper_t op; IN: Operation to perform on current selection
+ const hssize_t *start; IN: Offset of start of hyperslab
+ const hssize_t *stride; IN: Hyperslab stride
+ const hssize_t *count; IN: Number of blocks included in hyperslab
+ const hssize_t *block; IN: Size of block in hyperslab
+ RETURNS
+ Dataspace ID on success/Negative on failure
+ DESCRIPTION
+ Combines a hyperslab selection with the current selection for a dataspace,
+ creating a new dataspace to return the generated selection.
+ If the current selection is not a hyperslab, it is freed and the hyperslab
+ parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a
+ selection composing the entire current extent). If STRIDE or BLOCK is
+ NULL, they are assumed to be set to all '1'.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
-static herr_t
-H5S_hyper_select_iterate_mem_opt(H5S_sel_iter_t * UNUSED iter, void *buf, hid_t type_id, H5S_t *space, H5D_operator_t op,
- void *op_data)
+hid_t
+H5Scombine_hyperslab(hid_t space_id, H5S_seloper_t op, const hssize_t start[],
+ const hsize_t stride[], const hsize_t count[], const hsize_t block[])
{
- H5S_hyper_dim_t *diminfo; /* Alias for dataspace's diminfo information */
- hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary hyperslab counts */
- hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary hyperslab blocks */
- hssize_t offset[H5O_LAYOUT_NDIMS]; /* Offset of element in dataspace */
- hsize_t slab[H5O_LAYOUT_NDIMS]; /* Size of objects in buffer */
- size_t elem_size; /* Size of data element in buffer */
- hssize_t temp_off; /* Offset in a given dimension */
- uint8_t *loc; /* Current element location */
- int i; /* Counter */
- unsigned u; /* Counter */
- int fast_dim; /* Rank of the fastest changing dimension for the dataspace */
- int temp_dim; /* Temporary rank holder */
- unsigned ndims; /* Rank of the dataspace */
- herr_t user_ret=0; /* User's return value */
+ H5S_t *space = NULL; /* Dataspace to modify selection of */
+ H5S_t *new_space = NULL; /* New dataspace created */
+ hid_t ret_value = FAIL;
- FUNC_ENTER (H5S_hyper_select_iterate_mem_opt, FAIL);
+ FUNC_ENTER (H5Scombine_hyperslab, FAIL);
+ H5TRACE6("e","iSs*[a0]Hs*[a0]h*[a0]h*[a0]h",space_id,op,start,stride,
+ count,block);
- /* Set some convienence values */
- ndims=space->extent.u.simple.rank;
- fast_dim=ndims-1;
- diminfo=space->select.sel_info.hslab.diminfo;
+ /* Check args */
+ if (H5I_DATASPACE != H5I_get_type(space_id) ||
+ NULL == (space=H5I_object(space_id))) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space");
+ }
+ if(start==NULL || count==NULL)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified");
- /* Get the data element size */
- elem_size=H5Tget_size(type_id);
+ if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID))
+ HGOTO_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
- /* Elements in the fastest dimension are 'elem_size' */
- slab[ndims-1]=elem_size;
+ /* Copy the first dataspace */
+ if (NULL==(new_space=H5S_copy (space)))
+ HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to copy data space");
- /* If we have two or more dimensions, build the other dimension's element sizes */
- if(ndims>=2) {
- /* Build the table of next-dimension down 'element' sizes */
- for(i=ndims-2; i>=0; i--)
- slab[i]=slab[i+1]*space->extent.u.simple.size[i+1];
- } /* end if */
+ /* Go modify the selection in the new dataspace */
+ if (H5S_select_hyperslab(new_space, op, start, stride, count, block)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection");
- /* Build the tables of count & block sizes as well as the initial offset */
- for(u=0; u<ndims; u++) {
- tmp_count[u]=diminfo[u].count;
- tmp_block[u]=diminfo[u].block;
- offset[u]=diminfo[u].start;
- } /* end for */
+ /* Atomize */
+ if ((ret_value=H5I_register (H5I_DATASPACE, new_space))<0)
+ HGOTO_ERROR (H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom");
- /* Initialize the starting location */
- for(loc=buf,u=0; u<ndims; u++)
- loc+=diminfo[u].start*slab[u];
+done:
+ if (ret_value<0 && new_space)
+ H5S_close(new_space);
- /* Go iterate over the hyperslabs */
- while(user_ret==0) {
- /* Iterate over the blocks in the fastest dimension */
- while(tmp_count[fast_dim]>0 && user_ret==0) {
+ FUNC_LEAVE (ret_value);
+} /* end H5Scombine_hyperslab() */
- /* Iterate over the elements in the fastest dimension */
- while(tmp_block[fast_dim]>0 && user_ret==0) {
- user_ret=(*op)(loc,type_id,(hsize_t)ndims,offset,op_data);
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_combine_select
+ *
+ * Purpose: Internal version of H5Scombine_select().
+ *
+ * Return: New dataspace on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, October 30, 2001
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static H5S_t *
+H5S_combine_select (H5S_t *space1, H5S_seloper_t op, H5S_t *space2)
+{
+ H5S_t *new_space=NULL; /* New dataspace generated */
+ H5S_t *ret_value=NULL; /* return value */
- /* Increment the buffer location */
- loc+=slab[fast_dim];
+ FUNC_ENTER (H5S_combine_select, NULL);
- /* Increment the offset in the dataspace */
- offset[fast_dim]++;
+ /* Check args */
+ assert(space1);
+ assert(space2);
+ assert(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID);
+
+ /* Copy the first dataspace */
+ if (NULL==(new_space=H5S_copy (space1)))
+ HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, NULL, "unable to copy data space");
- /* Decrement the sequence count */
- tmp_block[fast_dim]--;
- } /* end while */
+ /* 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)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, NULL, "can't clip hyperslab information");
- /* Reset the sequence count */
- tmp_block[fast_dim]=diminfo[fast_dim].block;
+ /* Set the return value */
+ ret_value=new_space;
- /* Move the location to the next sequence to start */
- loc+=(diminfo[fast_dim].stride-diminfo[fast_dim].block)*slab[fast_dim];
-
- /* Move the offset to the next sequence to start */
- offset[fast_dim]+=(diminfo[fast_dim].stride-diminfo[fast_dim].block);
+done:
+ if(ret_value==NULL && new_space!=NULL)
+ H5S_close(new_space);
- /* Decrement the block count */
- tmp_count[fast_dim]--;
- } /* end while */
+ FUNC_LEAVE (ret_value);
+} /* end H5S_combine_select() */
- /* Check for getting out of iterator, we're done in the 1-D case */
- if(ndims==1)
- goto done; /* Yes, an evil goto.. :-) -QAK */
+
+/*--------------------------------------------------------------------------
+ NAME
+ H5Scombine_select
+ PURPOSE
+ Combine two hyperslab selections with an operation, returning a dataspace
+ with the resulting selection.
+ USAGE
+ hid_t H5Scombine_select(space1, op, space2)
+ hid_t space1; IN: First Dataspace ID
+ H5S_seloper_t op; IN: Selection operation
+ hid_t space2; IN: Second Dataspace ID
+ RETURNS
+ Dataspace ID on success/Negative on failure
+ DESCRIPTION
+ Combine two existing hyperslab selections with an operation, returning
+ a new dataspace with the resulting selection. The dataspace extent from
+ space1 is copied for the dataspace extent of the newly created dataspace.
+ GLOBAL VARIABLES
+ COMMENTS, BUGS, ASSUMPTIONS
+ EXAMPLES
+ REVISION LOG
+--------------------------------------------------------------------------*/
+hid_t
+H5Scombine_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id)
+{
+ H5S_t *space1; /* First Dataspace */
+ H5S_t *space2; /* Second Dataspace */
+ H5S_t *new_space = NULL; /* New Dataspace */
+ hid_t ret_value = FAIL;
- /* Work on other dimensions if necessary */
- if(fast_dim>0 && user_ret==0) {
- /* Reset the sequence and block counts */
- tmp_block[fast_dim]=diminfo[fast_dim].block;
- tmp_count[fast_dim]=diminfo[fast_dim].count;
+ FUNC_ENTER (H5Scombine_select, FAIL);
+ H5TRACE3("e","iSsi",space1_id,op,space2_id);
- /* Bubble up the decrement to the slower changing dimensions */
- temp_dim=fast_dim-1;
- while(temp_dim>=0) {
- /* Decrement the sequence count in this dimension */
- tmp_block[temp_dim]--;
+ /* Check args */
+ if (H5I_DATASPACE != H5I_get_type(space1_id) ||
+ NULL == (space1=H5I_object(space1_id))) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space");
+ }
+ if (H5I_DATASPACE != H5I_get_type(space2_id) ||
+ NULL == (space2=H5I_object(space2_id))) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space");
+ }
+ if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID))
+ HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
- /* Check if we are still in the sequence */
- if(tmp_block[temp_dim]>0)
- break;
+ /* Check that both dataspaces have the same rank */
+ if(space1->extent.u.simple.rank!=space2->extent.u.simple.rank)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same rank");
- /* Reset the sequence count in this dimension */
- tmp_block[temp_dim]=diminfo[temp_dim].block;
+ /* Check that both dataspaces have hyperslab selections */
+ if(space1->select.type!=H5S_SEL_HYPERSLABS || space2->select.type!=H5S_SEL_HYPERSLABS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces don't have hyperslab selections");
- /* Decrement the block count */
- tmp_count[temp_dim]--;
+ /* Go combine the dataspaces */
+ if ((new_space=H5S_combine_select(space1, op, space2))==NULL)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to create hyperslab selection");
- /* Check if we have more blocks left */
- if(tmp_count[temp_dim]>0)
- break;
+ /* Atomize */
+ if ((ret_value=H5I_register (H5I_DATASPACE, new_space))<0)
+ HGOTO_ERROR (H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom");
- /* Check for getting out of iterator */
- if(temp_dim==0)
- goto done; /* Yes, an evil goto.. :-) -QAK */
+done:
+ if (ret_value<0 && new_space)
+ H5S_close(new_space);
- /* 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 */
+ FUNC_LEAVE (ret_value);
+} /* end H5Scombine_select() */
- /* Re-compute buffer location & offset array */
- for(loc=buf,u=0; u<ndims; u++) {
- temp_off=diminfo[u].start
- +diminfo[u].stride*(diminfo[u].count-tmp_count[u])
- +(diminfo[u].block-tmp_block[u]);
- loc+=temp_off*slab[u];
- offset[u]=temp_off;
- } /* end for */
- } /* end while */
+
+/*-------------------------------------------------------------------------
+ * Function: H5S_select_select
+ *
+ * Purpose: Internal version of H5Sselect_select().
+ *
+ * Return: New dataspace on success/NULL on failure
+ *
+ * Programmer: Quincey Koziol
+ * Tuesday, October 30, 2001
+ *
+ * Modifications:
+ *
+ *-------------------------------------------------------------------------
+ */
+static herr_t
+H5S_select_select (H5S_t *space1, H5S_seloper_t op, H5S_t *space2)
+{
+ H5S_hyper_span_info_t *tmp_spans=NULL; /* Temporary copy of selection */
+ herr_t ret_value=FAIL; /* return value */
+
+ FUNC_ENTER (H5S_select_select, FAIL);
+
+ /* Check args */
+ assert(space1);
+ assert(space2);
+ assert(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID);
+
+ /* Copy the first dataspace */
+ if (NULL==(tmp_spans=H5S_hyper_copy_span(space1->select.sel_info.hslab.span_lst)))
+ HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy data space");
+
+ /* 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)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTCLIP, FAIL, "can't clip hyperslab information");
+
+ /* Set the return value */
+ ret_value=SUCCEED;
done:
- FUNC_LEAVE (user_ret);
-} /* end H5S_hyper_select_iterate_mem_opt() */
+ if(tmp_spans!=NULL)
+ H5S_hyper_free_span_info(tmp_spans);
+
+ FUNC_LEAVE (ret_value);
+} /* end H5S_select_select() */
/*--------------------------------------------------------------------------
NAME
- H5S_hyper_select_iterate
+ H5Sselect_select
PURPOSE
- Iterate over a hyperslab selection, calling a user's function for each
- element.
+ Refine a hyperslab selection with an operation using a second hyperslab
+ to modify it.
USAGE
- herr_t H5S_hyper_select_iterate(buf, type_id, space, op, operator_data)
- void *buf; IN/OUT: Buffer containing elements to iterate over
- hid_t type_id; IN: Datatype ID of BUF array.
- H5S_t *space; IN: Dataspace object containing selection to iterate over
- H5D_operator_t op; IN: Function pointer to the routine to be
- called for each element in BUF iterated over.
- void *operator_data; IN/OUT: Pointer to any user-defined data
- associated with the operation.
+ herr_t H5Sselect_select(space1, op, space2)
+ hid_t space1; IN/OUT: First Dataspace ID
+ H5S_seloper_t op; IN: Selection operation
+ hid_t space2; IN: Second Dataspace ID
RETURNS
- Returns the return value of the last operator if it was non-zero, or zero
- if all elements were processed. Otherwise returns a negative value.
+ Non-negative on success/Negative on failure
DESCRIPTION
- Iterates over the selected elements in a memory buffer, calling the user's
- callback function for each element. The selection in the dataspace is
- modified so that any elements already iterated over are removed from the
- selection if the iteration is interrupted (by the H5D_operator_t function
- returning non-zero) in the "middle" of the iteration and may be re-started
- by the user where it left off.
-
- NOTE: Until "subtracting" elements from a selection is implemented,
- the selection is not modified.
+ Refine an existing hyperslab selection with an operation, using a second
+ hyperslab. The first selection is modified to contain the result of
+ space1 operated on by space2.
GLOBAL VARIABLES
COMMENTS, BUGS, ASSUMPTIONS
EXAMPLES
REVISION LOG
--------------------------------------------------------------------------*/
herr_t
-H5S_hyper_select_iterate(void *buf, hid_t type_id, H5S_t *space, H5D_operator_t op,
- void *operator_data)
+H5Sselect_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id)
{
- H5S_hyper_iter_info_t iter_info; /* Block of parameters to pass into recursive calls */
- H5S_sel_iter_t iter; /* selection iteration info*/
- herr_t ret_value=FAIL; /* return value */
-
- FUNC_ENTER (H5S_hyper_select_iterate, FAIL);
-
- assert(buf);
- assert(space);
- assert(op);
- assert(H5I_DATATYPE == H5I_get_type(type_id));
+ H5S_t *space1; /* First Dataspace */
+ H5S_t *space2; /* Second Dataspace */
+ hid_t ret_value = FAIL;
- /* Initialize the selection iterator */
- if (H5S_hyper_init(space, &iter)<0) {
- HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL,
- "unable to initialize selection information");
- }
+ FUNC_ENTER (H5Sselect_select, FAIL);
+ H5TRACE3("e","iSsi",space1_id,op,space2_id);
- /* Check for the special case of just one H5Sselect_hyperslab call made */
- if(space->select.sel_info.hslab.diminfo!=NULL) {
- /* Use optimized call to iterate over regular hyperslab */
- ret_value=H5S_hyper_select_iterate_mem_opt(&iter,buf,type_id,space,op,operator_data);
+ /* Check args */
+ if (H5I_DATASPACE != H5I_get_type(space1_id) ||
+ NULL == (space1=H5I_object(space1_id))) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space");
}
- else {
- /* Initialize parameter block for recursive calls */
- iter_info.dt=type_id;
- iter_info.elem_size=H5Tget_size(type_id);
- iter_info.space=space;
- iter_info.iter=&iter;
- iter_info.src=buf;
+ if (H5I_DATASPACE != H5I_get_type(space2_id) ||
+ NULL == (space2=H5I_object(space2_id))) {
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data space");
+ }
+ if(!(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID))
+ HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation");
- /* Set up the size of the memory space */
- HDmemcpy(iter_info.mem_size, space->extent.u.simple.size, space->extent.u.simple.rank*sizeof(hsize_t));
- iter_info.mem_size[space->extent.u.simple.rank]=iter_info.elem_size;
+ /* Check that both dataspaces have the same rank */
+ if(space1->extent.u.simple.rank!=space2->extent.u.simple.rank)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same rank");
- /* Copy the location of the region in the file */
- iter_info.op=op;
- iter_info.op_data=operator_data;
+ /* Check that both dataspaces have hyperslab selections */
+ if(space1->select.type!=H5S_SEL_HYPERSLABS || space2->select.type!=H5S_SEL_HYPERSLABS)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces don't have hyperslab selections");
- /* Recursively input the hyperslabs currently defined */
- /* starting with the slowest changing dimension */
- ret_value=H5S_hyper_select_iterate_mem(-1,&iter_info);
- } /* end else */
+ /* Go refine the first selection */
+ if (H5S_select_select(space1, op, space2)<0)
+ HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to modify hyperslab selection");
- /* Release selection iterator */
- H5S_sel_iter_release(space,&iter);
+ /* Set the return value */
+ ret_value=SUCCEED;
done:
FUNC_LEAVE (ret_value);
-} /* H5S_hyper_select_iterate() */
-
+} /* end H5Sselect_select() */
+#endif /* OLD_WAY */ /* Works */