diff options
author | Quincey Koziol <koziol@hdfgroup.org> | 2001-11-02 20:31:35 (GMT) |
---|---|---|
committer | Quincey Koziol <koziol@hdfgroup.org> | 2001-11-02 20:31:35 (GMT) |
commit | 1cd9eb7e0d282aaf5161af220aae00cc7f7e31f9 (patch) | |
tree | 90c364175d9336948f7f98ec7c632494af48edb3 | |
parent | e9d955be61f79ceddd6be3d279f723d8e9153b9b (diff) | |
download | hdf5-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)
-rw-r--r-- | src/H5D.c | 63 | ||||
-rw-r--r-- | src/H5E.c | 6 | ||||
-rw-r--r-- | src/H5Epublic.h | 4 | ||||
-rw-r--r-- | src/H5FL.c | 2 | ||||
-rw-r--r-- | src/H5S.c | 2 | ||||
-rw-r--r-- | src/H5Sall.c | 112 | ||||
-rw-r--r-- | src/H5Shyper.c | 7777 | ||||
-rw-r--r-- | src/H5Spkg.h | 83 | ||||
-rw-r--r-- | src/H5Spoint.c | 4 | ||||
-rw-r--r-- | src/H5Sprivate.h | 30 | ||||
-rw-r--r-- | src/H5Spublic.h | 40 | ||||
-rw-r--r-- | src/H5Sselect.c | 165 |
12 files changed, 5463 insertions, 2825 deletions
@@ -2098,7 +2098,7 @@ H5D_read(H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space, #endif #ifdef QAK -printf("%s: check 1.0, nelmts=%d\n",FUNC,(int)nelmts); +printf("%s: check 1.0, nelmts=%d, H5S_get_select_npoints(file_space)=%d\n",FUNC,(int)nelmts,(int)H5S_get_select_npoints(file_space)); #endif /* QAK */ /* * Locate the type conversion function and data space conversion @@ -2222,29 +2222,32 @@ printf("%s: check 1.2, \n",FUNC); } #endif /* - * This is the general case. Figure out the strip mine size. + * This is the general case. */ - if ((sconv->f->init)(file_space, &file_iter)<0) { + + /* Compute element sizes and other parameters */ + src_type_size = H5T_get_size(dataset->type); + dst_type_size = H5T_get_size(mem_type); + target_size = H5P_peek_size_t(dxpl_id,H5D_XFER_MAX_TEMP_BUF_NAME); +#ifdef QAK +printf("%s: check 2.0, src_type_size=%d, dst_type_size=%d, target_size=%d, min_elem_out=%d\n",FUNC,(int)src_type_size,(int)dst_type_size,(int)target_size,(int)min_elem_out); +#endif /* QAK */ + request_nelmts = target_size / MAX(src_type_size, dst_type_size); + + /* Figure out the strip mine size. */ + if ((sconv->f->init)(file_space, src_type_size, &file_iter)<0) { HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize file selection information"); } - if ((sconv->m->init)(mem_space, &mem_iter)<0) { + if ((sconv->m->init)(mem_space, dst_type_size, &mem_iter)<0) { HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize memory selection information"); } - if ((sconv->m->init)(mem_space, &bkg_iter)<0) { + if ((sconv->m->init)(mem_space, dst_type_size, &bkg_iter)<0) { HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, "unable to initialize background selection information"); } - src_type_size = H5T_get_size(dataset->type); - dst_type_size = H5T_get_size(mem_type); - target_size = H5P_peek_size_t(dxpl_id,H5D_XFER_MAX_TEMP_BUF_NAME); -#ifdef QAK -printf("%s: check 2.0, src_type_size=%d, dst_type_size=%d, target_size=%d\n",FUNC,(int)src_type_size,(int)dst_type_size,(int)target_size); -#endif /* QAK */ - request_nelmts = target_size / MAX(src_type_size, dst_type_size); - #ifdef QAK printf("%s: check 3.0, request_nelmts=%d\n",FUNC,(int)request_nelmts); #endif @@ -2731,21 +2734,10 @@ H5D_write(H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space, } #endif /* - * This is the general case. Figure out the strip mine size. + * This is the general case. */ - if ((sconv->f->init)(file_space, &file_iter)<0) { - HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, - "unable to initialize file selection information"); - } - if ((sconv->m->init)(mem_space, &mem_iter)<0) { - HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, - "unable to initialize memory selection information"); - } - if ((sconv->f->init)(file_space, &bkg_iter)<0) { - HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, - "unable to initialize memory selection information"); - } - + + /* Compute element sizes and other parameters */ src_type_size = H5T_get_size(mem_type); dst_type_size = H5T_get_size(dataset->type); target_size = H5P_peek_size_t(dxpl_id,H5D_XFER_MAX_TEMP_BUF_NAME); @@ -2753,7 +2745,6 @@ H5D_write(H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space, printf("%s: check 2.0, src_type_size=%d, dst_type_size=%d, target_size=%d\n",FUNC,(int)src_type_size,(int)dst_type_size,(int)target_size); #endif /* QAK */ request_nelmts = target_size / MAX (src_type_size, dst_type_size); - #ifdef QAK printf("%s: check 3.0, request_nelmts=%d, tpath->cdata.need_bkg=%d\n",FUNC,(int)request_nelmts,(int)tpath->cdata.need_bkg); #endif @@ -2762,6 +2753,20 @@ printf("%s: check 2.0, src_type_size=%d, dst_type_size=%d, target_size=%d\n",FUN "temporary buffer max size is too small"); } + /* Figure out the strip mine size. */ + if ((sconv->f->init)(file_space, dst_type_size, &file_iter)<0) { + HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, + "unable to initialize file selection information"); + } + if ((sconv->m->init)(mem_space, src_type_size, &mem_iter)<0) { + HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, + "unable to initialize memory selection information"); + } + if ((sconv->f->init)(file_space, dst_type_size, &bkg_iter)<0) { + HGOTO_ERROR (H5E_DATASET, H5E_CANTINIT, FAIL, + "unable to initialize memory selection information"); + } + /* * Get a temporary buffer for type conversion unless the app has already * supplied one through the xfer properties. Instead of allocating a @@ -2828,6 +2833,7 @@ printf("%s: check 2.0, src_type_size=%d, dst_type_size=%d, target_size=%d\n",FUN } #ifdef QAK +#ifdef QAK { int i; uint16_t *b; @@ -2841,6 +2847,7 @@ printf("%s: check 2.0, src_type_size=%d, dst_type_size=%d, target_size=%d\n",FUN printf("\n"); } } +#endif /* QAK */ printf("%s: check 6.0, tconv_buf=%p, *tconv_buf=%p\n",FUNC,tconv_buf,*(char **)tconv_buf); #endif @@ -137,11 +137,15 @@ static const H5E_minor_mesg_t H5E_minor_mesg_g[] = { /* Datatype conversion errors */ {H5E_CANTCONVERT, "Can't convert datatypes"}, + /* Dataspace errors */ + {H5E_CANTCLIP, "Can't clip hyperslab region"}, + {H5E_CANTCOUNT, "Can't count elements"}, + /* Property list errors */ {H5E_CANTGET, "Can't get value"}, {H5E_CANTSET, "Can't set value"}, - /* Datatype conversion errors */ + /* Parallel I/O errors */ {H5E_MPI, "Some MPI function failed"} }; diff --git a/src/H5Epublic.h b/src/H5Epublic.h index 1118302..e364b7e 100644 --- a/src/H5Epublic.h +++ b/src/H5Epublic.h @@ -177,6 +177,10 @@ typedef enum H5E_minor_t { /* Datatype conversion errors */ H5E_CANTCONVERT, /*Can't convert datatypes */ + /* Dataspace errors */ + H5E_CANTCLIP, /*Can't clip hyperslab region */ + H5E_CANTCOUNT, /*Can't count elements */ + /* Property list errors */ H5E_CANTGET, /*Can't get value */ H5E_CANTSET, /*Can't set value */ @@ -1505,7 +1505,7 @@ printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_arr_gc_head.fi /* No maximum number of elements, use the PQ information */ else { #ifdef H5FL_DEBUG -printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_arr_gc_head->list->name,(int)H5FL_arr_gc_head->list->u.queue.allocated); +printf("H5FL_arr_term: head->name=%s, head->allocated=%d\n", H5FL_arr_gc_head.first->list->name,(int)H5FL_arr_gc_head.first->list->u.queue.allocated); #endif /* H5FL_DEBUG */ /* Check if the list has allocations outstanding */ if(H5FL_arr_gc_head.first->list->u.queue.allocated>0) { @@ -87,7 +87,7 @@ H5S_init_interface(void) /* Register space conversion functions */ if (H5S_register(H5S_SEL_POINTS, H5S_POINT_FCONV, H5S_POINT_MCONV)<0 || H5S_register(H5S_SEL_ALL, H5S_ALL_FCONV, H5S_ALL_MCONV) <0 || - H5S_register(H5S_SEL_HYPERSLABS, H5S_HYPER_FCONV, H5S_HYPER_MCONV)<0) { + H5S_register(H5S_SEL_HYPERSLABS, H5S_HYPER_FCONV, H5S_HYPER_MCONV) <0) { HRETURN_ERROR(H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to register one or more conversion functions"); } diff --git a/src/H5Sall.c b/src/H5Sall.c index a676f73..26b4abd 100644 --- a/src/H5Sall.c +++ b/src/H5Sall.c @@ -22,7 +22,7 @@ #define INTERFACE_INIT NULL static int interface_initialize_g = 0; -static herr_t H5S_all_init (const H5S_t *space, H5S_sel_iter_t *iter); +static herr_t H5S_all_init (const H5S_t *space, size_t elmt_size, H5S_sel_iter_t *iter); static hsize_t H5S_all_favail (const H5S_t *space, const H5S_sel_iter_t *iter, hsize_t max); static hsize_t H5S_all_fgath (H5F_t *f, const struct H5O_layout_t *layout, @@ -80,7 +80,7 @@ const H5S_mconv_t H5S_ALL_MCONV[1] = {{ *------------------------------------------------------------------------- */ static herr_t -H5S_all_init (const H5S_t *space, H5S_sel_iter_t *sel_iter) +H5S_all_init (const H5S_t *space, size_t UNUSED elmt_size, H5S_sel_iter_t *sel_iter) { FUNC_ENTER (H5S_all_init, FAIL); @@ -392,8 +392,8 @@ H5S_all_read(H5F_t *f, const H5O_layout_t *layout, const H5O_pline_t *pline, const H5S_t *mem_space, hid_t dxpl_id, void *_buf/*out*/, hbool_t *must_convert/*out*/) { + H5S_hyper_span_t *file_span=NULL,*mem_span=NULL; /* Hyperslab span node */ char *buf=(char*)_buf; /* Get pointer to buffer */ - H5S_hyper_node_t *file_node=NULL,*mem_node=NULL; /* Hyperslab node */ hsize_t mem_size,file_size; hssize_t file_off,mem_off; hssize_t count; /* Regular hyperslab count */ @@ -433,9 +433,24 @@ printf("%s: check 1.0\n",FUNC); goto fall_through; } /* end if */ else { - if(mem_space->select.sel_info.hslab.hyper_lst->count>1) - goto fall_through; - mem_node=mem_space->select.sel_info.hslab.hyper_lst->head; + /* Get the pointer to the hyperslab spans to check */ + mem_span=mem_space->select.sel_info.hslab.span_lst->head; + + /* Spin through the spans, checking for more than one span in each dimension */ + while(mem_span!=NULL) { + /* If there are more than one span in the dimension, we can't use this routine */ + if(mem_span->next!=NULL) + goto fall_through; + + /* Advance to the next span, if it's available */ + if(mem_span->down==NULL) + break; + else + mem_span=mem_span->down->head; + } /* end while */ + + /* Get the pointer to the hyperslab spans to use */ + mem_span=mem_space->select.sel_info.hslab.span_lst->head; } /* end else */ } /* end if */ else @@ -454,9 +469,24 @@ printf("%s: check 1.0\n",FUNC); goto fall_through; } /* end if */ else { - if(file_space->select.sel_info.hslab.hyper_lst->count>1) - goto fall_through; - file_node=file_space->select.sel_info.hslab.hyper_lst->head; + /* Get the pointer to the hyperslab spans to check */ + file_span=file_space->select.sel_info.hslab.span_lst->head; + + /* Spin through the spans, checking for more than one span in each dimension */ + while(file_span!=NULL) { + /* If there are more than one span in the dimension, we can't use this routine */ + if(file_span->next!=NULL) + goto fall_through; + + /* Advance to the next span, if it's available */ + if(file_span->down==NULL) + break; + else + file_span=file_span->down->head; + } /* end while */ + + /* Get the pointer to the hyperslab spans to use */ + file_span=file_space->select.sel_info.hslab.span_lst->head; } /* end else */ } /* end if */ else @@ -472,8 +502,9 @@ printf("%s: check 1.0\n",FUNC); mem_off=mem_space->select.sel_info.hslab.diminfo[u].start; } /* end if */ else { - mem_size=(mem_node->end[u]-mem_node->start[u])+1; - mem_off=mem_node->start[u]; + mem_size=(mem_span->high-mem_span->low)+1; + mem_off=mem_span->low; + mem_span=mem_span->down->head; } /* end else */ } /* end if */ else { @@ -488,8 +519,9 @@ printf("%s: check 1.0\n",FUNC); file_off=file_space->select.sel_info.hslab.diminfo[u].start; } /* end if */ else { - file_size=(file_node->end[u]-file_node->start[u])+1; - file_off=file_node->start[u]; + file_size=(file_span->high-file_span->low)+1; + file_off=file_span->low; + file_span=file_span->down->head; } /* end else */ } /* end if */ else { @@ -628,8 +660,8 @@ H5S_all_write(H5F_t *f, const struct H5O_layout_t *layout, const H5S_t *mem_space, hid_t dxpl_id, const void *_buf, hbool_t *must_convert/*out*/) { + H5S_hyper_span_t *file_span=NULL,*mem_span=NULL; /* Hyperslab span node */ const char *buf=(const char*)_buf; /* Get pointer to buffer */ - H5S_hyper_node_t *file_node=NULL,*mem_node=NULL; /* Hyperslab node */ hsize_t mem_size,file_size; hssize_t file_off,mem_off; hssize_t count; /* Regular hyperslab count */ @@ -666,9 +698,24 @@ H5S_all_write(H5F_t *f, const struct H5O_layout_t *layout, goto fall_through; } /* end if */ else { - if(mem_space->select.sel_info.hslab.hyper_lst->count>1) - goto fall_through; - mem_node=mem_space->select.sel_info.hslab.hyper_lst->head; + /* Get the pointer to the hyperslab spans to check */ + mem_span=mem_space->select.sel_info.hslab.span_lst->head; + + /* Spin through the spans, checking for more than one span in each dimension */ + while(mem_span!=NULL) { + /* If there are more than one span in the dimension, we can't use this routine */ + if(mem_span->next!=NULL) + goto fall_through; + + /* Advance to the next span, if it's available */ + if(mem_span->down==NULL) + break; + else + mem_span=mem_span->down->head; + } /* end while */ + + /* Get the pointer to the hyperslab spans to use */ + mem_span=mem_space->select.sel_info.hslab.span_lst->head; } /* end else */ } /* end if */ else @@ -687,9 +734,24 @@ H5S_all_write(H5F_t *f, const struct H5O_layout_t *layout, goto fall_through; } /* end if */ else { - if(file_space->select.sel_info.hslab.hyper_lst->count>1) - goto fall_through; - file_node=file_space->select.sel_info.hslab.hyper_lst->head; + /* Get the pointer to the hyperslab spans to check */ + file_span=file_space->select.sel_info.hslab.span_lst->head; + + /* Spin through the spans, checking for more than one span in each dimension */ + while(file_span!=NULL) { + /* If there are more than one span in the dimension, we can't use this routine */ + if(file_span->next!=NULL) + goto fall_through; + + /* Advance to the next span, if it's available */ + if(file_span->down==NULL) + break; + else + file_span=file_span->down->head; + } /* end while */ + + /* Get the pointer to the hyperslab spans to use */ + file_span=file_space->select.sel_info.hslab.span_lst->head; } /* end else */ } /* end if */ else @@ -705,8 +767,9 @@ H5S_all_write(H5F_t *f, const struct H5O_layout_t *layout, mem_off=mem_space->select.sel_info.hslab.diminfo[u].start; } /* end if */ else { - mem_size=(mem_node->end[u]-mem_node->start[u])+1; - mem_off=mem_node->start[u]; + mem_size=(mem_span->high-mem_span->low)+1; + mem_off=mem_span->low; + mem_span=mem_span->down->head; } /* end else */ } /* end if */ else { @@ -721,8 +784,9 @@ H5S_all_write(H5F_t *f, const struct H5O_layout_t *layout, file_off=file_space->select.sel_info.hslab.diminfo[u].start; } /* end if */ else { - file_size=(file_node->end[u]-file_node->start[u])+1; - file_off=file_node->start[u]; + file_size=(file_span->high-file_span->low)+1; + file_off=file_span->low; + file_span=file_span->down->head; } /* end else */ } /* end if */ else { 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 */ diff --git a/src/H5Spkg.h b/src/H5Spkg.h index cf6001b..7c4d53f 100644 --- a/src/H5Spkg.h +++ b/src/H5Spkg.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2000-2001 NCSA - * All rights reserved. + * Copyright (C) 2000 NCSA + * All rights reserved. * * Programmer: Quincey Koziol <koziol@ncsa.uiuc.edu> * Thursday, September 28, 2000 @@ -16,7 +16,7 @@ #ifndef _H5Spkg_H #define _H5Spkg_H -#include "H5Sprivate.h" +#include <H5Sprivate.h> /* * Dataspace extent information @@ -53,41 +53,23 @@ typedef struct { H5S_pnt_node_t *head; /* Pointer to head of point list */ } H5S_pnt_list_t; -/* Node in hyperslab selection list */ -typedef struct H5S_hyper_node_tag { - hssize_t *start; /* Pointer to a corner of a hyperslab closest to the origin */ - hssize_t *end; /* Pointer to a corner of a hyperslab furthest from the origin */ - struct { - unsigned cached; /* Flag to indicate that the block is cached (during I/O only) */ - size_t size; /* Size of cached block (in elements) */ - unsigned rleft; /* Read elements left to access in block */ - unsigned wleft; /* Write elements left to access in block */ - uint8_t *block; /* Pointer into buffer for cache */ - uint8_t *rpos; /* Pointer to current read location within block */ - uint8_t *wpos; /* Pointer to current write location within block */ - } cinfo; - struct H5S_hyper_node_tag *next; /* pointer to next hyperslab in list */ -} H5S_hyper_node_t; - -/* Region in dimension */ -typedef struct H5S_hyper_region_tag { - hssize_t start; /* The low bound of a region in a dimension */ - hssize_t end; /* The high bound of a region in a dimension */ - H5S_hyper_node_t *node; /* pointer to the node the region is in */ -} H5S_hyper_region_t; - -/* Information about hyperslab boundary and pointer to hyperslab node */ -typedef struct { - hssize_t bound; /* Location of boundary */ - H5S_hyper_node_t *node; /* Boundary's node */ -} H5S_hyper_bound_t; +/* Information about new-style hyperslab spans */ -/* Information about hyperslab list */ -typedef struct { - size_t count; /* Number of nodes in list */ - H5S_hyper_node_t *head; /* Pointer to head of hyperslab list */ - H5S_hyper_bound_t **lo_bounds; /* Lower (closest to the origin) bound array for each dimension */ -} H5S_hyper_list_t; +/* Information a particular hyperslab span */ +struct H5S_hyper_span_t { + hssize_t low, high; /* Low & high bounds of span */ + hsize_t nelem; /* Number of elements in span (only needed during I/O) */ + hsize_t pstride; /* Pseudo-stride from start of previous span (only used during I/O) */ + struct H5S_hyper_span_info_t *down; /* Pointer to list of spans in next dimension down */ + struct H5S_hyper_span_t *next; /* Pointer to next span in list */ +}; + +/* Information about a list of hyperslab spans */ +struct H5S_hyper_span_info_t { + unsigned count; /* Ref. count of number of spans which share this span */ + struct H5S_hyper_span_info_t *scratch; /* Scratch pointer (used during copies & as mark during precomputes for I/O) */ + struct H5S_hyper_span_t *head; /* Pointer to list of spans in next dimension down */ +}; /* Information about one dimension in a hyperslab selection */ typedef struct { @@ -97,7 +79,7 @@ typedef struct { hsize_t block; } H5S_hyper_dim_t; -/* Information about hyperslab selection */ +/* Information about new-style hyperslab selection */ typedef struct { H5S_hyper_dim_t *diminfo; /* ->[rank] of per-dim selection info */ /* diminfo only points to one array, which holds the information @@ -106,12 +88,12 @@ typedef struct { * restriction to H5S_SELECT_SET is removed. */ H5S_hyper_dim_t *app_diminfo;/* ->[rank] of per-dim selection info */ /* 'diminfo' points to a [potentially] optimized version of the user's - * hyperslab information. 'app_diminfo' points to the actual parameters - * that the application used for setting the hyperslab selection. These - * are only used for re-gurgitating the original values used to set the - * hyperslab to the application when it queries the hyperslab selection - * information. */ - H5S_hyper_list_t *hyper_lst; /* List of selected hyperslabs (order is not important) */ + * hyperslab information. 'app_diminfo' points to the actual parameters + * that the application used for setting the hyperslab selection. These + * are only used for re-gurgitating the original values used to set the + * hyperslab to the application when it queries the hyperslab selection + * information. */ + H5S_hyper_span_info_t *span_lst; /* List of hyperslab span information */ } H5S_hyper_sel_t; /* Selection information container */ @@ -122,7 +104,7 @@ typedef struct { hsize_t num_elem; /* Number of elements in selection */ union { H5S_pnt_list_t *pnt_lst; /* List of selected points (order is important) */ - H5S_hyper_sel_t hslab; /* Info about hyperslab selections */ + H5S_hyper_sel_t hslab; /* Info about new-style hyperslab selections */ } sel_info; } H5S_select_t; @@ -181,20 +163,13 @@ __DLL__ herr_t H5S_all_select_iterate(void *buf, hid_t type_id, H5S_t *space, __DLL__ herr_t H5S_hyper_release(H5S_t *space); __DLL__ herr_t H5S_hyper_sel_iter_release(H5S_sel_iter_t *sel_iter); __DLL__ hsize_t H5S_hyper_npoints(const H5S_t *space); -__DLL__ int H5S_hyper_compare_regions(const void *r1, const void *r2); -__DLL__ int H5S_hyper_compare_bounds(const void *r1, const void *r2); __DLL__ herr_t H5S_hyper_copy(H5S_t *dst, const H5S_t *src); __DLL__ htri_t H5S_hyper_select_valid(const H5S_t *space); -__DLL__ int H5S_hyper_bound_comp(const void *_b1, const void *_b2); -__DLL__ herr_t H5S_hyper_node_add(H5S_hyper_node_t **head, int endflag, - unsigned rank, const hssize_t *start, - const hsize_t *size); -__DLL__ herr_t H5S_hyper_clip(H5S_t *space, H5S_hyper_node_t *nodes, - H5S_hyper_node_t **uniq, - H5S_hyper_node_t **overlap); __DLL__ hssize_t H5S_hyper_select_serial_size(const H5S_t *space); __DLL__ herr_t H5S_hyper_select_serialize(const H5S_t *space, uint8_t *buf); __DLL__ herr_t H5S_hyper_select_deserialize(H5S_t *space, const uint8_t *buf); +__DLL__ hssize_t H5S_hyper_span_nblocks(H5S_hyper_span_info_t *spans); +__DLL__ 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); __DLL__ herr_t H5S_hyper_bounds(H5S_t *space, hsize_t *start, hsize_t *end); __DLL__ htri_t H5S_hyper_select_contiguous(const H5S_t *space); __DLL__ herr_t H5S_hyper_select_iterate(void *buf, hid_t type_id, H5S_t *space, diff --git a/src/H5Spoint.c b/src/H5Spoint.c index b21096d..5f89957 100644 --- a/src/H5Spoint.c +++ b/src/H5Spoint.c @@ -23,7 +23,7 @@ #define INTERFACE_INIT NULL static int interface_initialize_g = 0; -static herr_t H5S_point_init (const H5S_t *space, H5S_sel_iter_t *iter); +static herr_t H5S_point_init (const H5S_t *space, size_t elmt_size, H5S_sel_iter_t *iter); static hsize_t H5S_point_favail (const H5S_t *space, const H5S_sel_iter_t *iter, hsize_t max); static hsize_t H5S_point_fgath (H5F_t *f, const struct H5O_layout_t *layout, @@ -83,7 +83,7 @@ const H5S_mconv_t H5S_POINT_MCONV[1] = {{ *------------------------------------------------------------------------- */ static herr_t -H5S_point_init (const H5S_t *space, H5S_sel_iter_t *sel_iter) +H5S_point_init (const H5S_t *space, size_t UNUSED elmt_size, H5S_sel_iter_t *sel_iter) { FUNC_ENTER (H5S_point_init, FAIL); diff --git a/src/H5Sprivate.h b/src/H5Sprivate.h index 11eb054..594e8bf 100644 --- a/src/H5Sprivate.h +++ b/src/H5Sprivate.h @@ -33,15 +33,17 @@ /* Forward references of common typedefs */ typedef struct H5S_t H5S_t; typedef struct H5S_pnt_node_t H5S_pnt_node_t; +typedef struct H5S_hyper_span_t H5S_hyper_span_t; +typedef struct H5S_hyper_span_info_t H5S_hyper_span_info_t; /* Enumerated type for the type of selection */ typedef enum { - H5S_SEL_ERROR = -1, /* Error */ - H5S_SEL_NONE = 0, /* Nothing selected */ - H5S_SEL_POINTS = 1, /* Sequence of points selected */ - H5S_SEL_HYPERSLABS = 2, /* Hyperslab selection defined */ - H5S_SEL_ALL = 3, /* Entire extent selected */ - H5S_SEL_N = 4 /*THIS MUST BE LAST */ + H5S_SEL_ERROR = -1, /* Error */ + H5S_SEL_NONE = 0, /* Nothing selected */ + H5S_SEL_POINTS = 1, /* Sequence of points selected */ + H5S_SEL_HYPERSLABS = 2, /* "New-style" hyperslab selection defined */ + H5S_SEL_ALL = 3, /* Entire extent selected */ + H5S_SEL_N = 4 /*THIS MUST BE LAST */ }H5S_sel_type; /* Point selection iteration container */ @@ -50,9 +52,12 @@ typedef struct { H5S_pnt_node_t *curr; /* Pointer to next node to output */ } H5S_point_iter_t; -/* Hyperslab selection iteration container */ +/* New Hyperslab selection iteration container */ typedef struct { hsize_t elmt_left; /* Number of elements left to iterate over */ + H5S_hyper_span_info_t *spans; /* Pointer to copy of the span tree */ + H5S_hyper_span_t **span; /* Array of pointers to span nodes */ + hssize_t *off; /* Offset in span node */ hssize_t *pos; /* Position to start iterating at */ } H5S_hyper_iter_t; @@ -65,7 +70,7 @@ typedef struct { /* Selection iteration container */ typedef union { H5S_point_iter_t pnt; /* Point selection iteration information */ - H5S_hyper_iter_t hyp; /* Hyperslab selection iteration information */ + H5S_hyper_iter_t hyp; /* New Hyperslab selection iteration information */ H5S_all_iter_t all; /* "All" selection iteration information */ } H5S_sel_iter_t; @@ -81,7 +86,7 @@ typedef struct H5S_fconv_t { H5S_sel_type type; /* Initialize file element numbering information */ - herr_t (*init)(const H5S_t *space, H5S_sel_iter_t *iter); + herr_t (*init)(const H5S_t *space, size_t elmt_size, H5S_sel_iter_t *iter); /* Determine optimal number of elements to transfer */ hsize_t (*avail)(const H5S_t *file_space, const H5S_sel_iter_t *file_iter, @@ -110,7 +115,7 @@ typedef struct H5S_mconv_t { H5S_sel_type type; /* Initialize memory element numbering information */ - herr_t (*init)(const H5S_t *space, H5S_sel_iter_t *iter); + herr_t (*init)(const H5S_t *space, size_t elmt_size, H5S_sel_iter_t *iter); /* Gather elements from app buffer to type conversion buffer */ hsize_t (*gath)(const void *buf, size_t elmt_size, @@ -207,11 +212,6 @@ __DLL__ H5S_t *H5S_read(struct H5G_entry_t *ent); __DLL__ int H5S_cmp(const H5S_t *ds1, const H5S_t *ds2); __DLL__ htri_t H5S_is_simple(const H5S_t *sdim); __DLL__ unsigned H5S_nelem(const H5S_t *space); -__DLL__ 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[]); __DLL__ int H5S_get_hyperslab(const H5S_t *ds, hssize_t offset[]/*out*/, hsize_t size[]/*out*/, hsize_t stride[]/*out*/); __DLL__ herr_t H5S_select_copy(H5S_t *dst, const H5S_t *src); diff --git a/src/H5Spublic.h b/src/H5Spublic.h index 577998b..7c5ab31 100644 --- a/src/H5Spublic.h +++ b/src/H5Spublic.h @@ -40,7 +40,34 @@ typedef enum H5S_seloper_t { H5S_SELECT_NOOP = -1, /* error */ H5S_SELECT_SET = 0, /* Select "set" operation */ H5S_SELECT_OR, /* Binary "or" operation for hyperslabs - * (add new selection to existing selection) + * (add new selection to existing selection) + * Original region: AAAAAAAAAA + * New region: BBBBBBBBBB + * A or B: CCCCCCCCCCCCCCCC + */ + H5S_SELECT_AND, /* Binary "and" operation for hyperslabs + * (only leave overlapped regions in selection) + * Original region: AAAAAAAAAA + * New region: BBBBBBBBBB + * A and B: CCCC + */ + H5S_SELECT_XOR, /* Binary "xor" operation for hyperslabs + * (only leave non-overlapped regions in selection) + * Original region: AAAAAAAAAA + * New region: BBBBBBBBBB + * A xor B: CCCCCC CCCCCC + */ + H5S_SELECT_NOTB, /* Binary "not" operation for hyperslabs + * (only leave non-overlapped regions in original selection) + * Original region: AAAAAAAAAA + * New region: BBBBBBBBBB + * A not B: CCCCCC + */ + H5S_SELECT_NOTA, /* Binary "not" operation for hyperslabs + * (only leave non-overlapped regions in new selection) + * Original region: AAAAAAAAAA + * New region: BBBBBBBBBB + * B not A: CCCCCC */ H5S_SELECT_APPEND, /* Append elements to end of point selection */ H5S_SELECT_PREPEND, /* Prepend elements to beginning of point selection */ @@ -72,6 +99,17 @@ __DLL__ herr_t H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, const hsize_t _stride[], const hsize_t count[], const hsize_t _block[]); +#ifdef NEW_HYPERSLAB_API +__DLL__ 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[]); +__DLL__ herr_t H5Sselect_select(hid_t space1_id, H5S_seloper_t op, + hid_t space2_id); +__DLL__ hid_t H5Scombine_select(hid_t space1_id, H5S_seloper_t op, + hid_t space2_id); +#endif /* OLD_WAY */ __DLL__ herr_t H5Sselect_elements(hid_t space_id, H5S_seloper_t op, size_t num_elemn, const hssize_t **coord); diff --git a/src/H5Sselect.c b/src/H5Sselect.c index a0be458..623aeea 100644 --- a/src/H5Sselect.c +++ b/src/H5Sselect.c @@ -235,25 +235,25 @@ H5S_get_select_npoints (const H5S_t *space) assert(space); switch(space->select.type) { - case H5S_SEL_POINTS: /* Sequence of points selected */ - ret_value=H5S_point_npoints(space); - break; + case H5S_SEL_POINTS: /* Sequence of points selected */ + ret_value=H5S_point_npoints(space); + break; - case H5S_SEL_HYPERSLABS: /* Hyperslab selection defined */ - ret_value=H5S_hyper_npoints(space); - break; + case H5S_SEL_HYPERSLABS: /* Hyperslab selection defined */ + ret_value=H5S_hyper_npoints(space); + break; - case H5S_SEL_ALL: /* Entire extent selected */ - ret_value=H5S_all_npoints(space); - break; + case H5S_SEL_ALL: /* Entire extent selected */ + ret_value=H5S_all_npoints(space); + break; - case H5S_SEL_NONE: /* Nothing selected */ - ret_value=0; - break; + case H5S_SEL_NONE: /* Nothing selected */ + ret_value=0; + break; - case H5S_SEL_ERROR: - case H5S_SEL_N: - break; + case H5S_SEL_ERROR: + case H5S_SEL_N: + break; } FUNC_LEAVE (ret_value); @@ -379,22 +379,22 @@ H5S_select_valid (const H5S_t *space) assert(space); switch(space->select.type) { - case H5S_SEL_POINTS: /* Sequence of points selected */ - ret_value=H5S_point_select_valid(space); - break; - - case H5S_SEL_HYPERSLABS: /* Hyperslab selection defined */ - ret_value=H5S_hyper_select_valid(space); - break; - - case H5S_SEL_ALL: /* Entire extent selected */ - case H5S_SEL_NONE: /* Nothing selected */ - ret_value=TRUE; - break; - - case H5S_SEL_ERROR: - case H5S_SEL_N: - break; + case H5S_SEL_POINTS: /* Sequence of points selected */ + ret_value=H5S_point_select_valid(space); + break; + + case H5S_SEL_HYPERSLABS: /* Hyperslab selection defined */ + ret_value=H5S_hyper_select_valid(space); + break; + + case H5S_SEL_ALL: /* Entire extent selected */ + case H5S_SEL_NONE: /* Nothing selected */ + ret_value=TRUE; + break; + + case H5S_SEL_ERROR: + case H5S_SEL_N: + break; } FUNC_LEAVE (ret_value); @@ -430,26 +430,27 @@ H5S_select_serial_size (const H5S_t *space) assert(space); switch(space->select.type) { - case H5S_SEL_POINTS: /* Sequence of points selected */ - ret_value=H5S_point_select_serial_size(space); - break; - - case H5S_SEL_HYPERSLABS: /* Hyperslab selection defined */ - ret_value=H5S_hyper_select_serial_size(space); - break; - - case H5S_SEL_ALL: /* Entire extent selected */ - case H5S_SEL_NONE: /* Nothing selected */ - ret_value=16; /* replace with real function call at some point */ - break; - - case H5S_SEL_ERROR: - case H5S_SEL_N: - break; + case H5S_SEL_POINTS: /* Sequence of points selected */ + ret_value=H5S_point_select_serial_size(space); + break; + + case H5S_SEL_HYPERSLABS: /* Hyperslab selection defined */ + ret_value=H5S_hyper_select_serial_size(space); + break; + + case H5S_SEL_ALL: /* Entire extent selected */ + case H5S_SEL_NONE: /* Nothing selected */ + ret_value=16; /* replace with real function call at some point */ + break; + + case H5S_SEL_ERROR: + case H5S_SEL_N: + break; } FUNC_LEAVE (ret_value); } /* H5S_select_serial_size() */ + /*-------------------------------------------------------------------------- NAME @@ -569,6 +570,7 @@ H5S_select_deserialize (H5S_t *space, const uint8_t *buf) FUNC_LEAVE (ret_value); } /* H5S_select_deserialize() */ + /*-------------------------------------------------------------------------- NAME @@ -599,23 +601,16 @@ H5S_get_select_hyper_nblocks(H5S_t *space) /* Check for a "regular" hyperslab selection */ if(space->select.sel_info.hslab.diminfo != NULL) { - -#ifdef QAK -{ -H5S_hyper_dim_t *diminfo=space->select.sel_info.hslab.diminfo; -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)diminfo[u].start,(int)diminfo[u].stride,(int)diminfo[u].count,(int)diminfo[u].block); -} -#endif /*QAK */ /* Check each dimension */ for(ret_value=1,u=0; u<space->extent.u.simple.rank; u++) ret_value*=space->select.sel_info.hslab.app_diminfo[u].count; } /* end if */ - else - ret_value = (hssize_t)space->select.sel_info.hslab.hyper_lst->count; + else + ret_value = H5S_hyper_span_nblocks(space->select.sel_info.hslab.span_lst); FUNC_LEAVE (ret_value); -} /* H5Sget_select_hyper_nblocks() */ +} /* H5S_get_select_hyper_nblocks() */ + /*-------------------------------------------------------------------------- NAME @@ -655,6 +650,7 @@ H5Sget_select_hyper_nblocks(hid_t spaceid) FUNC_LEAVE (ret_value); } /* H5Sget_select_hyper_nblocks() */ + /*-------------------------------------------------------------------------- NAME @@ -686,6 +682,7 @@ H5S_get_select_elem_npoints(H5S_t *space) FUNC_LEAVE (ret_value); } /* H5Sget_select_elem_npoints() */ + /*-------------------------------------------------------------------------- NAME @@ -725,6 +722,7 @@ H5Sget_select_elem_npoints(hid_t spaceid) FUNC_LEAVE (ret_value); } /* H5Sget_select_elem_npoints() */ + /*-------------------------------------------------------------------------- NAME @@ -732,7 +730,7 @@ H5Sget_select_elem_npoints(hid_t spaceid) PURPOSE Get the list of hyperslab blocks currently selected USAGE - herr_t H5S_get_select_hyper_blocklist(space, hsize_t *buf) + herr_t H5S_get_select_hyper_blocklist(space, startblock, numblocks, buf) H5S_t *space; IN: Dataspace pointer of selection to query hsize_t startblock; IN: Hyperslab block to start with hsize_t numblocks; IN: Number of hyperslab blocks to get @@ -743,7 +741,7 @@ H5Sget_select_elem_npoints(hid_t spaceid) 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 happen first) + 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 @@ -762,9 +760,9 @@ H5S_get_select_hyper_blocklist(H5S_t *space, hsize_t startblock, hsize_t numbloc 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 *node; /* Hyperslab node */ - int rank; /* Dataspace rank */ int i; /* Counter */ int fast_dim; /* Rank of the fastest changing dimension for the dataspace */ int temp_dim; /* Temporary rank holder */ @@ -777,9 +775,6 @@ H5S_get_select_hyper_blocklist(H5S_t *space, hsize_t startblock, hsize_t numbloc assert(space); assert(buf); - /* 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) { /* Set some convienence values */ @@ -859,35 +854,18 @@ H5S_get_select_hyper_blocklist(H5S_t *space, hsize_t startblock, hsize_t numbloc /* Re-compute offset array */ for(i=0; i<ndims; i++) { - temp_off=diminfo[i].start - +diminfo[i].stride*(diminfo[i].count-tmp_count[i]); + temp_off=diminfo[i].start+diminfo[i].stride*(diminfo[i].count-tmp_count[i]); offset[i]=temp_off; } /* end for */ } /* end while */ } /* end if */ else { - /* Get the head of the hyperslab list */ - node=space->select.sel_info.hslab.hyper_lst->head; - - /* Get to the correct first node to give back to the user */ - while(node!=NULL && startblock>0) { - startblock--; - node=node->next; - } /* end while */ - - /* Iterate through the node, copying each hyperslab's information */ - while(node!=NULL && numblocks>0) { - HDmemcpy(buf,node->start,sizeof(hsize_t)*rank); - buf+=rank; - HDmemcpy(buf,node->end,sizeof(hsize_t)*rank); - buf+=rank; - numblocks--; - node=node->next; - } /* end while */ + ret_value=H5S_hyper_span_blocklist(space->select.sel_info.hslab.span_lst,start,end,(hsize_t)0,&startblock,&numblocks,&buf); } /* end else */ FUNC_LEAVE (ret_value); -} /* H5Sget_select_hyper_blocklist() */ +} /* H5S_get_select_hyper_blocklist() */ + /*-------------------------------------------------------------------------- NAME @@ -895,7 +873,7 @@ H5S_get_select_hyper_blocklist(H5S_t *space, hsize_t startblock, hsize_t numbloc PURPOSE Get the list of hyperslab blocks currently selected USAGE - herr_t H5Sget_select_hyper_blocklist(dsid, hsize_t *buf) + herr_t H5Sget_select_hyper_blocklist(dsid, startblock, numblocks, buf) hid_t dsid; IN: Dataspace ID of selection to query hsize_t startblock; IN: Hyperslab block to start with hsize_t numblocks; IN: Number of hyperslab blocks to get @@ -938,10 +916,15 @@ H5Sget_select_hyper_blocklist(hid_t spaceid, hsize_t startblock, hsize_t numbloc if(space->select.type!=H5S_SEL_HYPERSLABS) HRETURN_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a hyperslab selection"); - ret_value = H5S_get_select_hyper_blocklist(space,startblock,numblocks,buf); + /* Go get the correct number of blocks */ + if(numblocks>0) + ret_value = H5S_get_select_hyper_blocklist(space,startblock,numblocks,buf); + else + ret_value=SUCCEED; /* Successfully got 0 blocks... */ FUNC_LEAVE (ret_value); } /* H5Sget_select_hyper_blocklist() */ + /*-------------------------------------------------------------------------- NAME @@ -1006,6 +989,7 @@ H5S_get_select_elem_pointlist(H5S_t *space, hsize_t startpoint, hsize_t numpoint FUNC_LEAVE (ret_value); } /* H5Sget_select_elem_pointlist() */ + /*-------------------------------------------------------------------------- NAME @@ -1059,6 +1043,7 @@ H5Sget_select_elem_pointlist(hid_t spaceid, hsize_t startpoint, hsize_t numpoint FUNC_LEAVE (ret_value); } /* H5Sget_select_elem_pointlist() */ + /*-------------------------------------------------------------------------- NAME @@ -1100,7 +1085,7 @@ H5S_get_select_bounds(H5S_t *space, hsize_t *start, hsize_t *end) assert(start); assert(end); - /* Set all the start and end arrays up */ + /* Set the start and end arrays up */ rank=space->extent.u.simple.rank; for(i=0; i<rank; i++) { start[i]=UINT_MAX; @@ -1128,6 +1113,7 @@ H5S_get_select_bounds(H5S_t *space, hsize_t *start, hsize_t *end) FUNC_LEAVE (ret_value); } /* H5S_get_select_bounds() */ + /*-------------------------------------------------------------------------- NAME @@ -1177,6 +1163,7 @@ H5Sget_select_bounds(hid_t spaceid, hsize_t *start, hsize_t *end) FUNC_LEAVE (ret_value); } /* H5Sget_select_bounds() */ + /*-------------------------------------------------------------------------- NAME |