From 1cd9eb7e0d282aaf5161af220aae00cc7f7e31f9 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Fri, 2 Nov 2001 15:31:35 -0500 Subject: [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) --- src/H5D.c | 63 +- src/H5E.c | 6 +- src/H5Epublic.h | 4 + src/H5FL.c | 2 +- src/H5S.c | 2 +- src/H5Sall.c | 112 +- src/H5Shyper.c | 8103 +++++++++++++++++++++++++++++++++++------------------- src/H5Spkg.h | 83 +- src/H5Spoint.c | 4 +- src/H5Sprivate.h | 30 +- src/H5Spublic.h | 40 +- src/H5Sselect.c | 165 +- 12 files changed, 5626 insertions(+), 2988 deletions(-) diff --git a/src/H5D.c b/src/H5D.c index 619818f..d4aa2ad 100644 --- a/src/H5D.c +++ b/src/H5D.c @@ -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 diff --git a/src/H5E.c b/src/H5E.c index 9f0c01e..19d1645 100644 --- a/src/H5E.c +++ b/src/H5E.c @@ -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 */ diff --git a/src/H5FL.c b/src/H5FL.c index a71a21c..f81690c 100644 --- a/src/H5FL.c +++ b/src/H5FL.c @@ -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) { diff --git a/src/H5S.c b/src/H5S.c index c511276..ffc29ef 100644 --- a/src/H5S.c +++ b/src/H5S.c @@ -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); + + 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 */ + + 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); -/* Declare a free list to manage arrays of H5S_hyper_region_t */ -H5FL_ARR_DEFINE_STATIC(H5S_hyper_region_t,-1); + 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 */ -/* Declare a free list to manage blocks of hyperslab data */ -H5FL_BLK_DEFINE_STATIC(hyper_block); + 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; uextent.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; ibound=%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; ihyp.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=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]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]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]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; uspace->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; ihyp.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; iselect.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; uspace->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; uspace->extent.u.simple.rank; u++) { - printf("%d",(int)io_info->iter->hyp.pos[u]); - if(uspace->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; ispace->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; inelmts>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; uspace->extent.u.simple.rank; u++) { - printf("%d",(int)io_info->iter->hyp.pos[u]); - if(uspace->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_dimdown); + 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; jspace->extent.u.simple.rank; j++) { - printf("%d",(int)io_info->iter->hyp.pos[j]); - if(jspace->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; idown->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; inelmts>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; kspace->extent.u.simple.rank; k++) { - printf("%d",(int)io_info->iter->hyp.pos[k]); - if(kspace->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; i0) { + /* 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; uspace->extent.u.simple.rank; u++) { - printf("%d",(int)io_info->iter->hyp.pos[u]); - if(uspace->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; kspace->extent.u.simple.rank; k++) { - printf("%d",(int)io_info->iter->hyp.pos[k]); - if(kspace->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; ihyp.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]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]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]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_dimdown); + 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; i0) { + /* 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; ihyp.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); - - assert(io_info); - - /* 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"); - - -#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) { - #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; ispace->extent.u.simple.rank) { - - /* perform I/O on data from regions */ - for(i=0; inelmts>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); - } /* end if */ + /* 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); - /* 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"); - } - 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; - } /* end if */ + /* 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 */ - 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"); - } - } /* end else */ + /* Set the offset of the first element iterated on */ + for(i=0, loc_off=0; iselect.offset[i])*slab[i]; - /* Advance the pointer in the buffer */ - io_info->src = ((const uint8_t *)io_info->src) + - region_size*io_info->elmt_size; + /* Range check against number of elements left in selection */ + assert(io_bytes_left<=(iter->hyp.elmt_left*elmt_size)); - /* Increment the number of elements read */ - num_written+=region_size; + /* 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"); - /* Decrement the buffer left */ - io_info->nelmts-=region_size; + /* 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"); - /* 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 */ - - /* Increment the dimension we are working with */ - dim++; - - /* Step through each region in this dimension */ - for(i=0; inelmts>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 */ + /* 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; + + 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_dimdown); + 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; i0) { + /* 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 */ + + /* 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 */ + + /* 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 */ + /* 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 */ + + /* 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 */ + } /* 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_dimdown); + 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, loc_off=0; i0) { + /* 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 */ + + /* 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,227 +2563,458 @@ 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; i0); + 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; iselect.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; inelmts>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; inelmts>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 */ - } /* end else */ + /* Check if we are done */ + if(io_bytes_left>0) { + /* Move to next span in fastest changing dimension */ + curr_span=curr_span->next; - /* Release the temporary buffer */ - H5FL_ARR_FREE(H5S_hyper_region_t,regions); - } /* end if */ + if(curr_span!=NULL) { + /* Move location offset of destination */ + tmp_src+=(curr_span->low-abs_arr[fast_dim])*elmt_size; - FUNC_LEAVE (num_read); -} /* H5S_hyper_mread() */ + /* 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; - -/*------------------------------------------------------------------------- - * Function: H5S_hyper_mread_opt - * - * Purpose: Performs an optimized gather from a memory buffer, based on a - * regular hyperslab (i.e. one which was generated from just one call to - * H5Sselect_hyperslab). - * - * Return: Success: Number of elements copied. - * Failure: 0 - * - * Programmer: Quincey Koziol - * Tuesday, September 12, 2000 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ -static hsize_t -H5S_hyper_mread_opt (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*/) -{ - hsize_t mem_size[H5O_LAYOUT_NDIMS]; /* Size of the source buffer */ - hsize_t slab[H5O_LAYOUT_NDIMS]; /* Hyperslab size */ - hssize_t wrap[H5O_LAYOUT_NDIMS]; /* Bytes to wrap around at the end of a row */ - hsize_t skip[H5O_LAYOUT_NDIMS]; /* Bytes to skip between blocks */ - hssize_t offset[H5O_LAYOUT_NDIMS]; /* Offset on disk */ - hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary block count */ - hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block offset */ - const uint8_t *src=(const uint8_t *)_buf; /* Alias for pointer arithmetic */ - uint8_t *dst=(uint8_t *)_tconv_buf; /* Alias for pointer arithmetic */ - const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ - hssize_t fast_dim_start, /* Local copies of fastest changing dimension info */ - fast_dim_offset; - hsize_t fast_dim_stride, /* Local copies of fastest changing dimension info */ - fast_dim_block, - fast_dim_count; - hsize_t tot_blk_count; /* Total number of blocks left to output */ - size_t act_blk_count; /* Actual number of blocks to output */ - size_t fast_dim_buf_off; /* Local copy of amount to move fastest dimension buffer offset */ - int fast_dim; /* Rank of the fastest changing dimension for the dataspace */ - int temp_dim; /* Temporary rank holder */ - hsize_t acc; /* Accumulator */ - int i; /* Counters */ - unsigned u; /* Counters */ - int ndims; /* Number of dimensions of dataset */ - size_t actual_read; /* The actual number of elements to read in */ - size_t actual_bytes; /* The actual number of bytes to copy */ - size_t io_left; /* The number of elements left in I/O operation */ -#ifndef NO_DUFFS_DEVICE - hsize_t duffs_index; /* Counting index for Duff's device */ -#endif /* NO_DUFFS_DEVICE */ + /* Check if we are still within the span */ + if(abs_arr[fast_dim]<=curr_span->high) { + iter->hyp.span[fast_dim]=curr_span; - FUNC_ENTER (H5S_hyper_mread_opt, 0); + 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: Called!, nelmts=%lu, elmt_size=%d\n",FUNC,(unsigned long)nelmts,(int)elmt_size); -#endif /* QAK */ - /* Check if this is the first element read in from the hyperslab */ - if(mem_iter->hyp.pos[0]==(-1)) { - for(u=0; uextent.u.simple.rank; u++) - mem_iter->hyp.pos[u]=mem_space->select.sel_info.hslab.diminfo[u].start; - } /* end if */ + /* 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; -#ifdef QAK -for(u=0; uextent.u.simple.rank; u++) - printf("%s: mem_file->hyp.pos[%u]=%d\n",FUNC,(unsigned)u,(int)mem_iter->hyp.pos[u]); -#endif /* QAK */ + goto partial_done; /* finished with partial span */ + } /* end if */ + } /* end else */ + } /* end else */ - /* Set the aliases for a few important dimension ranks */ - fast_dim=mem_space->extent.u.simple.rank-1; - ndims=mem_space->extent.u.simple.rank; + /* Adjust iterator pointers */ - /* Set up the size of the memory space */ - HDmemcpy(mem_size, mem_space->extent.u.simple.size,mem_space->extent.u.simple.rank*sizeof(hsize_t)); - mem_size[mem_space->extent.u.simple.rank]=elmt_size; + if(curr_span==NULL) { +/* Same as code in main loop */ + /* Start at the next fastest dim */ + curr_dim=fast_dim-1; - /* initialize row sizes for each dimension */ - for(i=(ndims-1),acc=1; i>=0; i--) { - slab[i]=acc*elmt_size; + /* 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_dimdown); + 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; i0) { + /* 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_dimdown); + 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; ihyp.elmt_left-=nelem; + + /* Success! */ + ret_value=nelem; + +#ifdef LATER +done: +#endif /* LATER */ + FUNC_LEAVE (ret_value); +} /* end H5S_hyper_mread() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_mread_opt + * + * Purpose: Performs an optimized gather from a memory buffer, based on a + * regular hyperslab (i.e. one which was generated from just one call to + * H5Sselect_hyperslab). + * + * Return: Success: Number of elements copied. + * Failure: 0 + * + * Programmer: Quincey Koziol + * Tuesday, September 12, 2000 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static hsize_t +H5S_hyper_mread_opt (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*/) +{ + hsize_t mem_size[H5O_LAYOUT_NDIMS]; /* Size of the source buffer */ + hsize_t slab[H5O_LAYOUT_NDIMS]; /* Hyperslab size */ + hssize_t wrap[H5O_LAYOUT_NDIMS]; /* Bytes to wrap around at the end of a row */ + hsize_t skip[H5O_LAYOUT_NDIMS]; /* Bytes to skip between blocks */ + hssize_t offset[H5O_LAYOUT_NDIMS]; /* Offset on disk */ + hsize_t tmp_count[H5O_LAYOUT_NDIMS]; /* Temporary block count */ + hsize_t tmp_block[H5O_LAYOUT_NDIMS]; /* Temporary block offset */ + const uint8_t *src=(const uint8_t *)_buf; /* Alias for pointer arithmetic */ + uint8_t *dst=(uint8_t *)_tconv_buf; /* Alias for pointer arithmetic */ + const H5S_hyper_dim_t *tdiminfo; /* Temporary pointer to diminfo information */ + hssize_t fast_dim_start, /* Local copies of fastest changing dimension info */ + fast_dim_offset; + hsize_t fast_dim_stride, /* Local copies of fastest changing dimension info */ + fast_dim_block, + fast_dim_count; + hsize_t tot_blk_count; /* Total number of blocks left to output */ + size_t act_blk_count; /* Actual number of blocks to output */ + size_t fast_dim_buf_off; /* Local copy of amount to move fastest dimension buffer offset */ + int fast_dim; /* Rank of the fastest changing dimension for the dataspace */ + int temp_dim; /* Temporary rank holder */ + hsize_t acc; /* Accumulator */ + int i; /* Counters */ + unsigned u; /* Counters */ + int ndims; /* Number of dimensions of dataset */ + size_t actual_read; /* The actual number of elements to read in */ + size_t actual_bytes; /* The actual number of bytes to copy */ + size_t io_left; /* The number of elements left in I/O operation */ +#ifndef NO_DUFFS_DEVICE + hsize_t duffs_index; /* Counting index for Duff's device */ +#endif /* NO_DUFFS_DEVICE */ + + FUNC_ENTER (H5S_hyper_mread_opt, 0); + +#ifdef QAK +printf("%s: Called!, nelmts=%lu, elmt_size=%d\n",FUNC,(unsigned long)nelmts,(int)elmt_size); +#endif /* QAK */ + /* Check if this is the first element read in from the hyperslab */ + if(mem_iter->hyp.pos[0]==(-1)) { + for(u=0; uextent.u.simple.rank; u++) + mem_iter->hyp.pos[u]=mem_space->select.sel_info.hslab.diminfo[u].start; + } /* end if */ + +#ifdef QAK +for(u=0; uextent.u.simple.rank; u++) + printf("%s: mem_file->hyp.pos[%u]=%d\n",FUNC,(unsigned)u,(int)mem_iter->hyp.pos[u]); +#endif /* QAK */ + + /* Set the aliases for a few important dimension ranks */ + fast_dim=mem_space->extent.u.simple.rank-1; + ndims=mem_space->extent.u.simple.rank; + + /* Set up the size of the memory space */ + HDmemcpy(mem_size, mem_space->extent.u.simple.size,mem_space->extent.u.simple.rank*sizeof(hsize_t)); + mem_size[mem_space->extent.u.simple.rank]=elmt_size; + + /* initialize row sizes for each dimension */ + for(i=(ndims-1),acc=1; i>=0; i--) { + slab[i]=acc*elmt_size; acc*=mem_size[i]; } /* end for */ #ifdef QAK @@ -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,150 +3439,382 @@ 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); + + /* 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 */ -#ifdef QAK - printf("%s: check 2.0, rank=%d\n", - FUNC,(int)io_info->space->extent.u.simple.rank); - for(i=0; ispace->extent.u.simple.rank) { + /* Set the offset of the first element iterated on */ + for(i=0, tmp_dst=dst; iselect.offset[i])*slab[i]; - /* Set up hyperslab I/O parameters which apply to all regions */ + /* Range check against number of elements left in selection */ + assert(io_bytes_left<=(iter->hyp.elmt_left*elmt_size)); - /* 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; + /* Take care of any partial spans leftover from previous I/Os */ + if(abs_arr[fast_dim]!=curr_span->low) { -#ifdef QAK - printf("%s: check 3.0\n",FUNC); -#endif /* QAK */ - /* perform I/O on data from regions */ - for(i=0; inelmts>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; + /* 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 */ + /* 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; -#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; inelmts>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++) { + HDmemcpy(tmp_dst,src,(size_t)span_size); - /* Set the correct position we are working on */ - io_info->iter->hyp.pos[dim]=j; + /* Increment offset in destination */ + src+=span_size; - /* Go get the regions in the next lower dimension */ - num_write+=H5S_hyper_mwrite(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_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_dimdown); + 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; i0) { + /* 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_dimdown); + 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; ihyp.elmt_left-=nelem; + + /* Success! */ + ret_value=nelem; + +#ifdef LATER +done: +#endif /* LATER */ + FUNC_LEAVE (ret_value); +} /* end H5S_hyper_mwrite() */ + + +/*------------------------------------------------------------------------- + * Function: H5S_hyper_mwrite_opt + * + * Purpose: Performs an optimized scatter to a memory buffer, based on a * regular hyperslab (i.e. one which was generated from just one call to * H5Sselect_hyperslab). * @@ -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->boundbound) - 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; ustart[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 */ + + /* Change the nelem & pstride values into bytes */ + span->nelem *= elmt_size; + span->pstride *= elmt_size; - /* Prepend on list of hyperslabs for this selection */ - slab->next=*head; - *head=slab; + /* 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); - /* Prepend on list of hyperslabs for this selection */ - node->next=*head; - *head=node; + /* 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"); + + /* 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; + + /* 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 */ - /* 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); + /* 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); - - /* 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; uextent.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 */ + 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; - 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; + FUNC_ENTER (H5S_hyper_copy_span_helper, NULL); - /* Don't loose place in list of nodes to add.. */ - piece_lst=piece_lst->next; + assert(spans); -#ifdef QAK - printf("%s: check 3.0\n",FUNC); -#endif /* QAK */ - /* Set boundary on new node */ - for(u=0,elem_count=1; uextent.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 */ + /* 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; - /* 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; + /* 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; -#ifdef QAK - printf("%s: check 4.0\n",FUNC); - { - unsigned v; - - for(u=0; uextent.u.simple.rank; u++) { - for(v=0; vselect.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; uextent.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 */ + /* Copy the pstride */ + new_span->pstride=span->pstride; - /* 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; + /* 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 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; uextent.u.simple.rank; u++) { - for(v=0; vselect.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 */ + /* Update the previous (new) span */ + prev_span=new_span; - /* Sort each dimension's array of bounds, now that they are all in the array */ - for(u=0; uextent.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* 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; ustart[u]); - if(uend={",FUNC); - for(u=0; uend[u]); - if(unext=%p\n",region,region->next); - printf("\tstart={",FUNC); - for(u=0; ustart[u]); - if(uend[u]); - if(unext; - } /* 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; ustart[u]); - if(uend[u]); - if(unext; - } /* 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; ustart[u]); - if(uend={",FUNC); - for(u=0; uend[u]); - if(uend[u]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; ustart[u]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]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); + /* 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 */ + else { + /* Check for one span being NULL */ + if(span1==NULL || span2==NULL) { + ret_value=FALSE; + break; } /* 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; + /* 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 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 */ - } /* 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); - } /* 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; - } /* 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; vstart[v]); - if(vend[v]); - if(vnext; - } /* 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; vstart[v]); - if(vend[v]); - if(vnext; - } /* 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 */ - - FUNC_ENTER (H5S_hyper_release, FAIL); + H5S_hyper_span_t *span, *next_span; + herr_t ret_value=SUCCEED; - /* Check args */ - assert (space && H5S_SEL_HYPERSLABS==space->select.type); -#ifdef QAK - printf("%s: check 1.0\n",FUNC); -#endif /* QAK */ + FUNC_ENTER (H5S_hyper_free_span_info, FAIL); - /* Reset the number of points selected */ - space->select.num_elem=0; + assert(span_info); - /* 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 */ + /* Decrement the span tree's reference count */ + span_info->count--; - /* 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; uextent.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 */ + /* Free the span tree if the reference count drops to zero */ + if(span_info->count==0) { - /* 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; uextent.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; uextent.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(rankhead; + 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; uextent.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,63 +5076,98 @@ 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; uextent.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 */ - - curr=curr->next; - } /* end while */ - } /* end while */ + /* 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 */ FUNC_LEAVE (ret_value); } /* end H5S_hyper_select_valid() */ + /*-------------------------------------------------------------------------- NAME - H5S_hyper_select_serial_size + H5S_hyper_span_nblocks PURPOSE - Determine the number of bytes needed to store the serialized hyperslab - selection information. + Count the number of blocks in a span tree USAGE - hssize_t H5S_hyper_select_serial_size(space) - H5S_t *space; IN: Dataspace pointer to query + hssize_t H5S_hyper_span_nblocks(spans) + const H5S_hyper_span_info_t *spans; IN: Hyperslan span tree to count elements of RETURNS - The number of bytes required on success, negative on an error. + Number of blocks in span tree on success; negative on failure DESCRIPTION - Determines the number of bytes required to serialize the current hyperslab - selection information for storage on disk. + 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_select_serial_size (const H5S_t *space) +H5S_hyper_span_nblocks (H5S_hyper_span_info_t *spans) { - 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 */ - - FUNC_ENTER (H5S_hyper_select_serial_size, FAIL); + H5S_hyper_span_t *span; /* Hyperslab span */ + hssize_t ret_value=FAIL; - assert(space); + FUNC_ENTER (H5S_hyper_span_nblocks, FAIL); - /* Basic number of bytes required to serialize point selection: - * + + + - * + + <# of blocks (4 bytes)> = 24 bytes + /* 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 else */ + +#ifdef LATER +done: +#endif /* LATER */ + FUNC_LEAVE (ret_value); +} /* H5S_hyper_span_nblocks() */ + + +/*-------------------------------------------------------------------------- + NAME + H5S_hyper_select_serial_size + PURPOSE + Determine the number of bytes needed to store the serialized hyperslab + selection information. + USAGE + hssize_t H5S_hyper_select_serial_size(space) + H5S_t *space; IN: Dataspace pointer to query + RETURNS + The number of bytes required on success, negative on an error. + DESCRIPTION + Determines the number of bytes required to serialize the current hyperslab + selection information for storage on disk. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +hssize_t +H5S_hyper_select_serial_size (const H5S_t *space) +{ + unsigned u; /* Counter */ + hssize_t block_count; /* block counter for regular hyperslabs */ + hssize_t ret_value=FAIL; /* return value */ + + FUNC_ENTER (H5S_hyper_select_serial_size, FAIL); + + assert(space); + + /* Basic number of bytes required to serialize point selection: + * + + + + * + + <# of blocks (4 bytes)> = 24 bytes */ ret_value=24; @@ -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(rankhead; + 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; ulow); + + /* Encode previous ending points */ + for(u=0; uhigh); + } /* 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; iselect.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; uextent.u.simple.rank; u++) - UINT32ENCODE(buf, (uint32_t)curr->start[u]); - - /* Encode ending point */ - for(u=0; uextent.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 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(rank0); + 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; ulow, sizeof(hsize_t)); + (*buf)++; + + /* Copy previous ending points */ + for(u=0; uhigh, 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(rankhead; + 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; iselect.sel_info.hslab.hyper_lst->head; - while(node!=NULL) { - for(i=0; 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,211 +5799,2535 @@ 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; uend[u]-node->start[u])+1)!=(hssize_t)space->extent.u.simple.size[u]) { - ret_value=FALSE; - break; - } /* end if */ - } /* end for */ + 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() */ -/*------------------------------------------------------------------------- - * Function: H5S_generate_hyperlab - * - * Purpose: Generate hyperslab information from H5S_select_hyperslab() - * - * Return: Non-negative on success/Negative on failure - * - * Programmer: Quincey Koziol (split from HS_select_hyperslab()). - * Tuesday, September 12, 2000 - * - * Modifications: - * - *------------------------------------------------------------------------- - */ +/*-------------------------------------------------------------------------- + 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_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*/]) +H5S_hyper_select_iterate_helper(H5S_hyper_iter_info_t *iter_info) { - 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 */ - herr_t ret_value=FAIL; /* return value */ - - FUNC_ENTER (H5S_generate_hyperslab, FAIL); + 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(block); - assert(stride); - assert(space); - assert(start); - assert(count); - assert(op>H5S_SELECT_NOOP && opextent.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 */ - } /* end if */ + 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 */ -#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"))); -#endif /* QAK */ + /* Set the offset of the first element iterated on */ + for(i=0, loc_off=0; ihyp.span[i]->low; -#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"); - } /* end if */ + /* 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; uop))(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 */ + /* 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_dimdown); + 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; iextent.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; u0 && 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; uselect.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_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->highlow) { +#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->lowlow && (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->highhigh) { + /* 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->lowlow && 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->highhigh) { + /* 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->highlow) { +#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->lowlow && (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->highhigh) { + /* 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->lowlow && 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->highhigh) { + /* 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; ulow=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 + * + * Purpose: Generate hyperslab information from H5S_select_hyperslab() + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol (split from HS_select_hyperslab()). + * Tuesday, September 12, 2000 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_generate_hyperslab (H5S_t *space, H5S_seloper_t op, + const 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; /* 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(space); + assert(op>H5S_SELECT_NOOP && opextent.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"); #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); +printf("%s: new_spans=%p\n",FUNC,new_spans); #endif /* QAK */ - /* Generate list of blocks to add to selection */ - if(contig) { /* Check for trivial case */ + + /* 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; + + 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; + + /* Reset the number of items in selection */ + space->select.num_elem=0; + + /* 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"); + + /* 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; + + 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; + + /* 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; + + /* 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 4.1\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; + +done: + 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 + * Wednesday, January 10, 2001 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +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 *_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_select_hyperslab, FAIL); + + /* Check args */ + assert(space); + assert(start); + assert(count); + assert(op>H5S_SELECT_NOOP && opextent.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; + } + + /* Fill in the correct block values */ + if(block==NULL) { + hssize_t fill=1; + + /* 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; + } + + /* 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(op==H5S_SELECT_SET) { + /* + * Check for overlapping hyperslab blocks in new selection. + */ + for(u=0; uextent.u.simple.rank; u++) { + if(count[u]>1 && stride[u]extent.u.simple.rank,0))==NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "can't allocate per-dimension vector"); + for(u=0; uextent.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"); + + /* Optimize the hyperslab selection to detect contiguously selected block/stride information */ + /* Modify the stride, block & count for contiguous hyperslab selections */ + for(u=0; uextent.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_ALL: + /* break out now, 'or'ing with an all selection leaves the all selection */ + HGOTO_DONE(SUCCEED); - /* 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; uextent.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; uextent.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; uextent.u.simple.rank; u++) { - printf("%d",(int)slab[u]); - if(u<(space->extent.u.simple.rank-1)) - printf(", "); - else - printf("}\n"); + 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; + + /* 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"); + + /* Set selection type */ + space->select.type=H5S_SEL_HYPERSLABS; + + 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 + H5Sselect_hyperslab + PURPOSE + Specify a hyperslab to combine with the current hyperslab selection + USAGE + herr_t H5Sselect_hyperslab(dsid, op, start, stride, count, block) + hid_t dsid; IN: Dataspace ID of selection to modify + H5S_seloper_t op; IN: Operation to perform on current selection + const 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 + Non-negative on success/Negative on failure + DESCRIPTION + Combines a hyperslab selection with the current selection for a dataspace. + If the current selection is not a hyperslab, it is freed and the hyperslab + parameters passed in are combined with the H5S_SEL_ALL hyperslab (ie. a + selection composing the entire current extent). If STRIDE or BLOCK is + NULL, they are assumed to be set to all '1'. + GLOBAL VARIABLES + COMMENTS, BUGS, ASSUMPTIONS + EXAMPLES + REVISION LOG +--------------------------------------------------------------------------*/ +herr_t +H5Sselect_hyperslab(hid_t space_id, H5S_seloper_t op, const 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); + + /* 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"); } -#endif /* QAK */ + if(start==NULL || count==NULL) + HRETURN_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "hyperslab not specified"); - /* 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; uextent.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; vextent.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 */ + if(!(op>H5S_SELECT_NOOP && opH5S_SELECT_NOOP && opselect.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_generate_hyperlab + * + * Purpose: Generate hyperslab information from H5S_select_hyperslab() + * + * Return: Non-negative on success/Negative on failure + * + * Programmer: Quincey Koziol (split from HS_select_hyperslab()). + * Tuesday, September 12, 2000 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5S_generate_hyperslab (H5S_t *space, H5S_seloper_t op, + const 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 && opextent.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() */ @@ -5646,8 +8339,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 +8348,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 +8373,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 +8384,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 +8397,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; uextent.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; uextent.u.simple.rank; u++) { - if(count[u]>1 && stride[u]1 && stride[u]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; uextent.u.simple.rank; u++) { diminfo[u].start = start[u]; diminfo[u].stride = stride[u]; @@ -5744,9 +8422,8 @@ for(u=0; uextent.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,42 +8445,15 @@ for(u=0; uextent.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; uextent.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 */ - HGOTO_DONE(SUCCEED); - 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; uextent.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,27 +8461,19 @@ for(u=0; uextent.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; ret_value=SUCCEED; @@ -5863,417 +8505,334 @@ 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 && opH5S_SELECT_NOOP && opH5S_SELECT_NOOP && opspace->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; imem_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 */ - - /* Set the next position to start at */ - iter_info->iter->hyp.pos[dim+1]=(-1); - } else { /* recurse on each region to next dimension down */ + H5S_t *new_space=NULL; /* New dataspace generated */ + H5S_t *ret_value=NULL; /* return value */ - /* Increment the dimension we are working with */ - dim++; + FUNC_ENTER (H5S_combine_select, NULL); - /* Step through each region in this dimension */ - for(i=0; iiter->hyp.pos[dim]!=j) - iter_info->iter->hyp.pos[dim+1]=(-1); + /* Check args */ + assert(space1); + assert(space2); + assert(op>H5S_SELECT_NOOP && opiter->hyp.pos[dim]=j; + /* 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"); - /* 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 */ + /* Set the return value */ + ret_value=new_space; - /* Release the temporary buffer */ - H5FL_ARR_FREE(H5S_hyper_region_t,regions); - } /* end if */ +done: + if(ret_value==NULL && new_space!=NULL) + H5S_close(new_space); - FUNC_LEAVE (user_ret); -} /* H5S_hyper_select_iterate_mem() */ + FUNC_LEAVE (ret_value); +} /* end H5S_combine_select() */ /*-------------------------------------------------------------------------- NAME - H5S_hyper_select_iterate_mem_opt + H5Scombine_select PURPOSE - Iterate over the data points in a regular hyperslab selection, calling a - user's function for each element. + Combine two hyperslab selections with an operation, returning a dataspace + with the resulting 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. + 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 - 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. + Dataspace ID 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. + 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 --------------------------------------------------------------------------*/ -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_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id) { - 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; u0 && 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 */ + H5S_t *space1; /* First Dataspace */ + H5S_t *space2; /* Second Dataspace */ + H5S_t *new_space = NULL; /* New Dataspace */ + hid_t ret_value = FAIL; - /* Reset the sequence count */ - tmp_block[fast_dim]=diminfo[fast_dim].block; + FUNC_ENTER (H5Scombine_select, FAIL); + H5TRACE3("e","iSsi",space1_id,op,space2_id); - /* 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); + /* 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 && opextent.u.simple.rank!=space2->extent.u.simple.rank) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "dataspaces not same rank"); - /* Check for getting out of iterator, we're done in the 1-D case */ - if(ndims==1) - goto done; /* Yes, an evil goto.. :-) -QAK */ + /* 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"); - /* 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; + /* 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"); - /* 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]--; + /* Atomize */ + if ((ret_value=H5I_register (H5I_DATASPACE, new_space))<0) + HGOTO_ERROR (H5E_ATOM, H5E_CANTREGISTER, FAIL, "unable to register dataspace atom"); - /* Check if we are still in the sequence */ - if(tmp_block[temp_dim]>0) - break; +done: + if (ret_value<0 && new_space) + H5S_close(new_space); - /* Reset the sequence count in this dimension */ - tmp_block[temp_dim]=diminfo[temp_dim].block; + FUNC_LEAVE (ret_value); +} /* end H5Scombine_select() */ - /* Decrement the block count */ - tmp_count[temp_dim]--; + +/*------------------------------------------------------------------------- + * 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 */ - /* Check if we have more blocks left */ - if(tmp_count[temp_dim]>0) - break; + FUNC_ENTER (H5S_select_select, FAIL); - /* Check for getting out of iterator */ - if(temp_dim==0) - goto done; /* Yes, an evil goto.. :-) -QAK */ + /* Check args */ + assert(space1); + assert(space2); + assert(op>H5S_SELECT_NOOP && opselect.sel_info.hslab.span_lst))) + HGOTO_ERROR (H5E_DATASPACE, H5E_CANTINIT, FAIL, "unable to copy data 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 */ + /* 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"); - /* Re-compute buffer location & offset array */ - for(loc=buf,u=0; uselect.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 && opextent.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 * Thursday, September 28, 2000 @@ -16,7 +16,7 @@ #ifndef _H5Spkg_H #define _H5Spkg_H -#include "H5Sprivate.h" +#include /* * 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; uextent.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; uextent.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; iselect.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