diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 1998-09-23 23:29:09 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 1998-09-23 23:29:09 (GMT) |
commit | 8af76560a0a0f05840e465a5a2871fe8010733ad (patch) | |
tree | 8df3ac0e5761a176f4f6e9c67416d6867a995d5a | |
parent | 0db7facffee0e07e096ad96f323608d752d3790a (diff) | |
download | hdf5-8af76560a0a0f05840e465a5a2871fe8010733ad.zip hdf5-8af76560a0a0f05840e465a5a2871fe8010733ad.tar.gz hdf5-8af76560a0a0f05840e465a5a2871fe8010733ad.tar.bz2 |
[svn-r717] Added code to support unioning hyperslabs with the H5S_SELECT_OR operation to
H5Sselect_hyperslab.
-rw-r--r-- | src/H5.c | 5 | ||||
-rw-r--r-- | src/H5Shyper.c | 416 | ||||
-rw-r--r-- | src/H5Sprivate.h | 5 | ||||
-rw-r--r-- | src/H5Spublic.h | 6 | ||||
-rw-r--r-- | src/H5Sselect.c | 144 |
5 files changed, 493 insertions, 83 deletions
@@ -1872,12 +1872,15 @@ H5_trace (hbool_t returning, const char *func, const char *type, ...) } else { H5S_seloper_t so = va_arg(ap, H5S_seloper_t); switch (so) { - case H5S_NOOP: + case H5S_SELECT_NOOP: fprintf(out, "H5S_NOOP"); break; case H5S_SELECT_SET: fprintf(out, "H5S_SELECT_SET"); break; + case H5S_SELECT_OR: + fprintf(out, "H5S_SELECT_OR"); + break; default: fprintf(out, "%ld", (long)so); break; diff --git a/src/H5Shyper.c b/src/H5Shyper.c index 24fca4c..c67be6b 100644 --- a/src/H5Shyper.c +++ b/src/H5Shyper.c @@ -649,7 +649,6 @@ H5S_hyper_fread (intn dim, H5S_hyper_fhyper_info_t *fhyper_info) FUNC,i,(int)regions[i].start,(int)regions[i].end); #endif /* QAK */ if((dim+2)==fhyper_info->space->extent.u.simple.rank) { - /* perform I/O on data from regions */ for(i=0; i<num_regions && fhyper_info->nelmts>0; i++) { /* Compute the size of the region to read */ @@ -1705,6 +1704,102 @@ H5S_hyper_bsearch(hssize_t size, H5S_hyper_bound_t *barr, size_t count) /*-------------------------------------------------------------------------- NAME + H5S_hyper_node_add + PURPOSE + Add a new node to a list of hyperslab nodes + USAGE + herr_t H5S_hyper_node_add(head, start, size) + H5S_hyper_node_t *head; IN: Pointer to head of hyperslab list + intn endflag; IN: "size" array actually contains "end" array + intn rank; IN: # of dimensions of the node + const hssize_t *start; IN: Offset of block + const hsize_t *size; IN: Size of block + RETURNS + SUCCEED/FAIL + DESCRIPTION + Adds a new hyperslab node to a list of them. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5S_hyper_node_add (H5S_hyper_node_t **head, intn endflag, intn rank, const hssize_t *start, const hsize_t *size) +{ + H5S_hyper_node_t *slab; /* New hyperslab node to add */ + intn i; /* Counters */ + herr_t ret_value=SUCCEED; + + FUNC_ENTER (H5S_hyper_node_add, FAIL); + + /* Check args */ + assert (head); + assert (start); + assert (size); + + /* Create new hyperslab node to insert */ + if((slab = H5MM_malloc(sizeof(H5S_hyper_node_t)))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab node"); + if((slab->start = H5MM_malloc(sizeof(hsize_t)* rank))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab start boundary"); + if((slab->end = H5MM_malloc(sizeof(hsize_t)* rank))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab end boundary"); + + /* Set boundary on new node */ + for(i=0; i<rank; i++) { + slab->start[i]=start[i]; + if(endflag) + slab->end[i]=size[i]; + else + slab->end[i]=start[i]+size[i]-1; + } /* end for */ + + /* Prepend on list of hyperslabs for this selection */ + slab->next=*head; + *head=slab; + +done: + FUNC_LEAVE (ret_value); +} /* H5S_hyper_node_add() */ + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_node_prepend + PURPOSE + Prepend an existing node to an existing list of hyperslab nodes + 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 + RETURNS + SUCCEED/FAIL + DESCRIPTION + Prepends an existing hyperslab node to a list of them. + 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) +{ + herr_t ret_value=SUCCEED; + + FUNC_ENTER (H5S_hyper_node_prepend, FAIL); + + /* Check args */ + assert (head); + assert (node); + + /* Prepend on list of hyperslabs for this selection */ + node->next=*head; + *head=node; + + FUNC_LEAVE (ret_value); +} /* H5S_hyper_node_prepend() */ + +/*-------------------------------------------------------------------------- + NAME H5S_hyper_add PURPOSE Add a block to hyperslab selection @@ -1712,7 +1807,7 @@ H5S_hyper_bsearch(hssize_t size, H5S_hyper_bound_t *barr, size_t count) 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 *size; IN: Size of block + const hsize_t *end; IN: Offset of end of block RETURNS SUCCEED/FAIL DESCRIPTION @@ -1723,14 +1818,14 @@ H5S_hyper_bsearch(hssize_t size, H5S_hyper_bound_t *barr, size_t count) REVISION LOG --------------------------------------------------------------------------*/ herr_t -H5S_hyper_add (H5S_t *space, const hssize_t *start, const hsize_t *size) +H5S_hyper_add (H5S_t *space, const hssize_t *start, const hsize_t *end) { H5S_hyper_node_t *slab; /* New hyperslab node to insert */ H5S_hyper_bound_t *tmp; /* Temporary pointer to an hyperslab bound array */ intn bound_loc; /* Boundary location to insert hyperslab */ size_t elem_count; /* Number of elements in hyperslab selection */ intn i; /* Counters */ - herr_t ret_value=FAIL; + herr_t ret_value=SUCCEED; #ifdef QAK extern int qak_debug; #endif /* QAK */ @@ -1740,7 +1835,7 @@ H5S_hyper_add (H5S_t *space, const hssize_t *start, const hsize_t *size) /* Check args */ assert (space); assert (start); - assert (size); + assert (end); #ifdef QAK qak_debug=1; @@ -1751,16 +1846,11 @@ H5S_hyper_add (H5S_t *space, const hssize_t *start, const hsize_t *size) #endif /* QAK */ /* Create new hyperslab node to insert */ if((slab = H5MM_malloc(sizeof(H5S_hyper_node_t)))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, - "can't allocate hyperslab node"); - if((slab->start = H5MM_malloc(sizeof(hsize_t)* - space->extent.u.simple.rank))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, - "can't allocate hyperslab start boundary"); - if((slab->end = H5MM_malloc(sizeof(hsize_t)* - space->extent.u.simple.rank))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, - "can't allocate hyperslab end boundary"); + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab node"); + if((slab->start = H5MM_malloc(sizeof(hsize_t)*space->extent.u.simple.rank))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab start boundary"); + if((slab->end = H5MM_malloc(sizeof(hsize_t)*space->extent.u.simple.rank))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab end boundary"); #ifdef QAK printf("%s: check 2.0\n",FUNC); @@ -1768,12 +1858,12 @@ H5S_hyper_add (H5S_t *space, const hssize_t *start, const hsize_t *size) /* Set boundary on new node */ for(i=0,elem_count=1; i<space->extent.u.simple.rank; i++) { #ifdef QAK - printf("%s: check 2.1, %d: start=%d, size=%d, elem_count=%d\n", - FUNC,(int)i,(int)start[i],(int)size[i],(int)elem_count); + printf("%s: check 2.1, %d: start=%d, end=%d, elem_count=%d\n", + FUNC,(int)i,(int)start[i],(int)end[i],(int)elem_count); #endif /* QAK */ slab->start[i]=start[i]; - slab->end[i]=start[i]+size[i]-1; - elem_count*=size[i]; + slab->end[i]=end[i]; + elem_count*=(end[i]-start[i])+1; } /* end for */ /* Initialize caching parameters */ @@ -1885,12 +1975,12 @@ H5S_hyper_add (H5S_t *space, const hssize_t *start, const hsize_t *size) space->select.sel_info.hyper.hyper_lst->hi_bounds[i][bound_loc].node=slab; } /* end else */ } /* end for */ -#ifdef QAK - printf("%s: check 5.0\n",FUNC); -#endif /* QAK */ /* Increment the number of bounds in the array */ space->select.sel_info.hyper.hyper_lst->count++; +#ifdef QAK + printf("%s: check 5.0, count=%d\n",FUNC,(int)space->select.sel_info.hyper.hyper_lst->count); +#endif /* QAK */ /* Prepend on list of hyperslabs for this selection */ slab->next=space->select.sel_info.hyper.hyper_lst->head; @@ -1899,27 +1989,271 @@ H5S_hyper_add (H5S_t *space, const hssize_t *start, const hsize_t *size) /* Increment the number of elements in the hyperslab selection */ space->select.num_elem+=elem_count; #ifdef QAK - printf("%s: check 6.0\n",FUNC); + printf("%s: check 6.0, elem_count=%d\n",FUNC,(int)elem_count); { intn j; for(i=0; i<space->extent.u.simple.rank; i++) { for(j=0; j<(int)space->select.sel_info.hyper.hyper_lst->count; j++) { - printf("%s: lo_bound[%d][%d]=%d, hi_bound[%d][%d]=%d\n", - FUNC,i,j, - (int)space->select.sel_info.hyper.hyper_lst->lo_bounds[i][j].bound,i,j, - (int)space->select.sel_info.hyper.hyper_lst->hi_bounds[i][j].bound); + printf("%s: lo_bound[%d][%d]=%d, hi_bound[%d][%d]=%d\n", FUNC, + i,j,(int)space->select.sel_info.hyper.hyper_lst->lo_bounds[i][j].bound, + i,j,(int)space->select.sel_info.hyper.hyper_lst->hi_bounds[i][j].bound); } } } #endif /* QAK */ done: - FUNC_LEAVE (SUCCEED); + FUNC_LEAVE (ret_value); } /* H5S_hyper_add() */ /*-------------------------------------------------------------------------- NAME + H5S_hyper_clip + PURPOSE + Clip a list of nodes against the current selection + USAGE + herr_t H5S_hyper_add(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 + RETURNS + SUCCEED/FAIL + 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. + 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) +{ + H5S_hyper_node_t *region, /* Temp. hyperslab selection region pointer */ + *node, /* Temp. hyperslab node pointer */ + *next_node; /* Pointer to next node in node list */ + hsize_t *start, *end=NULL; /* Temporary arrays of start & sizes (for splitting nodes) */ + intn rank; /* Cached copy of the rank of the dataspace */ + intn overlapped; /* Flag for overlapping nodes */ + intn non_intersect; /* Flag for non-intersecting nodes */ + intn i; /* Counters */ + enum /* Cases for edge overlaps */ + {OVERLAP_BOTH,OVERLAP_LOWER,OVERLAP_UPPER,WITHIN,NO_OVERLAP} clip_case; + herr_t ret_value=SUCCEED; + + FUNC_ENTER (H5S_hyper_clip, FAIL); + + /* Check args */ + assert (space); + assert (nodes); + + /* Allocate space for the temporary starts & sizes */ + if((start = H5MM_malloc(sizeof(hsize_t)*space->extent.u.simple.rank))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab start array"); + if((end = H5MM_malloc(sizeof(hsize_t)*space->extent.u.simple.rank))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab size array"); + + /* Set up local variables */ + rank=space->extent.u.simple.rank; + + /* + * Cycle through all the hyperslab nodes, clipping them against the + * existing hyperslab selection. + */ + node=nodes; + while(node!=NULL) { + /* Remove current node from head of list to evaulate it */ + next_node=node->next; /* retain next node in list */ + if(nodes==node) + nodes=nodes->next; /* Move head of list */ + node->next=NULL; /* just to be safe */ + + overlapped=0; /* Reset overlapped flag */ + region=space->select.sel_info.hyper.hyper_lst->head; + while(region!=NULL && overlapped==0) { + /* Check for intersection */ + for(i=0, non_intersect=0; i<rank && non_intersect==0; i++) { + if(node->end[i]<region->start[i] || node->start[i]>region->end[i]) + non_intersect=1; + } /* end for */ + + /* Only compare node with regions that actually intersect */ + if(non_intersect==0) { + /* Compare the boundaries of the two objects in each dimension */ + for(i=0; i<rank && overlapped==0; i++) { + /* Find overlap case we are in */ + + /* True if case 1, 4 or 2b */ + if(node->start[i]<region->start[i]) { + /* Test for case 4 */ + /* NO_OVERLAP cases could be taken out, but are left in for clarity */ + if(node->end[i]<region->start[i]) { + clip_case=NO_OVERLAP; + assert("invalid clipping case" && 0); + } /* end if */ + else { + /* Test for case 2b */ + if(node->end[i]<=region->end[i]) { + clip_case=OVERLAP_LOWER; + } /* end if */ + /* Must be case 1 */ + else { + clip_case=OVERLAP_BOTH; + } /* end else */ + } /* end else */ + } /* end if */ + /* Case 2a, 3 or 4 (on the other side)*/ + else { + /* Test for case 4 */ + if(node->start[i]>region->end[i]) { + clip_case=NO_OVERLAP; + assert("invalid clipping case" && 0); + } /* end if */ + /* Case 2a or 3 */ + else { + /* Test for case 2a */ + if(node->end[i]>region->end[i]) { + clip_case=OVERLAP_UPPER; + } /* end if */ + /* Must be case 3 */ + else { + clip_case=WITHIN; + } /* end else */ + } /* end else */ + } /* end else */ + + if(clip_case!=WITHIN) { + /* 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) { + /* Modify the end point in the current dimension of the overlap */ + end[i]=region->start[i]-1; + /* Clip the existing non-overlapped portion off the current node */ + node->start[i]=region->start[i]; + /* Add the non-overlapping portion to the list of new nodes */ + if(H5S_hyper_node_add(&nodes,1,rank,(const hsize_t *)start,(const hsize_t *)end)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslab"); + } /* end if */ + + /* 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[i]=region->end[i]+1; + end[i]=node->end[i]; + /* Clip the existing non-overlapped portion off the current node */ + node->end[i]=region->end[i]; + /* Add the non-overlapping portion to the list of new nodes */ + if(H5S_hyper_node_add(&nodes,1,rank,(const hsize_t *)start,(const hsize_t *)end)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslab"); + } /* end if */ + + /* 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(i==(rank-1)) { + if(overlap!=NULL) { + if(H5S_hyper_node_prepend(overlap,node)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslab"); + } + 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) { + if(uniq!=NULL) { + if(H5S_hyper_node_prepend(uniq,node)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslab"); + } + } /* 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 && nodes!=NULL) + node=nodes; + } /* end while */ + +done: + if(start!=NULL) + H5MM_xfree(start); + if(end!=NULL) + H5MM_xfree(end); + + FUNC_LEAVE (ret_value); +} /* H5S_hyper_clip() */ + +/*-------------------------------------------------------------------------- + NAME H5S_hyper_release PURPOSE Release hyperslab selection information for a dataspace @@ -2107,7 +2441,7 @@ H5S_hyper_copy (H5S_t *dst, const H5S_t *src) { H5S_hyper_list_t *new_hyper; /* New hyperslab selection */ H5S_hyper_node_t *curr, *new, *new_head; /* Hyperslab information nodes */ - H5S_hyper_dim_t *new_diminfo; /* New per-dimension info array[rank] */ + H5S_hyper_dim_t *new_diminfo=NULL; /* New per-dimension info array[rank] */ intn i; /* Counters */ size_t u; /* Counters */ herr_t ret_value=SUCCEED; /* return value */ @@ -2120,19 +2454,19 @@ H5S_hyper_copy (H5S_t *dst, const H5S_t *src) #ifdef QAK printf("%s: check 3.0\n", FUNC); #endif /* QAK */ - /* Create the per-dimension selection info */ - if((new_diminfo = H5MM_malloc(sizeof(H5S_hyper_dim_t)* - src->extent.u.simple.rank))==NULL) - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, - "can't allocate per-dimension array"); + if(src->select.sel_info.hyper.diminfo!=NULL) { + /* Create the per-dimension selection info */ + if((new_diminfo = H5MM_malloc(sizeof(H5S_hyper_dim_t)*src->extent.u.simple.rank))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate per-dimension array"); - /* Copy the per-dimension selection info */ - for(i=0; i<src->extent.u.simple.rank; i++) { - new_diminfo[i].start = src->select.sel_info.hyper.diminfo[i].start; - new_diminfo[i].stride = src->select.sel_info.hyper.diminfo[i].stride; - new_diminfo[i].count = src->select.sel_info.hyper.diminfo[i].count; - new_diminfo[i].block = src->select.sel_info.hyper.diminfo[i].block; - } /* end for */ + /* Copy the per-dimension selection info */ + for(i=0; i<src->extent.u.simple.rank; i++) { + new_diminfo[i].start = src->select.sel_info.hyper.diminfo[i].start; + new_diminfo[i].stride = src->select.sel_info.hyper.diminfo[i].stride; + new_diminfo[i].count = src->select.sel_info.hyper.diminfo[i].count; + new_diminfo[i].block = src->select.sel_info.hyper.diminfo[i].block; + } /* end for */ + } /* end if */ dst->select.sel_info.hyper.diminfo = new_diminfo; /* Create the new hyperslab information node */ diff --git a/src/H5Sprivate.h b/src/H5Sprivate.h index 95c6ae6..7d3b93b 100644 --- a/src/H5Sprivate.h +++ b/src/H5Sprivate.h @@ -335,8 +335,7 @@ herr_t H5S_all_release (H5S_t *space); hsize_t H5S_all_npoints (const H5S_t *space); /* Hyperslab selection functions */ -herr_t H5S_hyper_add (H5S_t *space, const hssize_t *start, - const hsize_t *size); +herr_t H5S_hyper_add (H5S_t *space, const hssize_t *start, const hsize_t *end); herr_t H5S_hyper_release (H5S_t *space); herr_t H5S_hyper_sel_iter_release (H5S_sel_iter_t *sel_iter); hsize_t H5S_hyper_npoints (const H5S_t *space); @@ -344,6 +343,8 @@ int H5S_hyper_compare_regions (const void *r1, const void *r2); int H5S_hyper_compare_bounds (const void *r1, const void *r2); herr_t H5S_hyper_copy (H5S_t *dst, const H5S_t *src); hbool_t H5S_hyper_select_valid (const H5S_t *space); +herr_t H5S_hyper_node_add (H5S_hyper_node_t **head, intn endflag, intn rank, const hssize_t *start, const hsize_t *size); +herr_t H5S_hyper_clip (H5S_t *space, H5S_hyper_node_t *nodes, H5S_hyper_node_t **uniq, H5S_hyper_node_t **overlap); #ifdef HAVE_PARALLEL /* MPI-IO function to read directly from app buffer to file rky980813 */ diff --git a/src/H5Spublic.h b/src/H5Spublic.h index 55b8ab1..5136544 100644 --- a/src/H5Spublic.h +++ b/src/H5Spublic.h @@ -34,8 +34,10 @@ typedef enum H5S_class_t { /* Different ways of combining selections */ typedef enum H5S_seloper_t { - H5S_NOOP = -1, /*error */ - H5S_SELECT_SET = 0 /* Select "set" operation */ + H5S_SELECT_NOOP = -1, /* error */ + H5S_SELECT_SET = 0, /* Select "set" operation */ + H5S_SELECT_OR, /* Binary "or" operation (add new selection to existing selection) */ + H5S_SELECT_INVALID /* Invalid upper bound on selection operations */ } H5S_seloper_t; #ifdef __cplusplus diff --git a/src/H5Sselect.c b/src/H5Sselect.c index 0620570..17804e4 100644 --- a/src/H5Sselect.c +++ b/src/H5Sselect.c @@ -229,8 +229,8 @@ H5S_select_release (H5S_t *space) 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 operation is supported. If STRIDE or BLOCK is NULL, they - are assumed to be set to all '1'. + H5S_SELECT_SET & H5S_SELECT_OR operations are supported. If STRIDE or + BLOCK is NULL, they are assumed to be set to all '1'. GLOBAL VARIABLES COMMENTS, BUGS, ASSUMPTIONS EXAMPLES @@ -256,14 +256,14 @@ H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, } if(start==NULL || count==NULL) { HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified"); - } - if(op!=H5S_SELECT_SET) { - HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, - "operations other than H5S_SELECT_SET not supported currently"); - } + } /* end if */ + + 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, + HRETURN_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to set hyperslab selection"); } @@ -299,6 +299,9 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, hsize_t *_block=NULL; /* Block size array */ 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 */ + *tmp; /* Temporary hyperslab node */ uintn acc; /* Accumulator for building slices */ uintn contig; /* whether selection is contiguous or not */ int i,j; /* Counters */ @@ -311,7 +314,7 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, assert(space); assert(start); assert(count); - assert(H5S_SELECT_SET==op); + assert(op>H5S_SELECT_NOOP && op<H5S_SELECT_INVALID); /* Fill in the correct stride values */ if(stride==NULL) { @@ -322,7 +325,7 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate stride vector"); H5V_array_fill(_stride,&fill,sizeof(hssize_t),space->extent.u.simple.rank); - stride = _stride; + stride = _stride; } /* Fill in the correct block values */ @@ -333,20 +336,20 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate block vector"); H5V_array_fill(_block,&fill,sizeof(hssize_t),space->extent.u.simple.rank); - block = _block; + block = _block; } /* * Check for overlapping blocks (remove when real block-merging algorithm - * is in place). + * is in place?). */ if(op==H5S_SELECT_SET && block!=NULL) { - for(i=0; i<space->extent.u.simple.rank; i++) { - if(stride[i]<block[i]) { - HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, - "hyperslab blocks overlap"); - } /* end if */ - } /* end for */ + for(i=0; i<space->extent.u.simple.rank; i++) { + if(stride[i]<block[i]) { + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, + "hyperslab blocks overlap"); + } /* end if */ + } /* end for */ } /* end if */ /* Determine if selection is contiguous */ @@ -371,19 +374,6 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, } /* end if */ } /* end if */ - /* Copy all the per-dimension selection info into the space descriptor */ - if((diminfo = H5MM_malloc(sizeof(H5S_hyper_dim_t)*space->extent.u.simple.rank))==NULL) { - HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, - "can't allocate per-dimension vector"); - } /* end if */ - for(i=0; i<space->extent.u.simple.rank; i++) { - diminfo[i].start = start[i]; - diminfo[i].stride = stride[i]; - diminfo[i].count = count[i]; - diminfo[i].block = block[i]; - } /* end for */ - space->select.sel_info.hyper.diminfo = diminfo; - #ifdef QAK printf("%s: check 2.0\n",FUNC); #endif /* QAK */ @@ -397,11 +387,93 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate hyperslab lo bound information"); } /* end if */ +#ifndef OLD_WAY /* Generate list of blocks to add/remove based on selection operation */ + switch(op) { + case H5S_SELECT_SET: + case H5S_SELECT_OR: + /* Generate list of blocks to add to selection */ + if(contig) { /* Check for trivial case */ + + /* Account for strides & blocks being equal, but larger than one */ + /* (Why someone would torture us this way, I don't know... -QAK :-) */ + for(i=0; i<space->extent.u.simple.rank; i++) + slab[i]=count[i]*stride[i]; + + /* 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 { + /* Build the slice sizes for each dimension */ + for(i=0, acc=1; i<space->extent.u.simple.rank; i++) { + slice[i]=acc; + acc*=count[i]; + } /* end for */ + + /* Step through all the blocks to add */ + /* (reuse the count in ACC above) */ + for(i=0; i<(int)acc; i++) { + /* Build the location of the block */ + for(j=0; j<space->extent.u.simple.rank; j++) + slab[j]=start[j]+((i/slice[j])%count[j])*stride[j]; + + /* 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 if */ + + /* Clip list of new blocks to add against current selection */ + if(op==H5S_SELECT_OR) { + H5S_hyper_clip(space,add,&uniq,NULL); + add=uniq; + } /* end if */ + else { + /* Copy all the per-dimension selection info into the space descriptor */ + if((diminfo = H5MM_malloc(sizeof(H5S_hyper_dim_t)*space->extent.u.simple.rank))==NULL) { + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate per-dimension vector"); + } /* end if */ + for(i=0; i<space->extent.u.simple.rank; i++) { + diminfo[i].start = start[i]; + diminfo[i].stride = stride[i]; + diminfo[i].count = count[i]; + diminfo[i].block = block[i]; + } /* end for */ + space->select.sel_info.hyper.diminfo = diminfo; + } /* end else */ + break; + + default: + HRETURN_ERROR(H5E_ARGS, H5E_UNSUPPORTED, FAIL, "invalid selection operation"); + break; + } /* end switch */ + + /* Add new blocks to current selection */ + while(add!=NULL) { + tmp=add->next; + + /* Add new block */ + if(H5S_hyper_add(space,(const hssize_t *)add->start, (const hsize_t *)add->end)<0) + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslab"); + + /* Free nodes in list */ + H5MM_xfree(add->start); + H5MM_xfree(add->end); + H5MM_xfree(add); + + /* Go to next node */ + add=tmp; + } /* end while */ + + /* Merge blocks for better I/O performance */ + /* Regenerate lo/hi bounds arrays? */ #ifdef QAK printf("%s: check 3.0\n",FUNC); #endif /* QAK */ +#else /* OLD_WAY */ /* Add hyperslab to selection */ if(contig) { /* Check for trivial case */ @@ -412,8 +484,7 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, /* Add the contiguous hyperslab to the selection */ if(H5S_hyper_add(space,start,(const hsize_t *)slab)<0) { - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, - "can't insert hyperslab"); + HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, "can't insert hyperslab"); } } else { /* Build the slice sizes for each dimension */ @@ -430,13 +501,12 @@ H5S_select_hyperslab (H5S_t *space, H5S_seloper_t op, slab[j]=start[j]+((i/slice[j])%count[j])*stride[j]; /* Add the block to the list of hyperslab selections */ - if(H5S_hyper_add(space,(const hssize_t *)slab, - (const hsize_t *)block)<0) { - HGOTO_ERROR(H5E_DATASPACE, H5E_CANTINSERT, FAIL, - "can't insert hyperslab"); + if(H5S_hyper_add(space,(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 if */ +#endif /* OLD_WAY */ /* Set selection type */ space->select.type=H5S_SEL_HYPERSLABS; |