From 0c6229a68d8a8e6148f8a975c5392f62c4b3a35e Mon Sep 17 00:00:00 2001 From: Albert Cheng Date: Mon, 3 May 2004 18:34:42 -0500 Subject: [svn-r8479] Purpose: New Feature Description: Add the data transform function, H5Pset_transform(). Platforms tested: "h5committested". Copper was down. Ran parallel tests in sol instead. Misc. update: --- MANIFEST | 4 +- src/H5D.c | 234 +++++++- src/H5Dio.c | 94 +++- src/H5Dprivate.h | 10 + src/H5Pdxpl.c | 45 ++ src/H5Ppublic.h | 2 + src/H5Zprivate.h | 47 ++ src/H5Ztrans.c | 1626 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Makefile.in | 2 +- test/Makefile.in | 7 +- test/dtransform.c | 110 ++++ 11 files changed, 2159 insertions(+), 22 deletions(-) create mode 100644 src/H5Ztrans.c create mode 100644 test/dtransform.c diff --git a/MANIFEST b/MANIFEST index 5ee300b..bd4a61b 100644 --- a/MANIFEST +++ b/MANIFEST @@ -778,8 +778,7 @@ ./src/H5Dprivate.h ./src/H5Dpublic.h ./src/H5Dpkg.h -./src/H5DZ.c -./src/H5DZtrans.c +./src/H5Ztrans.c ./src/H5E.c ./src/H5Edefin.h ./src/H5Einit.h @@ -963,6 +962,7 @@ ./test/deflate.h5 ./test/dsets.c ./test/dtypes.c +./test/dtransform.c ./test/enum.c ./test/extend.c ./test/external.c diff --git a/src/H5D.c b/src/H5D.c index 58aa1a3..aae16c6 100644 --- a/src/H5D.c +++ b/src/H5D.c @@ -28,6 +28,7 @@ #include "H5MMprivate.h" /* Memory management */ #include "H5Sprivate.h" /* Dataspaces */ #include "H5Vprivate.h" /* Vectors and arrays */ +#include "H5Zprivate.h" /*#define H5D_DEBUG*/ @@ -52,6 +53,14 @@ static herr_t H5D_extend(H5D_t *dataset, const hsize_t *size, hid_t dxpl_id); static herr_t H5D_set_extent(H5D_t *dataset, const hsize_t *size, hid_t dxpl_id); static herr_t H5D_close(H5D_t *dataset); +static herr_t H5D_xfer_xform_set(hid_t prop_id, const char* name, size_t size, void* value); +static herr_t H5D_xfer_xform_del(hid_t prop_id, const char* name, size_t size, void* value); +static herr_t H5D_xfer_xform_copy(const char* name, size_t size, void* value); +static herr_t H5D_xfer_xform_close(const char* name, size_t size, void* value); + + + + /* Internal data structure for computing variable-length dataset's total size */ typedef struct { hid_t dataset_id; /* ID of the dataset we are working on */ @@ -128,6 +137,7 @@ H5D_init_interface(void) { /* Dataset Transfer property class variables. In sequence, they are, * - Transfer Property list class to modify + * - Default value for maximum data transform buffer size * - Default value for maximum temp buffer size * - Default value for type conversion buffer * - Default value for background buffer @@ -148,6 +158,7 @@ H5D_init_interface(void) * - Default value for datatype conversion callback */ H5P_genclass_t *xfer_pclass; + void* def_xfer_xform = H5D_XFER_XFORM_DEF; size_t def_max_temp_buf = H5D_XFER_MAX_TEMP_BUF_DEF; void *def_tconv_buf = H5D_XFER_TCONV_BUF_DEF; void *def_bkgr_buf = H5D_XFER_BKGR_BUF_DEF; @@ -189,7 +200,7 @@ H5D_init_interface(void) H5P_genplist_t *def_dcpl; /* Default Dataset Creation Property list */ size_t nprops; /* Number of properties */ herr_t ret_value = SUCCEED; /* Return value */ - + FUNC_ENTER_NOAPI_NOINIT(H5D_init_interface) /* Initialize the atom group for the dataset IDs */ @@ -210,6 +221,10 @@ H5D_init_interface(void) /* Assume that if there are properties in the class, they are the default ones */ if(nprops==0) { + /* Register the data transform property */ + if(H5P_register(xfer_pclass,H5D_XFER_XFORM,H5D_XFER_XFORM_SIZE,&def_xfer_xform,NULL,H5D_XFER_XFORM_SET,NULL,H5D_XFER_XFORM_DEL,H5D_XFER_XFORM_COPY,NULL,H5D_XFER_XFORM_CLOSE)<0) + HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") + /* Register the max. temp buffer size property */ if(H5P_register(xfer_pclass,H5D_XFER_MAX_TEMP_BUF_NAME,H5D_XFER_MAX_TEMP_BUF_SIZE,&def_max_temp_buf,NULL,NULL,NULL,NULL,NULL,NULL,NULL)<0) HGOTO_ERROR(H5E_PLIST, H5E_CANTINSERT, FAIL, "can't insert property into class") @@ -439,6 +454,219 @@ H5D_term_interface(void) FUNC_LEAVE_NOAPI(n) } + +/*------------------------------------------------------------------------- + * Function: H5D_xfer_xform_set + * + * Purpose: Callback for setting a data transform property. This generates + * the parse tree for the data transform, as well as saving the transform + * locally. + * + * Return: Success: SUCCEED, Failure: FAIL + * + * Programmer: Leon Arber, larber@uiuc.edu + * + * Date: April 9, 2004 + * + * Comments: private, calls H5Z_xform_parse and H5Z_xform_reduce_tree + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_xfer_xform_set(hid_t prop_id, const char UNUSED *name, size_t UNUSED size, void* value) +{ + H5P_genplist_t *new_plist; + void* parse_root; + H5Z_data_xform* data_xform_prop; + int exp_size; + herr_t ret_value=SUCCEED; + + exp_size = strlen(*(char**)value) + 1; + data_xform_prop = (H5Z_data_xform*) HDmalloc(sizeof(H5Z_data_xform)); + + FUNC_ENTER_NOAPI(H5D_xfer_xform_set, FAIL) + + /* Verify property list ID */ + if (NULL == (new_plist = H5I_object(prop_id))) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a data transform property list") + + if (value == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "cannot parse a null expression") + else + { +#ifdef H5Z_XFORM_DEBUG + printf("Adding a new dataset transfer prop. Parsing a new tree from %s\n",*(char**) value); +#endif + + /* copy the user's string into the property */ + data_xform_prop->xform_exp = HDmalloc(exp_size); + strncpy(data_xform_prop->xform_exp, *(char**)value, exp_size); + + + /* we generate the parse tree right here and store a poitner to its root in the property. */ + parse_root = H5Z_xform_parse(*(H5Z_node**)value); + H5Z_xform_reduce_tree((H5Z_node*)parse_root); + if(parse_root) + { + data_xform_prop->parse_root = parse_root; + HDmemcpy(value, &data_xform_prop, sizeof(void*)); + } + else + { + /* if we couldn't parse the user's string, we're not going to store it */ + data_xform_prop->parse_root = NULL; + free(data_xform_prop->xform_exp); + data_xform_prop->xform_exp = NULL; + free(data_xform_prop); + *(H5Z_data_xform**)value = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error parsing data transform expression") + } + } +done: + FUNC_LEAVE_NOAPI(ret_value) +} + + +/*------------------------------------------------------------------------- + * Function: H5D_xfer_xform_del + * + * Purpose: Frees memory allocated by H5D_xfer_xform_set + * + * Return: Success: SUCCEED, Failure: FAIL + * + * Programmer: Leon Arber larber@uiuc.edu + * + * + * Date: April 9, 2004 + * + * Comments: Private function, calls private H5Z_xform_destroy_parse_tree + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_xfer_xform_del(hid_t UNUSED prop_id, const char UNUSED *name, size_t UNUSED size, void *value) +{ +#ifdef H5Z_XFORM_DEBUG + fprintf(stderr, "Freeing memory b/c of delete\n"); +#endif + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5D_xfer_xform_del, FAIL) + + assert(value); + + + if( *(H5Z_data_xform**)value != NULL) + { + H5Z_xform_destroy_parse_tree(((*((H5Z_data_xform**)value)))->parse_root); + HDfree(((*((H5Z_data_xform**)value)))->xform_exp); + HDfree(*(H5Z_data_xform**)value); + *(H5Z_data_xform**)value = NULL; + } + +done: + FUNC_LEAVE_NOAPI(ret_value) + +} + +/*------------------------------------------------------------------------- + * Function: H5D_xfer_xform_copy + * + * Purpose: Creates a copy of the user's data transform string and its + * associated parse tree. + * + * Return: Success: SUCCEED, Failure: FAIL + * + * Programmer: Leon Arber larber@uiuc.edu + * + * + * Date: April 9, 2004 + * + * Comments: Public function, calls private H5Z_xform_copy_tree + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_xfer_xform_copy(const char UNUSED *name, size_t UNUSED size, void *value) +{ + H5Z_node* new_tree; + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5D_xfer_xform_copy, FAIL) + + /* this will involved generating a new parse tree by copying every single node in the old one */ + H5Z_data_xform* data_xform_prop; + data_xform_prop = (H5Z_data_xform*) HDmalloc(sizeof(H5Z_data_xform)); + + data_xform_prop->xform_exp = (char*) HDmalloc(strlen( ((*(H5Z_data_xform**)value))->xform_exp) + 1); + strcpy(data_xform_prop->xform_exp, ((*(H5Z_data_xform**)value))->xform_exp); + if( (new_tree = (H5Z_node*)H5Z_xform_copy_tree( ((*(H5Z_data_xform**)value))->parse_root)) == NULL) + HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "error copying the parse tree") + else + data_xform_prop->parse_root = new_tree; + + *(H5Z_data_xform**)value = data_xform_prop; + +done: +FUNC_LEAVE_NOAPI(ret_value) + + +} + + +/*------------------------------------------------------------------------- + * Function: H5D_xfer_xform_close + * + * Purpose: Frees memory allocated by H5D_xfer_xform_set + * + * Return: Success: SUCCEED, Failure: FAIL + * + * Programmer: Leon Arber larber@uiuc.edu + * + * Date: April 9, 2004 + * + * Comments: private function, calls H5Z_xform_destroy_parse_tree + * Identical to H5D_xfer_xform_del + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +static herr_t +H5D_xfer_xform_close(const char UNUSED *name, size_t UNUSED size, void *value) +{ +#ifdef H5Z_XFORM_DEBUG + fprintf(stderr, "Freeing memory b/c of close\n"); +#endif + herr_t ret_value = SUCCEED; + + FUNC_ENTER_NOAPI(H5D_xfer_xform_close, FAIL) + + assert(value); + + if( *(H5Z_data_xform**)value != NULL) + { + H5Z_xform_destroy_parse_tree(((*((H5Z_data_xform**)value)))->parse_root); + HDfree(((*((H5Z_data_xform**)value)))->xform_exp); + HDfree(*(H5Z_data_xform**)value); + *(H5Z_data_xform**)value = NULL; + } + + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + + + + + /*------------------------------------------------------------------------- * Function: H5D_crt_copy @@ -3560,7 +3788,7 @@ done: * Purpose: Modifies the dimensions of a dataset, based on H5Dextend. * Can change to a lower dimension. * - * Return: Success: 0, Failure: -1 + * Return: Success: SUCCEED, Failure: FAIL * * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu * Robb Matzke @@ -3603,7 +3831,7 @@ done: * Purpose: Based in H5D_extend, allows change to a lower dimension, * calls H5S_set_extent and H5F_istore_prune_by_extent instead * - * Return: Success: 0, Failure: -1 + * Return: Success: SUCCEED, Failure: FAIL * * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu * Robb Matzke diff --git a/src/H5Dio.c b/src/H5Dio.c index 227d0d7..48492b2 100644 --- a/src/H5Dio.c +++ b/src/H5Dio.c @@ -27,6 +27,8 @@ #include "H5Sprivate.h" /* Dataspace functions */ #include "H5TBprivate.h" /* Threaded, balanced, binary trees (TBBTs) */ #include "H5Vprivate.h" /* Vector and array functions */ +#include "H5Tpublic.h" +#include "H5Zprivate.h" /*#define H5D_DEBUG*/ @@ -129,6 +131,7 @@ H5FL_BLK_DEFINE(type_conv); /* Declare a free list to manage the H5D_chunk_info_t struct */ H5FL_DEFINE_STATIC(H5D_chunk_info_t); + /*-------------------------------------------------------------------------- NAME @@ -306,7 +309,10 @@ H5D_get_dxpl_cache_real(hid_t dxpl_id, H5D_dxpl_cache_t *cache) /* Get the dataset transfer property list */ if (NULL == (dx_plist = H5I_object(dxpl_id))) HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "not a dataset transfer property list") - + + /* Get the data transform property */ + H5P_get(dx_plist, H5D_XFER_XFORM, &cache->data_xform_prop); + /* Get maximum temporary buffer size */ if(H5P_get(dx_plist, H5D_XFER_MAX_TEMP_BUF_NAME, &cache->max_temp_buf)<0) HGOTO_ERROR (H5E_PLIST, H5E_CANTGET, FAIL, "Can't retrieve maximum temporary buffer size") @@ -1030,6 +1036,8 @@ done: * Modifications: * QAK - 2003/04/17 * Hacked on it a lot. :-) + * Leon Arber: 4/20/04 + * Added support for data transforms. * *------------------------------------------------------------------------- */ @@ -1062,13 +1070,19 @@ H5D_contig_read(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, hsize_t n, smine_nelmts; /*elements per strip */ herr_t ret_value = SUCCEED; /*return value */ + hid_t array_type; + FUNC_ENTER_NOAPI_NOINIT(H5D_contig_read) - + + /* Inits for data transforms, if needed */ + array_type = H5Z_xform_find_type(mem_type); + /* * If there is no type conversion then read directly into the * application's buffer. This saves at least one mem-to-mem copy. */ - if (H5T_path_noop(tpath)) { + + if ( (dxpl_cache->data_xform_prop == NULL) && H5T_path_noop(tpath)) { #ifdef H5S_DEBUG H5_timer_begin(&timer); #endif @@ -1090,10 +1104,10 @@ H5D_contig_read(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, if (status<0) { HGOTO_ERROR(H5E_DATASET, H5E_READERROR, FAIL, "optimized read failed") } else - /* direct xfer accomplished successfully */ + /* direct xfer accomplished successfully */ HGOTO_DONE(SUCCEED) } /* end if */ - + /* * This is the general case(type conversion). */ @@ -1205,6 +1219,15 @@ H5D_contig_read(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, if (H5T_convert(tpath, src_id, dst_id, smine_nelmts, 0, 0, tconv_buf, bkg_buf, dxpl_id)<0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "data type conversion failed") + + /* Added by LA to do data transforms */ + + if(dxpl_cache->data_xform_prop) + H5Z_xform_eval(dxpl_cache->data_xform_prop->parse_root, tconv_buf, smine_nelmts, array_type); + + /* end of LA additions */ + + /* * Scatter the data into memory. */ @@ -1213,6 +1236,8 @@ H5D_contig_read(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, #endif status = H5S_select_mscat(tconv_buf, mem_space, &mem_iter, smine_nelmts, dxpl_cache, buf/*out*/); + + #ifdef H5S_DEBUG H5_timer_end(&(sconv->stats[1].scat_timer), &timer); sconv->stats[1].scat_nbytes += smine_nelmts * dst_type_size; @@ -1260,6 +1285,8 @@ done: * Modifications: * QAK - 2003/04/17 * Hacked on it a lot. :-) + * Leon Arber: 4/20/04 + * Added support for data transforms. * *------------------------------------------------------------------------- */ @@ -1290,14 +1317,21 @@ H5D_contig_write(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5 hsize_t smine_start; /*strip mine start loc */ hsize_t n, smine_nelmts; /*elements per strip */ herr_t ret_value = SUCCEED; /*return value */ - - FUNC_ENTER_NOAPI_NOINIT(H5D_contig_write) + hid_t array_type; + + FUNC_ENTER_NOAPI_NOINIT(H5D_contig_write) + + /*TODO: This should be the type of the destination file...not the memory source. Where do we get this? */ + /* Inits for the data transform, if needed */ + array_type = H5Z_xform_find_type(mem_type); + /* * If there is no type conversion then write directly from the * application's buffer. This saves at least one mem-to-mem copy. */ - if (H5T_path_noop(tpath)) { + + if ( (dxpl_cache->data_xform_prop == NULL) && H5T_path_noop(tpath)) { #ifdef H5S_DEBUG H5_timer_begin(&timer); #endif @@ -1305,10 +1339,11 @@ H5D_contig_write(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5 status = (sconv->write)(dataset->ent.file, &(dataset->layout), &dataset->dcpl_cache, (H5D_storage_t *)&(dataset->efl), (size_t)nelmts, H5T_get_size(dataset->type), file_space, mem_space, dxpl_cache, dxpl_id, buf); + #ifdef H5S_DEBUG - H5_timer_end(&(sconv->stats[0].write_timer), &timer); - sconv->stats[0].write_nbytes += nelmts * H5T_get_size(mem_type); - sconv->stats[0].write_ncalls++; + H5_timer_end(&(sconv->stats[0].write_timer), &timer); + sconv->stats[0].write_nbytes += nelmts * H5T_get_size(mem_type); + sconv->stats[0].write_ncalls++; #endif /* Check return value from optimized write */ @@ -1437,6 +1472,11 @@ H5D_contig_write(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5 #ifdef H5S_DEBUG H5_timer_begin(&timer); #endif + + /* LA additions for data transforms */ + if(dxpl_cache->data_xform_prop) + H5Z_xform_eval(dxpl_cache->data_xform_prop->parse_root, tconv_buf, smine_nelmts, array_type); + /* End of LA modifications */ status = H5S_select_fscat(dataset->ent.file, &(dataset->layout), &dataset->dcpl_cache, (H5D_storage_t *)&(dataset->efl), file_space, &file_iter, smine_nelmts, dxpl_cache, dxpl_id, tconv_buf); @@ -1451,6 +1491,7 @@ H5D_contig_write(hsize_t nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5 } /* end for */ done: + /* Release selection iterators */ if(file_iter_init) { if(H5S_select_iter_release(&file_iter)<0) @@ -1487,7 +1528,10 @@ done: * Modifications: * QAK - 2003/04/17 * Hacked on it a lot. :-) + * Leon Arber: 4/20/04 + * Added support for data transforms. * + *------------------------------------------------------------------------- */ /* ARGSUSED */ @@ -1524,18 +1568,21 @@ UNUSED uint8_t *bkg_buf = NULL; /*background buffer */ H5D_storage_t store; /*union of EFL and chunk pointer in file space */ herr_t ret_value = SUCCEED; /*return value */ - + hid_t array_type; + FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_read) /* Map elements between file and memory for each chunk*/ if(H5D_create_chunk_map(dataset, mem_type, file_space, mem_space, &fm)<0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "can't build chunk mapping") + array_type = H5Z_xform_find_type(mem_type); + /* * If there is no type conversion then read directly into the * application's buffer. This saves at least one mem-to-mem copy. */ - if (H5T_path_noop(tpath)) { + if ( (dxpl_cache->data_xform_prop == NULL) && H5T_path_noop(tpath)) { #ifdef H5S_DEBUG H5_timer_begin(&timer); #endif @@ -1705,6 +1752,13 @@ UNUSED tconv_buf, bkg_buf, dxpl_id)<0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "data type conversion failed") + /* LA additions for data transforms */ + if(dxpl_cache->data_xform_prop) + H5Z_xform_eval(dxpl_cache->data_xform_prop->parse_root, tconv_buf, smine_nelmts, array_type); + + + + /* * Scatter the data into memory. */ @@ -1784,6 +1838,8 @@ done: * Modifications: * QAK - 2003/04/17 * Hacked on it a lot. :-) + * Leon Arber: 4/20/04 + * Added support for data transforms. * *------------------------------------------------------------------------- */ @@ -1821,9 +1877,12 @@ nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space, uint8_t *bkg_buf = NULL; /*background buffer */ H5D_storage_t store; /*union of EFL and chunk pointer in file space */ herr_t ret_value = SUCCEED; /*return value */ + hid_t array_type; FUNC_ENTER_NOAPI_NOINIT(H5D_chunk_write) + array_type = H5Z_xform_find_type(mem_type); + #ifdef QAK { int mpi_rank; @@ -1850,7 +1909,7 @@ nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space, * If there is no type conversion then write directly from the * application's buffer. This saves at least one mem-to-mem copy. */ - if (H5T_path_noop(tpath)) { + if ((dxpl_cache->data_xform_prop == NULL) && H5T_path_noop(tpath)) { #ifdef H5S_DEBUG H5_timer_begin(&timer); #endif @@ -2043,6 +2102,13 @@ nelmts, H5D_t *dataset, const H5T_t *mem_type, const H5S_t *mem_space, tconv_buf, bkg_buf, dxpl_id)<0) HGOTO_ERROR(H5E_DATASET, H5E_CANTINIT, FAIL, "data type conversion failed") + /* LA additions for data transforms */ + if(dxpl_cache->data_xform_prop) + H5Z_xform_eval(dxpl_cache->data_xform_prop->parse_root, tconv_buf, smine_nelmts, array_type); + + + + /* * Scatter the data out to the file. */ diff --git a/src/H5Dprivate.h b/src/H5Dprivate.h index e52f51c..5489659 100644 --- a/src/H5Dprivate.h +++ b/src/H5Dprivate.h @@ -74,6 +74,15 @@ #define H5D_CRT_DATA_PIPELINE_CMP H5D_crt_data_pipeline_cmp /* ======== Data transfer properties ======== */ +/* Definitions for data transform property */ +#define H5D_XFER_XFORM "data_transform" +#define H5D_XFER_XFORM_SIZE sizeof(void *) +#define H5D_XFER_XFORM_DEF NULL +#define H5D_XFER_XFORM_SET H5D_xfer_xform_set +#define H5D_XFER_XFORM_DEL H5D_xfer_xform_del +#define H5D_XFER_XFORM_COPY H5D_xfer_xform_copy +#define H5D_XFER_XFORM_CLOSE H5D_xfer_xform_close + /* Definitions for maximum temp buffer size property */ #define H5D_XFER_MAX_TEMP_BUF_NAME "max_temp_buf" #define H5D_XFER_MAX_TEMP_BUF_SIZE sizeof(size_t) @@ -171,6 +180,7 @@ typedef struct H5D_dxpl_cache_t { #endif /*H5_HAVE_PARALLEL*/ H5Z_EDC_t err_detect; /* Error detection info (H5D_XFER_EDC_NAME) */ H5Z_cb_t filter_cb; /* Filter callback function (H5D_XFER_FILTER_CB_NAME) */ + H5Z_data_xform* data_xform_prop; /* Data transform prop (H5D_XFER_XFORM) */ } H5D_dxpl_cache_t; /* Typedef for cached dataset creation property list information */ diff --git a/src/H5Pdxpl.c b/src/H5Pdxpl.c index 04f4783..36bf77e 100644 --- a/src/H5Pdxpl.c +++ b/src/H5Pdxpl.c @@ -31,6 +31,51 @@ static int interface_initialize_g = 0; /* Static function prototypes */ +/*------------------------------------------------------------------------- + * Function: H5Pset_data_transform + * + * Purpose: + * Sets data transform expression. + * + * + * Return: Returns a non-negative value if successful; otherwise returns a negative value. + * + * + * Programmer: Leon Arber + * Monday, March 07, 2004 + * + * Modifications: + * + *------------------------------------------------------------------------- + */ +herr_t H5Pset_data_transform(hid_t plist_id, char* expression) +{ + H5P_genplist_t *plist; /* Property list pointer */ + herr_t ret_value=SUCCEED; /* return value */ + + FUNC_ENTER_API(H5Pset_data_transform, FAIL); + + /* H5TRACE4("e","izxx",plist_id,expression); */ + + /* Check arguments */ + if (expression == NULL) + HGOTO_ERROR (H5E_ARGS, H5E_BADVALUE, FAIL, "expression cannot be NULL"); + + /* Get the plist structure */ + if(NULL == (plist = H5P_object_verify(plist_id,H5P_DATASET_XFER))) + HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, FAIL, "can't find object for ID"); + + /* Update property list */ + if(H5P_set(plist, H5D_XFER_XFORM, &expression)<0) + HGOTO_ERROR (H5E_PLIST, H5E_CANTSET, FAIL, "Error setting data transform expression"); + +done: + FUNC_LEAVE_API(ret_value); +} + + + + /*------------------------------------------------------------------------- * Function: H5Pset_buffer diff --git a/src/H5Ppublic.h b/src/H5Ppublic.h index cae9337..8368c84 100644 --- a/src/H5Ppublic.h +++ b/src/H5Ppublic.h @@ -197,6 +197,7 @@ H5_DLL herr_t H5Pset_layout(hid_t plist_id, H5D_layout_t layout); H5_DLL H5D_layout_t H5Pget_layout(hid_t plist_id); H5_DLL herr_t H5Pset_chunk(hid_t plist_id, int ndims, const hsize_t dim[]); H5_DLL int H5Pget_chunk(hid_t plist_id, int max_ndims, hsize_t dim[]/*out*/); +H5_DLL herr_t H5Pset_data_transform(hid_t plist_id, char* expression); H5_DLL herr_t H5Pset_external(hid_t plist_id, const char *name, off_t offset, hsize_t size); H5_DLL int H5Pget_external_count(hid_t plist_id); @@ -217,6 +218,7 @@ H5_DLL herr_t H5Pset_family_offset(hid_t fapl_id, hsize_t offset); H5_DLL herr_t H5Pget_family_offset(hid_t fapl_id, hsize_t *offset); H5_DLL herr_t H5Pset_multi_type(hid_t fapl_id, H5FD_mem_t type); H5_DLL herr_t H5Pget_multi_type(hid_t fapl_id, H5FD_mem_t *type); + H5_DLL herr_t H5Pset_buffer(hid_t plist_id, size_t size, void *tconv, void *bkg); H5_DLL size_t H5Pget_buffer(hid_t plist_id, void **tconv/*out*/, diff --git a/src/H5Zprivate.h b/src/H5Zprivate.h index d87f735..48620be 100644 --- a/src/H5Zprivate.h +++ b/src/H5Zprivate.h @@ -19,6 +19,10 @@ #ifndef _H5Zprivate_H #define _H5Zprivate_H +#include "H5private.h" /* Generic Functions */ +#include "H5Tprivate.h" +#include "H5Eprivate.h" +#include "H5Iprivate.h" #include "H5Zpublic.h" /* Structure to store information about each filter's parameters */ @@ -30,6 +34,41 @@ typedef struct { unsigned *cd_values; /*client data values */ } H5Z_filter_info_t; + +/* Token types */ +typedef enum { + ERROR, + H5Z_INTEGER, /* this represents an integer type in the data transform expression */ + H5Z_FLOAT, /* this represents a floating point type in the data transform expression */ + SYMBOL, + PLUS, + MINUS, + MULT, + DIVIDE, + LPAREN, + RPAREN, + END +} H5Z_token_type; + +typedef union { + char *sym_val; + long int_val; + double float_val; +} H5Z_num_val; + + +typedef struct H5Z_node { + struct H5Z_node *lchild; + struct H5Z_node *rchild; + H5Z_token_type type; + H5Z_num_val value; +} H5Z_node; + +typedef struct { + char* xform_exp; + H5Z_node* parse_root; +} H5Z_data_xform; + /* Special parameters for szip compression */ /* [These are aliases for the similar definitions in szlib.h, which we can't * include directly due to the duplication of various symbols with the zlib.h @@ -60,5 +99,13 @@ H5_DLL H5Z_filter_info_t *H5Z_filter_info(const struct H5O_pline_t *pline, H5_DLL htri_t H5Z_all_filters_avail(const struct H5O_pline_t *pline); H5_DLL herr_t H5Z_delete(struct H5O_pline_t *pline, H5Z_filter_t filter); +/* Data Transform Functions */ +H5_DLL void H5Z_xform_destroy_parse_tree(H5Z_node *tree); +H5_DLL void H5Z_xform_eval(H5Z_node *tree, void* array, hsize_t array_size, hid_t array_type); +H5_DLL void* H5Z_xform_parse(const char *expression); +H5_DLL hid_t H5Z_xform_find_type(H5T_t* type); +H5_DLL void H5Z_xform_reduce_tree(H5Z_node* tree); +H5_DLL void* H5Z_xform_copy_tree(H5Z_node* tree); + #endif diff --git a/src/H5Ztrans.c b/src/H5Ztrans.c new file mode 100644 index 0000000..3aa4595 --- /dev/null +++ b/src/H5Ztrans.c @@ -0,0 +1,1626 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by the Board of Trustees of the University of Illinois. * + * All rights reserved. * + * * + + * terms governing use, modification, and redistribution, is contained in * + * the files COPYING and Copyright.html. COPYING can be found at the root * + * of the source code distribution tree; Copyright.html can be found at the * + * root level of an installed copy of the electronic HDF5 document set and * + * is linked from the top-level documents page. It can also be found at * + * http://hdf.ncsa.uiuc.edu/HDF5/doc/Copyright.html. If you do not have * + * access to either file, you may request a copy from hdfhelp@ncsa.uiuc.edu. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5Zprivate.h" + +typedef struct result { + H5Z_token_type type; + H5Z_num_val value; + H5T_class_t ar_type; +} H5Z_result; + + +/* The token */ +typedef struct { + const char *tok_expr; /* Holds the original expression */ + + /* Current token values */ + H5Z_token_type tok_type; /* The type of the current token */ + const char *tok_begin; /* The beginning of the current token */ + const char *tok_end; /* The end of the current token */ + + /* Previous token values */ + H5Z_token_type tok_last_type; /* The type of the last token */ + const char *tok_last_begin; /* The beginning of the last token */ + const char *tok_last_end; /* The end of the last token */ +} H5Z_token; + + + + +/* Interface initialization */ +static int interface_initialize_g = 0; +#define INTERFACE_INIT NULL + +static H5Z_token *H5Z_get_token(H5Z_token *current); +static H5Z_node *H5Z_parse_expression(H5Z_token *current); +static H5Z_node *H5Z_parse_term(H5Z_token *current); +static H5Z_node *H5Z_parse_factor(H5Z_token *current); +static H5Z_node *H5Z_new_node(H5Z_token_type type); +static void H5Z_do_op(H5Z_node* tree); +static H5Z_result H5Z_eval_full(H5Z_node *tree, void* array, hsize_t array_size, hid_t array_type); + + +#ifdef H5Z_XFORM_DEBUG +static void H5Z_XFORM_DEBUG(H5Z_node *tree); +static void H5Z_print(H5Z_node *tree, FILE *stream); +#endif /* H5Z_XFORM_DEBUG */ + + +/* + * Programmer: Bill Wendling + * 25. August 2003 + */ + +/* + * This is the context-free grammar for our expressions: + * + * expr := term | term '+ term | term '-' term + * term := factor | factor '*' factor | factor '/' factor + * factor := number | + * symbol | + * '-' factor | // unary minus + * '+' factor | // unary plus + * '(' expr ')' + * symbol := [a-zA-Z][a-zA-Z0-9]* + * number := H5Z_INTEGER | FLOAT + * // H5Z_INTEGER is a C long int + * // FLOAT is a C double + */ +/*------------------------------------------------------------------------- + * Function: H5Z_unget_token + * Purpose: Rollback the H5Z_token to the previous H5Z_token retrieved. There + * should only need to be one level of rollback necessary + * for our grammar. + * Return: Always succeeds. + * Programmer: Bill Wendling + * 26. August 2003 + * Modifications: + * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs +* + *------------------------------------------------------------------------- + */ +static void +H5Z_unget_token(H5Z_token *current) +{ + /* check args */ + assert(current); + + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5Z_unget_token) + + current->tok_type = current->tok_last_type; + current->tok_begin = current->tok_last_begin; + current->tok_end = current->tok_last_end; + + FUNC_LEAVE_NOAPI_VOID + + +} + +/*------------------------------------------------------------------------- + * Function: H5Z_get_token + * Purpose: Determine what the next valid H5Z_token is in the expression + * string. The current position within the H5Z_token string is + * kept internal to the H5Z_token and handled by this and the + * unget_H5Z_token function. + * Return: Succeess: The passed in H5Z_token with a valid tok_type + * field. + * NULLure: The passed in H5Z_token but with the tok_type + * field set to ERROR. + * Programmer: Bill Wendling + * 26. August 2003 + * Modifications: + * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs + *------------------------------------------------------------------------- + */ +static H5Z_token * +H5Z_get_token(H5Z_token *current) +{ + + void* ret_value=current; + + FUNC_ENTER_NOAPI(H5Z_get_token, NULL) + + + /* check args */ + assert(current); + + /* Save the last position for possible ungets */ + current->tok_last_type = current->tok_type; + current->tok_last_begin = current->tok_begin; + current->tok_last_end = current->tok_end; + + current->tok_begin = current->tok_end; + + while (current->tok_begin[0] != '\0') { + if (isspace(current->tok_begin[0])) { + /* ignore whitespace */ + } else if (isdigit(current->tok_begin[0]) || + current->tok_begin[0] == '.') { + current->tok_end = current->tok_begin; + + /* + * H5Z_INTEGER := digit-sequence + * digit-sequence := digit | digit digit-sequence + * digit := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 + */ + if (current->tok_end[0] != '.') { + /* is number */ + current->tok_type = H5Z_INTEGER; + + while (isdigit(current->tok_end[0])) + ++current->tok_end; + } + + /* + * float := digit-sequence exponent | + * dotted-digits exponent? + * dotted-digits := digit-sequence '.' digit-sequence? | + * '.' digit-sequence + * exponent := [Ee] [-+]? digit-sequence + */ + if (current->tok_end[0] == '.' || + current->tok_end[0] == 'e' || + current->tok_end[0] == 'E') { + current->tok_type = H5Z_FLOAT; + + if (current->tok_end[0] == '.') + do { + ++current->tok_end; + } while (isdigit(current->tok_end[0])); + + if (current->tok_end[0] == 'e' || + current->tok_end[0] == 'E') { + ++current->tok_end; + + if (current->tok_end[0] == '-' || + current->tok_end[0] == '+') + ++current->tok_end; + + if (!isdigit(current->tok_end[0])) { + current->tok_type = ERROR; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current, "Invalidly formatted floating point number") + } + + while (isdigit(current->tok_end[0])) + ++current->tok_end; + } + + /* Check that this is a properly formatted numerical value */ + if (isalpha(current->tok_end[0]) || current->tok_end[0] == '.') { + current->tok_type = ERROR; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current, "Invalidly formatted floating point number") + } + } + + break; + } else if (isalpha(current->tok_begin[0])) { + /* is symbol */ + current->tok_type = SYMBOL; + current->tok_end = current->tok_begin; + + while (isalnum(current->tok_end[0])) + ++current->tok_end; + + break; + } else { + /* should be +, -, *, /, (, or ) */ + switch (current->tok_begin[0]) { + case '+': current->tok_type = PLUS; break; + case '-': current->tok_type = MINUS; break; + case '*': current->tok_type = MULT; break; + case '/': current->tok_type = DIVIDE; break; + case '(': current->tok_type = LPAREN; break; + case ')': current->tok_type = RPAREN; break; + default: + current->tok_type = ERROR; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current, "Unknown H5Z_token in data transform expression ") + } + + current->tok_end = current->tok_begin + 1; + break; + } + + ++current->tok_begin; + } + + if (current->tok_begin[0] == '\0') + current->tok_type = END; + + HGOTO_DONE(current); + +done: + FUNC_LEAVE_NOAPI(ret_value) + +} + +/*------------------------------------------------------------------------- + * Function: H5Z_xform_destroy_parse_tree + * Purpose: Recursively destroys the expression tree. + * Return: Nothing + * Programmer: Bill Wendling + * 25. August 2003 + * Modifications: + * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs + * + *------------------------------------------------------------------------- + */ +void +H5Z_xform_destroy_parse_tree(H5Z_node *tree) +{ + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5Z_xform_destroy_parse_tree) + + if (!tree) + return; + + if (tree->type == SYMBOL) + HDfree(tree->value.sym_val); + + H5Z_xform_destroy_parse_tree(tree->lchild); + H5Z_xform_destroy_parse_tree(tree->rchild); + HDfree(tree); + tree = NULL; + + FUNC_LEAVE_NOAPI_VOID +} + + +/*------------------------------------------------------------------------- + * Function: H5Z_parse + * Purpose: Entry function for parsing the expression string. + * Return: Success: Valid H5Z_node ptr to an expression tree. + * NULLure: NULL + * Programmer: Bill Wendling + * 26. August 2003 + * Modifications: + * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs + * + *------------------------------------------------------------------------- + */ +void * +H5Z_xform_parse(const char *expression) +{ + H5Z_token tok; + void* ret_value; + + FUNC_ENTER_NOAPI(H5Z_xform_parse, NULL) + + if (!expression) + return NULL; + + /* Set up the initial H5Z_token for parsing */ + tok.tok_expr = tok.tok_begin = tok.tok_end = expression; + + ret_value = (void*)H5Z_parse_expression(&tok); + +done: + FUNC_LEAVE_NOAPI(ret_value) +} + +/*------------------------------------------------------------------------- + * Function: H5Z_parse_expression + * Purpose: Beginning of the recursive descent parser to parse the + * expression. An expression is: + * + * expr := term | term '+' term | term '-' term + * + * Return: Success: Valid H5Z_node ptr to expression tree + * NULLure: NULL + * Programmer: Bill Wendling + * 26. August 2003 + * Modifications: + * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs +* + *------------------------------------------------------------------------- + */ +static H5Z_node * +H5Z_parse_expression(H5Z_token *current) +{ + void* ret_value=NULL; + + FUNC_ENTER_NOAPI(H5Z_parse_expression, NULL) + + H5Z_node *expr = H5Z_parse_term(current); + + for (;;) { + H5Z_node *new_node; + new_node = NULL; + + current = H5Z_get_token(current); + + switch (current->tok_type) { + case PLUS: + new_node = H5Z_new_node(PLUS); + + if (!new_node) { + H5Z_xform_destroy_parse_tree(expr); + expr = NULL; + HGOTO_DONE(expr) + } + + new_node->lchild = expr; + new_node->rchild = H5Z_parse_term(current); + + if (!new_node->rchild) { + H5Z_xform_destroy_parse_tree(new_node); + expr = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") + } + + expr = new_node; + break; + case MINUS: + new_node = H5Z_new_node(MINUS); + + if (!new_node) { + H5Z_xform_destroy_parse_tree(expr); + expr = NULL; + HGOTO_DONE(expr) + } + + new_node->lchild = expr; + new_node->rchild = H5Z_parse_term(current); + + if (!new_node->rchild) { + H5Z_xform_destroy_parse_tree(new_node); + expr = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") + } + + expr = new_node; + break; + case RPAREN: + H5Z_unget_token(current); + HGOTO_DONE(expr) + case END: + HGOTO_DONE(expr) + default: + H5Z_xform_destroy_parse_tree(expr); + expr = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") + } + } + +done: + FUNC_LEAVE_NOAPI(expr) + + +} + +/*------------------------------------------------------------------------- + * Function: H5Z_parse_term + * Purpose: Parses a term in our expression language. A term is: + * + * term := factor | factor '*' factor | factor '/' factor + * + * Return: Success: Valid H5Z_node ptr to expression tree + * NULLure: NULL + * Programmer: Bill Wendling + * 26. August 2003 + * Modifications: + * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs +* + *------------------------------------------------------------------------- + */ +static H5Z_node * +H5Z_parse_term(H5Z_token *current) +{ + H5Z_node *term = NULL; + void* ret_value=NULL; + + FUNC_ENTER_NOAPI(H5Z_parse_term, NULL); + term = H5Z_parse_factor(current); + + for (;;) { + H5Z_node *new_node; + new_node = NULL; + + current = H5Z_get_token(current); + + switch (current->tok_type) { + case MULT: + new_node = H5Z_new_node(MULT); + + if (!new_node) { + H5Z_xform_destroy_parse_tree(term); + term = NULL; + HGOTO_DONE(term) + } + + new_node->lchild = term; + new_node->rchild = H5Z_parse_factor(current); + + if (!new_node->rchild) { + H5Z_xform_destroy_parse_tree(term); + term = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") + } + + term = new_node; + break; + case DIVIDE: + new_node = H5Z_new_node(DIVIDE); + + if (!new_node) { + H5Z_xform_destroy_parse_tree(term); + term = NULL; + HGOTO_DONE(term) + } + + new_node->lchild = term; + new_node->rchild = H5Z_parse_factor(current); + term = new_node; + + if (!new_node->rchild) { + H5Z_xform_destroy_parse_tree(term); + term = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") + } + + break; + case RPAREN: + H5Z_unget_token(current); + HGOTO_DONE(term) + case END: + HGOTO_DONE(term) + default: + H5Z_unget_token(current); + HGOTO_DONE(term) + } + } + +done: + FUNC_LEAVE_NOAPI(term) + +} + +/*------------------------------------------------------------------------- + * Function: H5Z_parse_factor + * Purpose: Parses a factor in our expression language. A factor is: + * + * factor := number | // C long or double + * symbol | // C identifier + * '-' factor | // unary minus + * '+' factor | // unary plus + * '(' expr ')' + * + * Return: Success: Valid H5Z_node ptr to expression tree + * NULLure: NULL + * Programmer: Bill Wendling + * 26. August 2003 + * Modifications: + * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs +* + *------------------------------------------------------------------------- + */ +static H5Z_node * +H5Z_parse_factor(H5Z_token *current) +{ + H5Z_node *factor=NULL; + H5Z_node *new_node=NULL; + void* ret_value=NULL; + + FUNC_ENTER_NOAPI(H5Z_parse_factor, NULL); + + current = H5Z_get_token(current); + + switch (current->tok_type) { + case H5Z_INTEGER: + factor = H5Z_new_node(H5Z_INTEGER); + + if (!factor) + HGOTO_DONE(factor) + + sscanf(current->tok_begin, "%ld", &factor->value.int_val); + break; + case H5Z_FLOAT: + factor = H5Z_new_node(H5Z_FLOAT); + + if (!factor) + HGOTO_DONE(factor) + + sscanf(current->tok_begin, "%lf", &factor->value.float_val); + break; + case SYMBOL: + factor = H5Z_new_node(SYMBOL); + + if (!factor) + HGOTO_DONE(factor) + + factor->value.sym_val = HDcalloc(current->tok_end - current->tok_begin + 1, 1); + HDstrncpy(factor->value.sym_val, current->tok_begin, + current->tok_end - current->tok_begin); + break; + case LPAREN: + factor = H5Z_parse_expression(current); + + if (!factor) + HGOTO_DONE(factor) + + current = H5Z_get_token(current); + + if (current->tok_type != RPAREN) { + H5Z_xform_destroy_parse_tree(factor); + factor = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Syntax error in data transform expression") + } + + break; + case RPAREN: + /* We shouldn't see a ) right now */ + H5Z_xform_destroy_parse_tree(factor); + factor = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Syntax error: unexpected ')' ") + case PLUS: + /* unary + */ + new_node = H5Z_parse_factor(current); + + if (new_node) { + if (new_node->type != H5Z_INTEGER && new_node->type != H5Z_FLOAT && + new_node->type != SYMBOL) { + H5Z_xform_destroy_parse_tree(new_node); + H5Z_xform_destroy_parse_tree(factor); + factor=NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") + } + + factor = new_node; + new_node = H5Z_new_node(PLUS); + + if (!new_node) { + H5Z_xform_destroy_parse_tree(factor); + factor = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") + } + + new_node->rchild = factor; + factor = new_node; + } else { + H5Z_xform_destroy_parse_tree(factor); + factor = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") + } + + break; + case MINUS: + /* unary - */ + new_node = H5Z_parse_factor(current); + + if (new_node) { + if (new_node->type != H5Z_INTEGER && new_node->type != H5Z_FLOAT && + new_node->type != SYMBOL) { + H5Z_xform_destroy_parse_tree(new_node); + H5Z_xform_destroy_parse_tree(factor); + factor = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") + } + + factor = new_node; + new_node = H5Z_new_node(MINUS); + + if (!new_node) { + H5Z_xform_destroy_parse_tree(factor); + factor = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") + } + + new_node->rchild = factor; + factor = new_node; + } else { + H5Z_xform_destroy_parse_tree(factor); + factor = NULL; + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression") + } + + break; + case END: + HGOTO_DONE(factor) + } + +done: + + FUNC_LEAVE_NOAPI(factor); +} + +/*------------------------------------------------------------------------- + * Function: H5Z_new_node + * Purpose: Create and initilize a new H5Z_node structure. + * Return: Success: Valid H5Z_node ptr + * NULLure: NULL + * Programmer: Bill Wendling + * 26. August 2003 + * Modifications: + * Leon Arber: Added FUNC_ENTER / FUNC_LEAVE pairs +* + *------------------------------------------------------------------------- + */ +static H5Z_node * +H5Z_new_node(H5Z_token_type type) +{ + H5Z_node* ret_value; + H5Z_node* new_node; + + FUNC_ENTER_NOAPI(H5Z_new_node, NULL) + + new_node = HDcalloc(1, sizeof(H5Z_node)); + + if (new_node) + new_node->type = type; + else + assert(new_node); + +done: + + FUNC_LEAVE_NOAPI(new_node); +} + +#ifdef H5Z_XFORM_DEBUG +/*------------------------------------------------------------------------- + * Function: H5Z_XFORM_DEBUG + * Purpose: Print out the expression in a nice format which displays + * the precedences explicitly with parentheses. + * Return: Nothing + * Programmer: Bill Wendling + * 26. August 2003 + * Modifications: + * + *------------------------------------------------------------------------- + */ + +static void +H5Z_XFORM_DEBUG(H5Z_node *tree) +{ + int i; + printf("Expression: "); + H5Z_result res; + res = H5Z_eval(tree); + + if(res.type == H5Z_INTEGER) + printf("H5Z_result is: %d",res.value.int_val ); + else if(res.type == H5Z_FLOAT) + printf("H5Z_result is: %f",res.value.float_val ); + else + { + printf("H5Z_result is "); + for(i=0; i<5; i++) + printf("%d ", array[i]); + } + printf("\n"); +} + +/*------------------------------------------------------------------------- + * Function: H5Z_print + * Purpose: Print out the expression in a nice format which displays + * the precedences explicitly with parentheses. + * Return: Nothing + * Programmer: Bill Wendling + * 26. August 2003 + * Modifications: + * + *------------------------------------------------------------------------- + */ +static void +H5Z_print(H5Z_node *tree, FILE *stream) +{ + /* check args */ + assert(stream); + + if (!tree) + return; + + if (tree->type == H5Z_INTEGER) { + fprintf(stream, "%ld", tree->value.int_val); + } else if (tree->type == H5Z_FLOAT) { + fprintf(stream, "%f", tree->value.float_val); + } else if (tree->type == SYMBOL) { + fprintf(stream, "%s", tree->value.sym_val); + } else { + fprintf(stream, "("); + H5Z_print(tree->lchild, stream); + + switch (tree->type) { + case PLUS: fprintf(stream, "+"); break; + case MINUS: fprintf(stream, "-"); break; + case MULT: fprintf(stream, "*"); break; + case DIVIDE: fprintf(stream, "/"); break; + default: fprintf(stream, "Invalid expression tree\n"); + return; + } + + H5Z_print(tree->rchild, stream); + fprintf(stream, ")"); + } +} +#endif /* H5Z_XFORM_DEBUG */ + + +void H5Z_xform_eval(H5Z_node *tree, void* array, hsize_t array_size, hid_t array_type) +{ + unsigned int i; + int n; + float f; + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5Z_xform_eval) + + + if( tree->type == H5Z_INTEGER) + { + if(array_type == H5T_NATIVE_INT) + { + n = tree->value.int_val; + for(i=0; ivalue.int_val; + for(i=0; itype == H5Z_FLOAT) + { + for(i=0; ivalue.float_val; + for(i=0; ivalue.float_val; + for(i=0; itype == H5Z_INTEGER) + { + res.type = H5Z_INTEGER; + res.value = tree->value; + HGOTO_DONE(res) + } + else if (tree->type == H5Z_FLOAT) + { + res.type = H5Z_FLOAT; + res.value = tree->value; + HGOTO_DONE(res) + } + else if (tree->type == SYMBOL) + { + res.type = SYMBOL; + res.value = tree->value; + res.ar_type = array_type; + HGOTO_DONE(res) + } + else + { + resl = H5Z_eval_full(tree->lchild, array, array_size, array_type); + resr = H5Z_eval_full(tree->rchild, array, array_size, array_type); + switch (tree->type) + { + case PLUS: + if( (resl.type == SYMBOL) && (resr.type==H5Z_INTEGER)) + { + res.type = SYMBOL; + for(i=0; itype == H5Z_INTEGER) + { + if ((ret_value = (H5Z_node*) HDmalloc(sizeof(H5Z_node))) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") + else + { + ret_value -> type = H5Z_INTEGER; + ret_value ->value.int_val = tree->value.int_val; + } + } + else if (tree->type == H5Z_FLOAT) + { + if ((ret_value = (H5Z_node*) HDmalloc(sizeof(H5Z_node))) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") + else + { + ret_value -> type = H5Z_FLOAT; + ret_value ->value.float_val = tree->value.float_val; + } + } + else if(tree->type == SYMBOL) + { + if ((ret_value = (H5Z_node*) HDmalloc(sizeof(H5Z_node))) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") + else + { + ret_value -> type = SYMBOL; + if ((ret_value->value.sym_val = (char*) HDmalloc(strlen(tree->value.sym_val)+1)) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") + else + strcpy(ret_value ->value.sym_val, tree->value.sym_val); + } + } + else if(tree->type == MULT) + { + if ((ret_value = (H5Z_node*) HDmalloc(sizeof(H5Z_node))) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") + else + { + ret_value->type = MULT; + ret_value->lchild = (H5Z_node*) H5Z_xform_copy_tree(tree->lchild); + ret_value->rchild = (H5Z_node*) H5Z_xform_copy_tree(tree->rchild); + } + } + else if(tree->type == PLUS) + { + if ((ret_value = (H5Z_node*) HDmalloc(sizeof(H5Z_node))) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") + else + { + ret_value->type = PLUS; + ret_value->lchild = (H5Z_node*) H5Z_xform_copy_tree(tree->lchild); + ret_value->rchild = (H5Z_node*) H5Z_xform_copy_tree(tree->rchild); + } + } + else if(tree->type == MINUS) + { + if ((ret_value = (H5Z_node*) HDmalloc(sizeof(H5Z_node))) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") + else + { + ret_value->type = MINUS; + ret_value->lchild = (H5Z_node*) H5Z_xform_copy_tree(tree->lchild); + ret_value->rchild = (H5Z_node*) H5Z_xform_copy_tree(tree->rchild); + } + } + else if(tree->type == DIVIDE) + { + if ((ret_value = (H5Z_node*) HDmalloc(sizeof(H5Z_node))) == NULL) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") + else + { + ret_value->type = DIVIDE; + ret_value->lchild = (H5Z_node*) H5Z_xform_copy_tree(tree->lchild); + ret_value->rchild = (H5Z_node*) H5Z_xform_copy_tree(tree->rchild); + } + } + else + HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error in parse tree while trying to copy") + + + + done: + FUNC_LEAVE_NOAPI(ret_value) +} + +/*------------------------------------------------------------------------- + * Function: H5Z_xform_reduce_tree + * Purpose: Simplifies parse tree passed in by performing any obvious + * and trivial arithemtic calculations. + * + * Return: None. + * Programmer: Leon Arber + * April 1, 2004. + * Modifications: + * + *------------------------------------------------------------------------- + */ +void H5Z_xform_reduce_tree(H5Z_node* tree) +{ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5Z_xform_reduce_tree) + + if(!tree) + goto done; + + if((tree->type == PLUS) || (tree->type == DIVIDE) ||(tree->type == MULT) ||(tree->type == MINUS)) + { + if(((tree->lchild->type == H5Z_INTEGER) || (tree->lchild->type == H5Z_FLOAT)) && ((tree->rchild->type == H5Z_INTEGER) || (tree->rchild->type == H5Z_FLOAT))) + H5Z_do_op(tree); + else + { + H5Z_xform_reduce_tree(tree->lchild); + if(((tree->lchild->type == H5Z_INTEGER) || (tree->lchild->type == H5Z_FLOAT)) && ((tree->rchild->type == H5Z_INTEGER) || (tree->rchild->type == H5Z_FLOAT))) + H5Z_do_op(tree); + + H5Z_xform_reduce_tree(tree->rchild); + if(((tree->lchild->type == H5Z_INTEGER) || (tree->lchild->type == H5Z_FLOAT)) && ((tree->rchild->type == H5Z_INTEGER) || (tree->rchild->type == H5Z_FLOAT))) + H5Z_do_op(tree); + } + } + goto done; + +done: + FUNC_LEAVE_NOAPI_VOID; +} + +/*------------------------------------------------------------------------- + * Function: H5Z_do_op + * Purpose: If the root of the tree passed in points to a simple + * arithmetic operation and the left and right subtrees are both + * integer or floating point values, this function does that + * operation, free the left and rigt subtrees, and replaces + * the root with the result of the operation. + * Return: None. + * Programmer: Leon Arber + * April 1, 2004. + * Modifications: +* + *------------------------------------------------------------------------- + */ +static void H5Z_do_op(H5Z_node* tree) +{ + + FUNC_ENTER_NOAPI_NOINIT_NOFUNC(H5Z_do_op) + + + if(tree->type == DIVIDE) + { + if((tree->lchild->type == H5Z_INTEGER) && (tree->rchild->type==H5Z_INTEGER)) + { + tree->type = H5Z_INTEGER; + tree->value.int_val = tree->lchild->value.int_val / tree->rchild->value.int_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + else if((tree->lchild->type == H5Z_FLOAT) && (tree->rchild->type == H5Z_FLOAT)) + { + tree->type = H5Z_FLOAT; + tree->value.float_val = tree->lchild->value.float_val / tree->rchild->value.float_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + else if( (tree->lchild->type == H5Z_FLOAT) && (tree->rchild->type==H5Z_INTEGER)) + { + tree->type = H5Z_FLOAT; + tree->value.float_val = tree->lchild->value.float_val / tree->rchild->value.int_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + else if( (tree->lchild->type == H5Z_INTEGER) && (tree->rchild->type == H5Z_FLOAT)) + { + tree->type = H5Z_FLOAT; + tree->value.float_val = tree->lchild->value.int_val / tree->rchild->value.float_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + + } + else if(tree->type == MULT) + { + + + if((tree->lchild->type == H5Z_INTEGER) && (tree->rchild->type==H5Z_INTEGER)) + { + tree->type = H5Z_INTEGER; + tree->value.int_val = tree->lchild->value.int_val * tree->rchild->value.int_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + else if((tree->lchild->type == H5Z_FLOAT) && (tree->rchild->type == H5Z_FLOAT)) + { + tree->type = H5Z_FLOAT; + tree->value.float_val = tree->lchild->value.float_val * tree->rchild->value.float_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + else if( (tree->lchild->type == H5Z_FLOAT) && (tree->rchild->type==H5Z_INTEGER)) + { + tree->type = H5Z_FLOAT; + tree->value.float_val = tree->lchild->value.float_val * tree->rchild->value.int_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + else if( (tree->lchild->type == H5Z_INTEGER) && (tree->rchild->type == H5Z_FLOAT)) + { + tree->type = H5Z_FLOAT; + tree->value.float_val = tree->lchild->value.int_val * tree->rchild->value.float_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + + } + else if(tree->type == PLUS) + { + + + if((tree->lchild->type == H5Z_INTEGER) && (tree->rchild->type==H5Z_INTEGER)) + { + tree->type = H5Z_INTEGER; + tree->value.int_val = tree->lchild->value.int_val + tree->rchild->value.int_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + else if((tree->lchild->type == H5Z_FLOAT) && (tree->rchild->type == H5Z_FLOAT)) + { + tree->type = H5Z_FLOAT; + tree->value.float_val = tree->lchild->value.float_val + tree->rchild->value.float_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + else if( (tree->lchild->type == H5Z_FLOAT) && (tree->rchild->type==H5Z_INTEGER)) + { + tree->type = H5Z_FLOAT; + tree->value.float_val = tree->lchild->value.float_val + tree->rchild->value.int_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + else if( (tree->lchild->type == H5Z_INTEGER) && (tree->rchild->type == H5Z_FLOAT)) + { + tree->type = H5Z_FLOAT; + tree->value.float_val = tree->lchild->value.int_val + tree->rchild->value.float_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + + } + else if(tree->type == MINUS) + { + + + if((tree->lchild->type == H5Z_INTEGER) && (tree->rchild->type==H5Z_INTEGER)) + { + tree->type = H5Z_INTEGER; + tree->value.int_val = tree->lchild->value.int_val - tree->rchild->value.int_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + else if((tree->lchild->type == H5Z_FLOAT) && (tree->rchild->type == H5Z_FLOAT)) + { + tree->type = H5Z_FLOAT; + tree->value.float_val = tree->lchild->value.float_val - tree->rchild->value.float_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + else if( (tree->lchild->type == H5Z_FLOAT) && (tree->rchild->type==H5Z_INTEGER)) + { + tree->type = H5Z_FLOAT; + tree->value.float_val = tree->lchild->value.float_val - tree->rchild->value.int_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + else if( (tree->lchild->type == H5Z_INTEGER) && (tree->rchild->type == H5Z_FLOAT)) + { + tree->type = H5Z_FLOAT; + tree->value.float_val = tree->lchild->value.int_val - tree->rchild->value.float_val; + HDfree(tree->lchild); + HDfree(tree->rchild); + tree->lchild = NULL; + tree->rchild = NULL; + } + } + + FUNC_LEAVE_NOAPI_VOID; + +} diff --git a/src/Makefile.in b/src/Makefile.in index ab39296..c08141a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -45,7 +45,7 @@ LIB_SRC=H5.c H5A.c H5AC.c H5B.c H5D.c H5Dio.c H5E.c H5F.c H5Fcontig.c \ H5Tconv.c H5Tcset.c H5Tenum.c H5Tfields.c H5Tfixed.c H5Tfloat.c \ H5Tinit.c H5Tnative.c H5Toffset.c H5Topaque.c H5Torder.c H5Tpad.c \ H5Tprecis.c H5Tstrpad.c H5Tvlen.c H5TB.c H5TS.c H5V.c H5Z.c \ - H5Zdeflate.c H5Zfletcher32.c H5Zshuffle.c H5Zszip.c + H5Zdeflate.c H5Zfletcher32.c H5Zshuffle.c H5Zszip.c H5Ztrans.c LIB_OBJ=$(LIB_SRC:.c=.lo) diff --git a/test/Makefile.in b/test/Makefile.in index 3951d7a..e0d3a54 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -31,7 +31,7 @@ TEST_PROGS=testhdf5 lheap ohdr stab gheap hyperslab istore bittests dtypes dsets cmpd_dset extend external links unlink big mtime fillval mount \ flush1 flush2 enum gass_write gass_read gass_append set_extent \ srb_write srb_append srb_read ttsafe stream_test getname file_handle \ - ntypes dangle + ntypes dangle dtransform ## Test programs for Error API ERR_PROGS=error_test err_compat @@ -83,7 +83,7 @@ TEST_SRC=big.c bittests.c cmpd_dset.c dsets.c dtypes.c extend.c \ ttsafe_cancel.c ttsafe_acreate.c gass_write.c gass_read.c \ gass_append.c srb_read.c srb_write.c srb_append.c stream_test.c \ set_extent.c getname.c file_handle.c ntypes.c dangle.c error_test.c \ - err_compat.c + err_compat.c dtransform.c TEST_OBJ=$(TEST_SRC:.c=.lo) @@ -230,4 +230,7 @@ error_test: error_test.lo err_compat: err_compat.lo @$(LT_LINK_EXE) $(CFLAGS) -o $@ err_compat.lo $(LIB) $(LIBHDF5) $(LDFLAGS) $(LIBS) +dtransform: dtransform.lo + @$(LT_LINK_EXE) $(CFLAGS) -o $@ dtransform.lo $(LIB) $(LIBHDF5) $(LDFLAGS) $(LIBS) + @CONCLUDE@ diff --git a/test/dtransform.c b/test/dtransform.c new file mode 100644 index 0000000..0f2e4e8 --- /dev/null +++ b/test/dtransform.c @@ -0,0 +1,110 @@ +#include "h5test.h" + +#define ROWS 12 +#define COLS 18 +#define TOL 2 + +int compare(int* a, int* b); + +int main() +{ + + hid_t file_id, dxpl_id_f_to_c, dxpl_id_c_to_f, dset_id, datatype, dataspace; + hsize_t dim[2] = {ROWS, COLS}; + char* f_to_c = "(5/9.0)*(x-32)"; + char* c_to_f = "(9/5.0)*x + 32"; + int windchillF[ROWS][COLS] = + { {36, 31, 25, 19, 13, 7, 1, -5, -11, -16, -22, -28, -34, -40, -46, -52, -57, -63 }, + {34, 27, 21, 15, 9, 3, -4, -10, -16, -22, -28, -35, -41, -47, -53, -59, -66, -72 } , + {32, 25, 19, 13, 6, 0, -7, -13, -19, -26, -32, -39, -45, -51, -58, -64, -71, -77 }, + {30, 24, 17, 11, 4, -2, -9, -15, -22, -29, -35, -42, -48, -55, -61, -68, -74, -81 }, + {29, 23, 16, 9, 3, -4, -11, -17, -24, -31, -37, -44, -51, -58, -64, -71, -78, -84 }, + {28, 22, 15, 8, 1, -5, -12, -19, -26, -33, -39, -46, -53, -60, -67, -73, -80, -87 }, + {28, 21, 14, 7, 0, -7, -14, -21, -27, -34, -41, -48, -55, -62, -69, -76, -82, -89 }, + {27, 20, 13, 6, -1, -8, -15, -22, -29, -36, -43, -50, -57, -64, -71, -78, -84, -91 }, + {26, 19, 12, 5, -2, -9, -16, -23, -30, -37, -44, -51, -58, -65, -72, -79, -86, -93 }, + {26, 19, 12, 4, -3, -10, -17, -24, -31, -38, -45, -52, -60, -67, -74, -81, -88, -95}, + {25, 18, 11, 4, -3, -11, -18, -25, -32, -39, -46, -54, -61, -68, -75, -82, -89, -97}, + {25, 17, 10, 3, -4, -11, -19, -26, -33, -40, -48, -55, -62, -69, -76, -84, -91, -98} + }; + int windchillCread[ROWS][COLS]; + int windchillFread[ROWS][COLS]; + int windchillCcalc[ROWS][COLS]; + herr_t err; + int row, col; + + + TESTING("data transform"); + + dxpl_id_f_to_c = H5Pcreate(H5P_DATASET_XFER); + dxpl_id_c_to_f = H5Pcreate(H5P_DATASET_XFER); + + err= H5Pset_data_transform(dxpl_id_f_to_c, f_to_c); + err= H5Pset_data_transform(dxpl_id_c_to_f, c_to_f); + + + file_id = H5Fcreate("dtransform.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + + dataspace = H5Screate_simple(2, dim, NULL); + + datatype = H5Tcopy(H5T_NATIVE_INT); + + dset_id = H5Dcreate(file_id, "/transformtest", datatype, dataspace, H5P_DEFAULT); + + err = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, dxpl_id_f_to_c, windchillF); + err = H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, windchillCread); + + for(row = 0; row= (b[row*COLS + col] - TOL))) ) + return 0; + } + } + return 1; +} + + + -- cgit v0.12