mirror of
https://github.com/HDFGroup/hdf5.git
synced 2025-01-06 14:56:51 +08:00
f859cb732b
* fixed missed closing of a dataset * fixed missed closing of a dataset * fixed typo in error return * Committing clang-format changes * minor edits * code format * Committing clang-format changes * code format * minor edit * switched from using MPI_count, to actual bytes written for H5FD_mpio_debug rw debugging * Committing clang-format changes * changed size_i in printf to reflect the I/O. * Committing clang-format changes * Fixed seg fault with xlf on BE with -qintsize=8 * fixed error function string * spelling corrections via codespell, added new spell check github actions * Committing clang-format changes * misc * misc * misc * misc * misc * misc * misc * misc * misc * misc * misc * misc * misc * misc * Committing clang-format changes * misc * misc * misc * misc * misc * misc * Committing clang-format changes * misc * work around for https://github.com/codespell-project/codespell/issues/2137 * misc * added missing file * misc * misc. * misc * switch to using Codespell with GitHub Actions * misc. * misc. * fixed more sp errors * Fix new typos found by codespell. * fixed proceed with precede * fixed variable in fortran test * fixed minnum * updated spelling list Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Larry Knox <lrknox@hdfgroup.org>
1731 lines
74 KiB
C
1731 lines
74 KiB
C
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Copyright by The HDF Group. *
|
|
* Copyright by the Board of Trustees of the University of Illinois. *
|
|
* All rights reserved. *
|
|
* *
|
|
* This file is part of HDF5. The full HDF5 copyright notice, including *
|
|
* terms governing use, modification, and redistribution, is contained in *
|
|
* the COPYING file, which can be found at the root of the source code *
|
|
* distribution tree, or in https://www.hdfgroup.org/licenses. *
|
|
* If you do not have access to either file, you may request a copy from *
|
|
* help@hdfgroup.org. *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
#include "H5Zmodule.h" /* This source code file is part of the H5Z module */
|
|
|
|
#include "H5private.h" /* Generic Functions */
|
|
#include "H5Eprivate.h" /* Error handling */
|
|
#include "H5Iprivate.h" /* IDs */
|
|
#include "H5MMprivate.h" /* Memory management */
|
|
#include "H5VMprivate.h" /* H5VM_array_fill */
|
|
#include "H5Zpkg.h" /* Data filters */
|
|
|
|
/* Token types */
|
|
typedef enum {
|
|
H5Z_XFORM_ERROR,
|
|
H5Z_XFORM_INTEGER, /* this represents an integer type in the data transform expression */
|
|
H5Z_XFORM_FLOAT, /* this represents a floating point type in the data transform expression */
|
|
H5Z_XFORM_SYMBOL,
|
|
H5Z_XFORM_PLUS,
|
|
H5Z_XFORM_MINUS,
|
|
H5Z_XFORM_MULT,
|
|
H5Z_XFORM_DIVIDE,
|
|
H5Z_XFORM_LPAREN,
|
|
H5Z_XFORM_RPAREN,
|
|
H5Z_XFORM_END
|
|
} H5Z_token_type;
|
|
|
|
typedef struct {
|
|
unsigned int num_ptrs;
|
|
void ** ptr_dat_val;
|
|
} H5Z_datval_ptrs;
|
|
|
|
/* Used to represent values in transform expression */
|
|
typedef union {
|
|
void * dat_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;
|
|
|
|
struct H5Z_data_xform_t {
|
|
char * xform_exp;
|
|
H5Z_node * parse_root;
|
|
H5Z_datval_ptrs *dat_val_pointers;
|
|
};
|
|
|
|
typedef struct result {
|
|
H5Z_token_type type;
|
|
H5Z_num_val value;
|
|
} 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;
|
|
|
|
/* Local function prototypes */
|
|
static H5Z_token *H5Z__get_token(H5Z_token *current);
|
|
static H5Z_node * H5Z__parse_expression(H5Z_token *current, H5Z_datval_ptrs *dat_val_pointers);
|
|
static H5Z_node * H5Z__parse_term(H5Z_token *current, H5Z_datval_ptrs *dat_val_pointers);
|
|
static H5Z_node * H5Z__parse_factor(H5Z_token *current, H5Z_datval_ptrs *dat_val_pointers);
|
|
static H5Z_node * H5Z__new_node(H5Z_token_type type);
|
|
static void H5Z__do_op(H5Z_node *tree);
|
|
static hbool_t H5Z__op_is_numbs(H5Z_node *_tree);
|
|
static hbool_t H5Z__op_is_numbs2(H5Z_node *_tree);
|
|
static hid_t H5Z__xform_find_type(const H5T_t *type);
|
|
static herr_t H5Z__xform_eval_full(H5Z_node *tree, size_t array_size, hid_t array_type, H5Z_result *res);
|
|
static void H5Z__xform_destroy_parse_tree(H5Z_node *tree);
|
|
static void * H5Z__xform_parse(const char *expression, H5Z_datval_ptrs *dat_val_pointers);
|
|
static void * H5Z__xform_copy_tree(H5Z_node *tree, H5Z_datval_ptrs *dat_val_pointers,
|
|
H5Z_datval_ptrs *new_dat_val_pointers);
|
|
static void H5Z__xform_reduce_tree(H5Z_node *tree);
|
|
|
|
/* PGCC (11.8-0) has trouble with the command *p++ = *p OP tree_val. It increments P first before
|
|
* doing the operation. So I break down the command into two lines:
|
|
* *p = *p OP tree_val; p++;
|
|
* Actually, the behavior of *p++ = *p OP tree_val is undefined. (SLU - 2012/3/19)
|
|
*/
|
|
#define H5Z_XFORM_DO_OP1(RESL, RESR, TYPE, OP, SIZE) \
|
|
{ \
|
|
size_t u; \
|
|
\
|
|
if (((RESL).type == H5Z_XFORM_SYMBOL) && ((RESR).type != H5Z_XFORM_SYMBOL)) { \
|
|
TYPE * p; \
|
|
double tree_val; \
|
|
\
|
|
tree_val = \
|
|
((RESR).type == H5Z_XFORM_INTEGER ? (double)(RESR).value.int_val : (RESR).value.float_val); \
|
|
p = (TYPE *)(RESL).value.dat_val; \
|
|
\
|
|
for (u = 0; u < (SIZE); u++) { \
|
|
*p = (TYPE)((double)*p OP tree_val); \
|
|
p++; \
|
|
} \
|
|
} \
|
|
else if (((RESR).type == H5Z_XFORM_SYMBOL) && ((RESL).type != H5Z_XFORM_SYMBOL)) { \
|
|
TYPE * p; \
|
|
double tree_val; \
|
|
\
|
|
/* The case that the left operand is nothing, like -x or +x */ \
|
|
if ((RESL).type == H5Z_XFORM_ERROR) \
|
|
tree_val = 0; \
|
|
else \
|
|
tree_val = ((RESL).type == H5Z_XFORM_INTEGER ? (double)(RESL).value.int_val \
|
|
: (RESL).value.float_val); \
|
|
\
|
|
p = (TYPE *)(RESR).value.dat_val; \
|
|
for (u = 0; u < (SIZE); u++) { \
|
|
*p = (TYPE)(tree_val OP(double) * p); \
|
|
p++; \
|
|
} \
|
|
} \
|
|
else if (((RESL).type == H5Z_XFORM_SYMBOL) && ((RESR).type == H5Z_XFORM_SYMBOL)) { \
|
|
TYPE *pl = (TYPE *)(RESL).value.dat_val; \
|
|
TYPE *pr = (TYPE *)(RESR).value.dat_val; \
|
|
\
|
|
for (u = 0; u < (SIZE); u++) { \
|
|
*pl = (TYPE)(*pl OP * pr); \
|
|
pl++; \
|
|
pr++; \
|
|
} \
|
|
} \
|
|
else \
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Unexpected type conversion operation") \
|
|
}
|
|
|
|
#if CHAR_MIN >= 0
|
|
#define H5Z_XFORM_TYPE_OP(RESL, RESR, TYPE, OP, SIZE) \
|
|
{ \
|
|
if ((TYPE) == H5T_NATIVE_CHAR) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), char, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_SCHAR) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), signed char, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_SHORT) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), short, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_USHORT) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned short, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_INT) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), int, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_UINT) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned int, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_LONG) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), long, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_ULONG) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_LLONG) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), long long, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_ULLONG) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long long, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_FLOAT) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), float, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_DOUBLE) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), double, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_LDOUBLE) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), long double, OP, (SIZE)) \
|
|
}
|
|
#else /* CHAR_MIN >= 0 */
|
|
#define H5Z_XFORM_TYPE_OP(RESL, RESR, TYPE, OP, SIZE) \
|
|
{ \
|
|
if ((TYPE) == H5T_NATIVE_CHAR) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), char, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_UCHAR) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned char, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_SHORT) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), short, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_USHORT) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned short, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_INT) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), int, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_UINT) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned int, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_LONG) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), long, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_ULONG) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_LLONG) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), long long, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_ULLONG) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), unsigned long long, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_FLOAT) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), float, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_DOUBLE) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), double, OP, (SIZE)) \
|
|
else if ((TYPE) == H5T_NATIVE_LDOUBLE) \
|
|
H5Z_XFORM_DO_OP1((RESL), (RESR), long double, OP, (SIZE)) \
|
|
}
|
|
#endif /* CHAR_MIN >= 0 */
|
|
|
|
#define H5Z_XFORM_DO_OP3(OP) \
|
|
{ \
|
|
if ((tree->lchild->type == H5Z_XFORM_INTEGER) && (tree->rchild->type == H5Z_XFORM_INTEGER)) { \
|
|
tree->type = H5Z_XFORM_INTEGER; \
|
|
tree->value.int_val = tree->lchild->value.int_val OP tree->rchild->value.int_val; \
|
|
H5MM_xfree(tree->lchild); \
|
|
H5MM_xfree(tree->rchild); \
|
|
tree->lchild = NULL; \
|
|
tree->rchild = NULL; \
|
|
} \
|
|
else if (((tree->lchild->type == H5Z_XFORM_FLOAT) || (tree->lchild->type == H5Z_XFORM_INTEGER)) && \
|
|
((tree->rchild->type == H5Z_XFORM_FLOAT) || (tree->rchild->type == H5Z_XFORM_INTEGER))) { \
|
|
tree->type = H5Z_XFORM_FLOAT; \
|
|
tree->value.float_val = \
|
|
((tree->lchild->type == H5Z_XFORM_FLOAT) ? tree->lchild->value.float_val \
|
|
: (double)tree->lchild->value.int_val) \
|
|
OP((tree->rchild->type == H5Z_XFORM_FLOAT) ? tree->rchild->value.float_val \
|
|
: (double)tree->rchild->value.int_val); \
|
|
H5MM_xfree(tree->lchild); \
|
|
H5MM_xfree(tree->rchild); \
|
|
tree->lchild = NULL; \
|
|
tree->rchild = NULL; \
|
|
} \
|
|
}
|
|
|
|
#define H5Z_XFORM_DO_OP4(TYPE) \
|
|
{ \
|
|
if ((ret_value = (H5Z_node *)H5MM_malloc(sizeof(H5Z_node))) == NULL) \
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Ran out of memory trying to copy parse tree") \
|
|
else { \
|
|
ret_value->type = (TYPE); \
|
|
if (tree->lchild) \
|
|
ret_value->lchild = \
|
|
(H5Z_node *)H5Z__xform_copy_tree(tree->lchild, dat_val_pointers, new_dat_val_pointers); \
|
|
else \
|
|
ret_value->lchild = NULL; \
|
|
if (tree->rchild) \
|
|
ret_value->rchild = \
|
|
(H5Z_node *)H5Z__xform_copy_tree(tree->rchild, dat_val_pointers, new_dat_val_pointers); \
|
|
else \
|
|
ret_value->rchild = NULL; \
|
|
} \
|
|
}
|
|
|
|
#define H5Z_XFORM_DO_OP5(TYPE, SIZE) \
|
|
{ \
|
|
TYPE val = \
|
|
((tree->type == H5Z_XFORM_INTEGER) ? (TYPE)tree->value.int_val : (TYPE)tree->value.float_val); \
|
|
H5VM_array_fill(array, &val, sizeof(TYPE), (SIZE)); \
|
|
}
|
|
|
|
/* The difference of this macro from H5Z_XFORM_DO_OP3 is that it handles the operations when the left operand
|
|
* is empty, like -x or +x. The reason that it's separated from H5Z_XFORM_DO_OP3 is because compilers don't
|
|
* accept operations like *x or /x. So in H5Z__do_op, these two macros are called in different ways. (SLU
|
|
* 2012/3/20)
|
|
*/
|
|
#define H5Z_XFORM_DO_OP6(OP) \
|
|
{ \
|
|
if (!tree->lchild && (tree->rchild->type == H5Z_XFORM_INTEGER)) { \
|
|
tree->type = H5Z_XFORM_INTEGER; \
|
|
tree->value.int_val = OP tree->rchild->value.int_val; \
|
|
H5MM_xfree(tree->rchild); \
|
|
tree->rchild = NULL; \
|
|
} \
|
|
else if (!tree->lchild && (tree->rchild->type == H5Z_XFORM_FLOAT)) { \
|
|
tree->type = H5Z_XFORM_FLOAT; \
|
|
tree->value.float_val = OP tree->rchild->value.float_val; \
|
|
H5MM_xfree(tree->rchild); \
|
|
tree->rchild = NULL; \
|
|
} \
|
|
else if ((tree->lchild->type == H5Z_XFORM_INTEGER) && (tree->rchild->type == H5Z_XFORM_INTEGER)) { \
|
|
tree->type = H5Z_XFORM_INTEGER; \
|
|
tree->value.int_val = tree->lchild->value.int_val OP tree->rchild->value.int_val; \
|
|
H5MM_xfree(tree->lchild); \
|
|
H5MM_xfree(tree->rchild); \
|
|
tree->lchild = NULL; \
|
|
tree->rchild = NULL; \
|
|
} \
|
|
else if (((tree->lchild->type == H5Z_XFORM_FLOAT) || (tree->lchild->type == H5Z_XFORM_INTEGER)) && \
|
|
((tree->rchild->type == H5Z_XFORM_FLOAT) || (tree->rchild->type == H5Z_XFORM_INTEGER))) { \
|
|
tree->type = H5Z_XFORM_FLOAT; \
|
|
tree->value.float_val = \
|
|
((tree->lchild->type == H5Z_XFORM_FLOAT) ? tree->lchild->value.float_val \
|
|
: (double)tree->lchild->value.int_val) \
|
|
OP((tree->rchild->type == H5Z_XFORM_FLOAT) ? tree->rchild->value.float_val \
|
|
: (double)tree->rchild->value.int_val); \
|
|
H5MM_xfree(tree->lchild); \
|
|
H5MM_xfree(tree->rchild); \
|
|
tree->lchild = NULL; \
|
|
tree->rchild = NULL; \
|
|
} \
|
|
}
|
|
|
|
/*
|
|
* 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_XFORM_INTEGER | FLOAT
|
|
* // H5Z_XFORM_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
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static void
|
|
H5Z__unget_token(H5Z_token *current)
|
|
{
|
|
FUNC_ENTER_STATIC_NOERR
|
|
|
|
/* check args */
|
|
HDassert(current);
|
|
|
|
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.
|
|
* Failure: The passed in H5Z_token but with the tok_type
|
|
* field set to ERROR.
|
|
*
|
|
* Programmer: Bill Wendling
|
|
* 26. August 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static H5Z_token *
|
|
H5Z__get_token(H5Z_token *current)
|
|
{
|
|
H5Z_token *ret_value = current;
|
|
|
|
FUNC_ENTER_STATIC
|
|
|
|
/* check args */
|
|
HDassert(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 (HDisspace(current->tok_begin[0])) {
|
|
/* ignore whitespace */
|
|
}
|
|
else if (HDisdigit(current->tok_begin[0]) || current->tok_begin[0] == '.') {
|
|
current->tok_end = current->tok_begin;
|
|
|
|
/*
|
|
* H5Z_XFORM_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_XFORM_INTEGER;
|
|
|
|
while (HDisdigit(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_XFORM_FLOAT;
|
|
|
|
if (current->tok_end[0] == '.')
|
|
do {
|
|
++current->tok_end;
|
|
} while (HDisdigit(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 (!HDisdigit(current->tok_end[0])) {
|
|
current->tok_type = H5Z_XFORM_ERROR;
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current,
|
|
"Invalidly formatted floating point number")
|
|
}
|
|
|
|
while (HDisdigit(current->tok_end[0]))
|
|
++current->tok_end;
|
|
}
|
|
|
|
/* Check that this is a properly formatted numerical value */
|
|
if (HDisalpha(current->tok_end[0]) || current->tok_end[0] == '.') {
|
|
current->tok_type = H5Z_XFORM_ERROR;
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, current, "Invalidly formatted floating point number")
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
else if (HDisalpha(current->tok_begin[0])) {
|
|
/* is symbol */
|
|
current->tok_type = H5Z_XFORM_SYMBOL;
|
|
current->tok_end = current->tok_begin;
|
|
|
|
while (HDisalnum(current->tok_end[0]))
|
|
++current->tok_end;
|
|
|
|
break;
|
|
}
|
|
else {
|
|
/* should be +, -, *, /, (, or ) */
|
|
switch (current->tok_begin[0]) {
|
|
case '+':
|
|
current->tok_type = H5Z_XFORM_PLUS;
|
|
break;
|
|
case '-':
|
|
current->tok_type = H5Z_XFORM_MINUS;
|
|
break;
|
|
case '*':
|
|
current->tok_type = H5Z_XFORM_MULT;
|
|
break;
|
|
case '/':
|
|
current->tok_type = H5Z_XFORM_DIVIDE;
|
|
break;
|
|
case '(':
|
|
current->tok_type = H5Z_XFORM_LPAREN;
|
|
break;
|
|
case ')':
|
|
current->tok_type = H5Z_XFORM_RPAREN;
|
|
break;
|
|
default:
|
|
current->tok_type = H5Z_XFORM_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 = H5Z_XFORM_END;
|
|
|
|
/* Set return value */
|
|
ret_value = 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
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static void
|
|
H5Z__xform_destroy_parse_tree(H5Z_node *tree)
|
|
{
|
|
FUNC_ENTER_STATIC_NOERR
|
|
|
|
if (tree) {
|
|
H5Z__xform_destroy_parse_tree(tree->lchild);
|
|
H5Z__xform_destroy_parse_tree(tree->rchild);
|
|
H5MM_xfree(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.
|
|
* Failure: NULL
|
|
*
|
|
* Programmer: Bill Wendling
|
|
* 26. August 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static void *
|
|
H5Z__xform_parse(const char *expression, H5Z_datval_ptrs *dat_val_pointers)
|
|
{
|
|
H5Z_token tok;
|
|
void * ret_value = NULL; /* Return value */
|
|
|
|
FUNC_ENTER_STATIC
|
|
|
|
if (!expression)
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "No expression provided?")
|
|
|
|
/* 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, dat_val_pointers);
|
|
|
|
H5Z__xform_reduce_tree((H5Z_node *)ret_value);
|
|
|
|
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
|
|
* Failure: NULL
|
|
*
|
|
* Programmer: Bill Wendling
|
|
* 26. August 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static H5Z_node *
|
|
H5Z__parse_expression(H5Z_token *current, H5Z_datval_ptrs *dat_val_pointers)
|
|
{
|
|
H5Z_node *expr;
|
|
H5Z_node *ret_value = NULL; /* Return value */
|
|
|
|
FUNC_ENTER_STATIC
|
|
|
|
expr = H5Z__parse_term(current, dat_val_pointers);
|
|
|
|
for (;;) {
|
|
H5Z_node *new_node;
|
|
|
|
current = H5Z__get_token(current);
|
|
|
|
switch (current->tok_type) {
|
|
case H5Z_XFORM_PLUS:
|
|
new_node = H5Z__new_node(H5Z_XFORM_PLUS);
|
|
|
|
if (!new_node) {
|
|
H5Z__xform_destroy_parse_tree(expr);
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
|
|
}
|
|
|
|
new_node->lchild = expr;
|
|
new_node->rchild = H5Z__parse_term(current, dat_val_pointers);
|
|
|
|
if (!new_node->rchild) {
|
|
H5Z__xform_destroy_parse_tree(new_node);
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
|
|
}
|
|
|
|
expr = new_node;
|
|
break;
|
|
|
|
case H5Z_XFORM_MINUS:
|
|
new_node = H5Z__new_node(H5Z_XFORM_MINUS);
|
|
|
|
if (!new_node) {
|
|
H5Z__xform_destroy_parse_tree(expr);
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
|
|
}
|
|
|
|
new_node->lchild = expr;
|
|
new_node->rchild = H5Z__parse_term(current, dat_val_pointers);
|
|
|
|
if (!new_node->rchild) {
|
|
H5Z__xform_destroy_parse_tree(new_node);
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
|
|
}
|
|
|
|
expr = new_node;
|
|
break;
|
|
|
|
case H5Z_XFORM_RPAREN:
|
|
H5Z__unget_token(current);
|
|
HGOTO_DONE(expr)
|
|
|
|
case H5Z_XFORM_END:
|
|
HGOTO_DONE(expr)
|
|
|
|
case H5Z_XFORM_ERROR:
|
|
case H5Z_XFORM_INTEGER:
|
|
case H5Z_XFORM_FLOAT:
|
|
case H5Z_XFORM_SYMBOL:
|
|
case H5Z_XFORM_MULT:
|
|
case H5Z_XFORM_DIVIDE:
|
|
case H5Z_XFORM_LPAREN:
|
|
default:
|
|
H5Z__xform_destroy_parse_tree(expr);
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
|
|
}
|
|
}
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* 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
|
|
* Failure: NULL
|
|
*
|
|
* Programmer: Bill Wendling
|
|
* 26. August 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static H5Z_node *
|
|
H5Z__parse_term(H5Z_token *current, H5Z_datval_ptrs *dat_val_pointers)
|
|
{
|
|
H5Z_node *term = NULL;
|
|
H5Z_node *ret_value = NULL; /* Return value */
|
|
|
|
FUNC_ENTER_STATIC
|
|
|
|
term = H5Z__parse_factor(current, dat_val_pointers);
|
|
|
|
for (;;) {
|
|
H5Z_node *new_node;
|
|
|
|
current = H5Z__get_token(current);
|
|
|
|
switch (current->tok_type) {
|
|
case H5Z_XFORM_MULT:
|
|
new_node = H5Z__new_node(H5Z_XFORM_MULT);
|
|
|
|
if (!new_node) {
|
|
H5Z__xform_destroy_parse_tree(term);
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
|
|
}
|
|
|
|
new_node->lchild = term;
|
|
new_node->rchild = H5Z__parse_factor(current, dat_val_pointers);
|
|
|
|
if (!new_node->rchild) {
|
|
H5Z__xform_destroy_parse_tree(new_node);
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
|
|
}
|
|
|
|
term = new_node;
|
|
break;
|
|
|
|
case H5Z_XFORM_DIVIDE:
|
|
new_node = H5Z__new_node(H5Z_XFORM_DIVIDE);
|
|
|
|
if (!new_node) {
|
|
H5Z__xform_destroy_parse_tree(term);
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
|
|
}
|
|
|
|
new_node->lchild = term;
|
|
new_node->rchild = H5Z__parse_factor(current, dat_val_pointers);
|
|
term = new_node;
|
|
|
|
if (!new_node->rchild) {
|
|
H5Z__xform_destroy_parse_tree(new_node);
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
|
|
}
|
|
break;
|
|
|
|
case H5Z_XFORM_RPAREN:
|
|
H5Z__unget_token(current);
|
|
HGOTO_DONE(term)
|
|
|
|
case H5Z_XFORM_END:
|
|
HGOTO_DONE(term)
|
|
|
|
case H5Z_XFORM_INTEGER:
|
|
case H5Z_XFORM_FLOAT:
|
|
case H5Z_XFORM_SYMBOL:
|
|
case H5Z_XFORM_PLUS:
|
|
case H5Z_XFORM_MINUS:
|
|
case H5Z_XFORM_LPAREN:
|
|
H5Z__unget_token(current);
|
|
HGOTO_DONE(term)
|
|
|
|
case H5Z_XFORM_ERROR:
|
|
default:
|
|
H5Z__xform_destroy_parse_tree(term);
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL,
|
|
"bad transform type passed to data transform expression")
|
|
} /* end switch */
|
|
} /* end for */
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* 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
|
|
* Failure: NULL
|
|
*
|
|
* Programmer: Bill Wendling
|
|
* 26. August 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static H5Z_node *
|
|
H5Z__parse_factor(H5Z_token *current, H5Z_datval_ptrs *dat_val_pointers)
|
|
{
|
|
H5Z_node *factor = NULL;
|
|
H5Z_node *new_node;
|
|
H5Z_node *ret_value = NULL; /* Return value */
|
|
|
|
FUNC_ENTER_STATIC
|
|
|
|
current = H5Z__get_token(current);
|
|
|
|
switch (current->tok_type) {
|
|
case H5Z_XFORM_INTEGER:
|
|
factor = H5Z__new_node(H5Z_XFORM_INTEGER);
|
|
|
|
if (!factor)
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
|
|
HDsscanf(current->tok_begin, "%ld", &factor->value.int_val);
|
|
break;
|
|
|
|
case H5Z_XFORM_FLOAT:
|
|
factor = H5Z__new_node(H5Z_XFORM_FLOAT);
|
|
|
|
if (!factor)
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
|
|
HDsscanf(current->tok_begin, "%lf", &factor->value.float_val);
|
|
break;
|
|
|
|
case H5Z_XFORM_SYMBOL:
|
|
factor = H5Z__new_node(H5Z_XFORM_SYMBOL);
|
|
|
|
if (!factor)
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
|
|
|
|
factor->value.dat_val = &(dat_val_pointers->ptr_dat_val[dat_val_pointers->num_ptrs]);
|
|
dat_val_pointers->num_ptrs++;
|
|
break;
|
|
|
|
case H5Z_XFORM_LPAREN:
|
|
factor = H5Z__parse_expression(current, dat_val_pointers);
|
|
|
|
if (!factor)
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "Unable to allocate new node")
|
|
|
|
current = H5Z__get_token(current);
|
|
|
|
if (current->tok_type != H5Z_XFORM_RPAREN) {
|
|
H5Z__xform_destroy_parse_tree(factor);
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Syntax error in data transform expression")
|
|
}
|
|
break;
|
|
|
|
case H5Z_XFORM_RPAREN:
|
|
/* We shouldn't see a ) right now */
|
|
H5Z__xform_destroy_parse_tree(factor);
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Syntax error: unexpected ')' ")
|
|
|
|
case H5Z_XFORM_PLUS:
|
|
/* unary + */
|
|
new_node = H5Z__parse_factor(current, dat_val_pointers);
|
|
|
|
if (new_node) {
|
|
if (new_node->type != H5Z_XFORM_INTEGER && new_node->type != H5Z_XFORM_FLOAT &&
|
|
new_node->type != H5Z_XFORM_SYMBOL) {
|
|
H5Z__xform_destroy_parse_tree(new_node);
|
|
H5Z__xform_destroy_parse_tree(factor);
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
|
|
}
|
|
|
|
factor = new_node;
|
|
new_node = H5Z__new_node(H5Z_XFORM_PLUS);
|
|
|
|
if (!new_node) {
|
|
H5Z__xform_destroy_parse_tree(factor);
|
|
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);
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
|
|
}
|
|
break;
|
|
|
|
case H5Z_XFORM_MINUS:
|
|
/* unary - */
|
|
new_node = H5Z__parse_factor(current, dat_val_pointers);
|
|
|
|
if (new_node) {
|
|
if (new_node->type != H5Z_XFORM_INTEGER && new_node->type != H5Z_XFORM_FLOAT &&
|
|
new_node->type != H5Z_XFORM_SYMBOL) {
|
|
H5Z__xform_destroy_parse_tree(new_node);
|
|
H5Z__xform_destroy_parse_tree(factor);
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
|
|
}
|
|
|
|
factor = new_node;
|
|
new_node = H5Z__new_node(H5Z_XFORM_MINUS);
|
|
|
|
if (!new_node) {
|
|
H5Z__xform_destroy_parse_tree(factor);
|
|
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);
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error parsing data transform expression")
|
|
}
|
|
break;
|
|
|
|
case H5Z_XFORM_END:
|
|
break;
|
|
|
|
case H5Z_XFORM_MULT:
|
|
case H5Z_XFORM_DIVIDE:
|
|
case H5Z_XFORM_ERROR:
|
|
default:
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Invalid token while parsing data transform expression")
|
|
}
|
|
|
|
/* Set return value */
|
|
ret_value = factor;
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value);
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z__new_node
|
|
*
|
|
* Purpose: Create and initialize a new H5Z_node structure.
|
|
*
|
|
* Return: Success: Valid H5Z_node ptr
|
|
* Failure: NULL
|
|
*
|
|
* Programmer: Bill Wendling
|
|
* 26. August 2003
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static H5Z_node *
|
|
H5Z__new_node(H5Z_token_type type)
|
|
{
|
|
H5Z_node *ret_value = NULL; /* Return value */
|
|
|
|
FUNC_ENTER_STATIC
|
|
|
|
if (NULL == (ret_value = (H5Z_node *)H5MM_calloc(sizeof(H5Z_node))))
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
|
|
"Ran out of memory trying to allocate space for nodes in the parse tree")
|
|
|
|
ret_value->type = type;
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z_xform_eval
|
|
* Purpose: If the transform is trivial, this function applies it.
|
|
* Otherwise, it calls H5Z__xform_eval_full to do the full
|
|
* transform.
|
|
* Return: SUCCEED if transform applied successfully, FAIL otherwise
|
|
* Programmer: Leon Arber
|
|
* 5/1/04
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5Z_xform_eval(H5Z_data_xform_t *data_xform_prop, void *array, size_t array_size, const H5T_t *buf_type)
|
|
{
|
|
H5Z_node * tree;
|
|
hid_t array_type;
|
|
H5Z_result res;
|
|
size_t i;
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_NOAPI(FAIL)
|
|
|
|
HDassert(data_xform_prop);
|
|
|
|
tree = data_xform_prop->parse_root;
|
|
|
|
/* Get the datatype ID for the buffer's type */
|
|
if ((array_type = H5Z__xform_find_type(buf_type)) < 0)
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Cannot perform data transform on this type.")
|
|
|
|
/* After this point, we're assured that the type of the array is handled by the eval code,
|
|
* so we no longer have to check for valid types
|
|
*/
|
|
|
|
/* If it's a trivial data transform, perform it */
|
|
if (tree->type == H5Z_XFORM_INTEGER || tree->type == H5Z_XFORM_FLOAT) {
|
|
if (array_type == H5T_NATIVE_CHAR)
|
|
H5Z_XFORM_DO_OP5(char, array_size)
|
|
#if CHAR_MIN >= 0
|
|
else if (array_type == H5T_NATIVE_SCHAR)
|
|
H5Z_XFORM_DO_OP5(signed char, array_size)
|
|
#else /* CHAR_MIN >= 0 */
|
|
else if (array_type == H5T_NATIVE_UCHAR)
|
|
H5Z_XFORM_DO_OP5(unsigned char, array_size)
|
|
#endif /* CHAR_MIN >= 0 */
|
|
else if (array_type == H5T_NATIVE_SHORT)
|
|
H5Z_XFORM_DO_OP5(short, array_size)
|
|
else if (array_type == H5T_NATIVE_USHORT)
|
|
H5Z_XFORM_DO_OP5(unsigned short, array_size)
|
|
else if (array_type == H5T_NATIVE_INT)
|
|
H5Z_XFORM_DO_OP5(int, array_size)
|
|
else if (array_type == H5T_NATIVE_UINT)
|
|
H5Z_XFORM_DO_OP5(unsigned int, array_size)
|
|
else if (array_type == H5T_NATIVE_LONG)
|
|
H5Z_XFORM_DO_OP5(long, array_size)
|
|
else if (array_type == H5T_NATIVE_ULONG)
|
|
H5Z_XFORM_DO_OP5(unsigned long, array_size)
|
|
else if (array_type == H5T_NATIVE_LLONG)
|
|
H5Z_XFORM_DO_OP5(long long, array_size)
|
|
else if (array_type == H5T_NATIVE_ULLONG)
|
|
H5Z_XFORM_DO_OP5(unsigned long long, array_size)
|
|
else if (array_type == H5T_NATIVE_FLOAT)
|
|
H5Z_XFORM_DO_OP5(float, array_size)
|
|
else if (array_type == H5T_NATIVE_DOUBLE)
|
|
H5Z_XFORM_DO_OP5(double, array_size)
|
|
else if (array_type == H5T_NATIVE_LDOUBLE)
|
|
H5Z_XFORM_DO_OP5(long double, array_size)
|
|
|
|
} /* end if */
|
|
/* Otherwise, do the full data transform */
|
|
else {
|
|
/* Optimization for linear transform: */
|
|
if (data_xform_prop->dat_val_pointers->num_ptrs == 1)
|
|
data_xform_prop->dat_val_pointers->ptr_dat_val[0] = array;
|
|
|
|
/* If it's a quadratic transform, we have no choice but to store multiple copies of the data */
|
|
else {
|
|
for (i = 0; i < data_xform_prop->dat_val_pointers->num_ptrs; i++) {
|
|
if (NULL == (data_xform_prop->dat_val_pointers->ptr_dat_val[i] = (void *)H5MM_malloc(
|
|
array_size * H5T_get_size((H5T_t *)H5I_object(array_type)))))
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
|
|
"Ran out of memory trying to allocate space for data in data transform")
|
|
|
|
H5MM_memcpy(data_xform_prop->dat_val_pointers->ptr_dat_val[i], array,
|
|
array_size * H5T_get_size((H5T_t *)H5I_object(array_type)));
|
|
} /* end for */
|
|
} /* end else */
|
|
|
|
if (H5Z__xform_eval_full(tree, array_size, array_type, &res) < 0)
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error while performing data transform")
|
|
|
|
if (data_xform_prop->dat_val_pointers->num_ptrs > 1)
|
|
H5MM_memcpy(array, res.value.dat_val, array_size * H5T_get_size((H5T_t *)H5I_object(array_type)));
|
|
|
|
/* Free the temporary arrays we used */
|
|
if (data_xform_prop->dat_val_pointers->num_ptrs > 1)
|
|
for (i = 0; i < data_xform_prop->dat_val_pointers->num_ptrs; i++)
|
|
H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val[i]);
|
|
} /* end else */
|
|
|
|
done:
|
|
if (ret_value < 0) {
|
|
/* If we ran out of memory above copying the array for temp storage (which we easily can for
|
|
* polynomial transforms of high order) we free those arrays which we already allocated */
|
|
if (data_xform_prop->dat_val_pointers->num_ptrs > 1)
|
|
for (i = 0; i < data_xform_prop->dat_val_pointers->num_ptrs; i++)
|
|
if (data_xform_prop->dat_val_pointers->ptr_dat_val[i])
|
|
H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val[i]);
|
|
} /* end if */
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5Z_xform_eval() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z__xform_eval_full
|
|
*
|
|
* Purpose: Does a full evaluation of the parse tree contained in tree
|
|
* and applies this transform to array.
|
|
*
|
|
* Notes: In the case of a polynomial data transform (ie, the left and right
|
|
* subtree are both of type H5Z_XFORM_SYMBOL), the convention is
|
|
* that the left hand side will accumulate changes and, at the end,
|
|
* the new data will be copied from the lhs.
|
|
*
|
|
* Return: Nothing
|
|
*
|
|
* Programmer: Leon Arber
|
|
* 5/1/04
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static herr_t
|
|
H5Z__xform_eval_full(H5Z_node *tree, const size_t array_size, const hid_t array_type, H5Z_result *res)
|
|
{
|
|
H5Z_result resl, resr;
|
|
herr_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_STATIC
|
|
|
|
/* check args */
|
|
HDassert(tree);
|
|
|
|
HDmemset(&resl, 0, sizeof(H5Z_result));
|
|
HDmemset(&resr, 0, sizeof(H5Z_result));
|
|
|
|
if (tree->type == H5Z_XFORM_INTEGER) {
|
|
res->type = H5Z_XFORM_INTEGER;
|
|
res->value.int_val = tree->value.int_val;
|
|
} /* end if */
|
|
else if (tree->type == H5Z_XFORM_FLOAT) {
|
|
res->type = H5Z_XFORM_FLOAT;
|
|
res->value.float_val = tree->value.float_val;
|
|
} /* end if */
|
|
else if (tree->type == H5Z_XFORM_SYMBOL) {
|
|
res->type = H5Z_XFORM_SYMBOL;
|
|
|
|
/*since dat_val stores the address of the array which is really stored in the dat_val_pointers,
|
|
* here we make dat_val store a pointer to the array itself instead of the address of it so that the
|
|
* rest of the code below works normally. */
|
|
res->value.dat_val = *((void **)(tree->value.dat_val));
|
|
} /* end if */
|
|
else {
|
|
if (tree->lchild && H5Z__xform_eval_full(tree->lchild, array_size, array_type, &resl) < 0)
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error while performing data transform")
|
|
if (H5Z__xform_eval_full(tree->rchild, array_size, array_type, &resr) < 0)
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error while performing data transform")
|
|
|
|
res->type = H5Z_XFORM_SYMBOL;
|
|
|
|
/* For each type of operation:
|
|
* 1. See if "x" is on left hand side, right hand side, or if both sides are "x"
|
|
* 2. Figure out what type of data we're going to be manipulating
|
|
* 3. Do the operation on the data. */
|
|
switch (tree->type) {
|
|
case H5Z_XFORM_PLUS:
|
|
H5Z_XFORM_TYPE_OP(resl, resr, array_type, +, array_size)
|
|
break;
|
|
|
|
case H5Z_XFORM_MINUS:
|
|
H5Z_XFORM_TYPE_OP(resl, resr, array_type, -, array_size)
|
|
break;
|
|
|
|
case H5Z_XFORM_MULT:
|
|
H5Z_XFORM_TYPE_OP(resl, resr, array_type, *, array_size)
|
|
break;
|
|
|
|
case H5Z_XFORM_DIVIDE:
|
|
H5Z_XFORM_TYPE_OP(resl, resr, array_type, /, array_size)
|
|
break;
|
|
|
|
case H5Z_XFORM_ERROR:
|
|
case H5Z_XFORM_INTEGER:
|
|
case H5Z_XFORM_FLOAT:
|
|
case H5Z_XFORM_SYMBOL:
|
|
case H5Z_XFORM_LPAREN:
|
|
case H5Z_XFORM_RPAREN:
|
|
case H5Z_XFORM_END:
|
|
default:
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "Invalid expression tree")
|
|
} /* end switch */
|
|
|
|
/* The result stores a pointer to the new data */
|
|
/* So, if the left hand side got its data modified, the result stores a pointers
|
|
* to the left hand side's data, ditto for rhs */
|
|
if (resl.type == H5Z_XFORM_SYMBOL)
|
|
res->value.dat_val = resl.value.dat_val;
|
|
else if (resr.type == H5Z_XFORM_SYMBOL)
|
|
res->value.dat_val = resr.value.dat_val;
|
|
else
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, FAIL, "error during transform evaluation")
|
|
} /* end else */
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5Z__xform_eval_full() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z_find_type
|
|
*
|
|
* Return: Native type of datatype that is passed in
|
|
*
|
|
* Programmer: Leon Arber, 4/20/04
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static hid_t
|
|
H5Z__xform_find_type(const H5T_t *type)
|
|
{
|
|
H5T_t *tmp; /* Temporary datatype */
|
|
hid_t ret_value = SUCCEED; /* Return value */
|
|
|
|
FUNC_ENTER_STATIC
|
|
|
|
HDassert(type);
|
|
|
|
/* Check for SHORT type */
|
|
if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_SHORT)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_SHORT)
|
|
/* Check for INT type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_INT)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_INT)
|
|
/* Check for LONG type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_LONG)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_LONG)
|
|
/* Check for LONGLONG type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_LLONG)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_LLONG)
|
|
/* Check for UCHAR type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_UCHAR)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_UCHAR)
|
|
/* Check for CHAR type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_CHAR)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_CHAR)
|
|
/* Check for SCHAR type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_SCHAR)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_SCHAR)
|
|
/* Check for USHORT type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_USHORT)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_USHORT)
|
|
/* Check for UINT type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_UINT)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_UINT)
|
|
/* Check for ULONG type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_ULONG)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_ULONG)
|
|
/* Check for ULONGLONG type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_ULLONG)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_ULLONG)
|
|
/* Check for FLOAT type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_FLOAT)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_FLOAT)
|
|
/* Check for DOUBLE type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_DOUBLE)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_DOUBLE)
|
|
/* Check for LONGDOUBLE type */
|
|
else if ((tmp = (H5T_t *)H5I_object(H5T_NATIVE_LDOUBLE)) && 0 == H5T_cmp(type, tmp, FALSE))
|
|
HGOTO_DONE(H5T_NATIVE_LDOUBLE)
|
|
else
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "could not find matching type")
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* end H5Z__xform_find_type() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z__xform_copy_tree
|
|
*
|
|
* Purpose: Makes a copy of the parse tree passed in.
|
|
*
|
|
* Return: A pointer to a root for a new parse tree which is a copy
|
|
* of the one passed in.
|
|
*
|
|
* Programmer: Leon Arber
|
|
* April 1, 2004.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static void *
|
|
H5Z__xform_copy_tree(H5Z_node *tree, H5Z_datval_ptrs *dat_val_pointers, H5Z_datval_ptrs *new_dat_val_pointers)
|
|
{
|
|
H5Z_node *ret_value = NULL;
|
|
|
|
FUNC_ENTER_STATIC
|
|
|
|
HDassert(tree);
|
|
|
|
if (tree->type == H5Z_XFORM_INTEGER) {
|
|
if ((ret_value = (H5Z_node *)H5MM_malloc(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_XFORM_INTEGER;
|
|
ret_value->value.int_val = tree->value.int_val;
|
|
ret_value->lchild = NULL;
|
|
ret_value->rchild = NULL;
|
|
}
|
|
}
|
|
else if (tree->type == H5Z_XFORM_FLOAT) {
|
|
if ((ret_value = (H5Z_node *)H5MM_malloc(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_XFORM_FLOAT;
|
|
ret_value->value.float_val = tree->value.float_val;
|
|
ret_value->lchild = NULL;
|
|
ret_value->rchild = NULL;
|
|
}
|
|
}
|
|
else if (tree->type == H5Z_XFORM_SYMBOL) {
|
|
if ((ret_value = (H5Z_node *)H5MM_malloc(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_XFORM_SYMBOL;
|
|
|
|
ret_value->value.dat_val = &(new_dat_val_pointers->ptr_dat_val[new_dat_val_pointers->num_ptrs]);
|
|
new_dat_val_pointers->num_ptrs++;
|
|
ret_value->lchild = NULL;
|
|
ret_value->rchild = NULL;
|
|
}
|
|
}
|
|
else if (tree->type == H5Z_XFORM_MULT)
|
|
H5Z_XFORM_DO_OP4(H5Z_XFORM_MULT)
|
|
else if (tree->type == H5Z_XFORM_PLUS)
|
|
H5Z_XFORM_DO_OP4(H5Z_XFORM_PLUS)
|
|
else if (tree->type == H5Z_XFORM_MINUS)
|
|
H5Z_XFORM_DO_OP4(H5Z_XFORM_MINUS)
|
|
else if (tree->type == H5Z_XFORM_DIVIDE)
|
|
H5Z_XFORM_DO_OP4(H5Z_XFORM_DIVIDE)
|
|
else
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADVALUE, NULL, "Error in parse tree while trying to copy")
|
|
|
|
done:
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z__op_is_numbs
|
|
*
|
|
* Purpose: Internal function to facilitate the condition check in
|
|
* H5Z__xform_reduce_tree to reduce the bulkiness of the code.
|
|
*
|
|
* Return: TRUE or FALSE
|
|
*
|
|
* Programmer: Raymond Lu
|
|
* 15 March 2012
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static hbool_t
|
|
H5Z__op_is_numbs(H5Z_node *_tree)
|
|
{
|
|
hbool_t ret_value = FALSE;
|
|
|
|
FUNC_ENTER_STATIC_NOERR
|
|
|
|
HDassert(_tree);
|
|
|
|
if (((_tree->lchild->type == H5Z_XFORM_INTEGER) || (_tree->lchild->type == H5Z_XFORM_FLOAT)) &&
|
|
((_tree->rchild->type == H5Z_XFORM_INTEGER) || (_tree->rchild->type == H5Z_XFORM_FLOAT)))
|
|
ret_value = TRUE;
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z__op_is_numbs2
|
|
*
|
|
* Purpose: Internal function to facilitate the condition check in
|
|
* H5Z__xform_reduce_tree to reduce the bulkiness of the code.
|
|
* The difference from H5Z__op_is_numbs is that the left child
|
|
* can be empty, like -x or +x.
|
|
*
|
|
* Return: TRUE or FALSE
|
|
*
|
|
* Programmer: Raymond Lu
|
|
* 15 March 2012
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static hbool_t
|
|
H5Z__op_is_numbs2(H5Z_node *_tree)
|
|
{
|
|
hbool_t ret_value = FALSE;
|
|
|
|
FUNC_ENTER_STATIC_NOERR
|
|
|
|
HDassert(_tree);
|
|
|
|
if ((!_tree->lchild &&
|
|
((_tree->rchild->type == H5Z_XFORM_INTEGER) || (_tree->rchild->type == H5Z_XFORM_FLOAT))) ||
|
|
((_tree->lchild &&
|
|
((_tree->lchild->type == H5Z_XFORM_INTEGER) || (_tree->lchild->type == H5Z_XFORM_FLOAT))) &&
|
|
(_tree->rchild &&
|
|
((_tree->rchild->type == H5Z_XFORM_INTEGER) || (_tree->rchild->type == H5Z_XFORM_FLOAT)))))
|
|
ret_value = TRUE;
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z__xform_reduce_tree
|
|
*
|
|
* Purpose: Simplifies parse tree passed in by performing any obvious
|
|
* and trivial arithmetic calculations.
|
|
*
|
|
* Return: None.
|
|
*
|
|
* Programmer: Leon Arber
|
|
* April 1, 2004.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static void
|
|
H5Z__xform_reduce_tree(H5Z_node *tree)
|
|
{
|
|
FUNC_ENTER_STATIC_NOERR
|
|
|
|
if (tree) {
|
|
if ((tree->type == H5Z_XFORM_DIVIDE) || (tree->type == H5Z_XFORM_MULT)) {
|
|
if (H5Z__op_is_numbs(tree))
|
|
H5Z__do_op(tree);
|
|
else {
|
|
H5Z__xform_reduce_tree(tree->lchild);
|
|
if (H5Z__op_is_numbs(tree))
|
|
H5Z__do_op(tree);
|
|
else {
|
|
H5Z__xform_reduce_tree(tree->rchild);
|
|
if (H5Z__op_is_numbs(tree))
|
|
H5Z__do_op(tree);
|
|
}
|
|
}
|
|
}
|
|
else if ((tree->type == H5Z_XFORM_PLUS) || (tree->type == H5Z_XFORM_MINUS)) {
|
|
if (H5Z__op_is_numbs2(tree))
|
|
H5Z__do_op(tree);
|
|
else {
|
|
H5Z__xform_reduce_tree(tree->lchild);
|
|
if (H5Z__op_is_numbs2(tree))
|
|
H5Z__do_op(tree);
|
|
else {
|
|
H5Z__xform_reduce_tree(tree->rchild);
|
|
if (H5Z__op_is_numbs2(tree))
|
|
H5Z__do_op(tree);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 right subtrees, and replaces
|
|
* the root with the result of the operation.
|
|
*
|
|
* Return: None.
|
|
*
|
|
* Programmer: Leon Arber
|
|
* April 1, 2004.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
static void
|
|
H5Z__do_op(H5Z_node *tree)
|
|
{
|
|
FUNC_ENTER_STATIC_NOERR
|
|
|
|
if (tree->type == H5Z_XFORM_DIVIDE)
|
|
H5Z_XFORM_DO_OP3(/)
|
|
else if (tree->type == H5Z_XFORM_MULT)
|
|
H5Z_XFORM_DO_OP3(*)
|
|
else if (tree->type == H5Z_XFORM_PLUS)
|
|
H5Z_XFORM_DO_OP6(+)
|
|
else if (tree->type == H5Z_XFORM_MINUS)
|
|
H5Z_XFORM_DO_OP6(-)
|
|
|
|
FUNC_LEAVE_NOAPI_VOID;
|
|
}
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z_xform_create
|
|
*
|
|
* Purpose: Create a new data transform object from a string.
|
|
*
|
|
* Return:
|
|
* Success: SUCCEED
|
|
* Failure: FAIL
|
|
*
|
|
* Programmer: Quincey Koziol
|
|
*
|
|
* Date: May 4, 2004
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
H5Z_data_xform_t *
|
|
H5Z_xform_create(const char *expr)
|
|
{
|
|
H5Z_data_xform_t *data_xform_prop = NULL;
|
|
unsigned int i;
|
|
unsigned int count = 0;
|
|
H5Z_data_xform_t *ret_value = NULL; /* Return value */
|
|
|
|
FUNC_ENTER_NOAPI(NULL)
|
|
|
|
HDassert(expr);
|
|
|
|
/* Allocate space for the data transform information */
|
|
if (NULL == (data_xform_prop = (H5Z_data_xform_t *)H5MM_calloc(sizeof(H5Z_data_xform_t))))
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to allocate memory for data transform info")
|
|
|
|
if (NULL == (data_xform_prop->dat_val_pointers = (H5Z_datval_ptrs *)H5MM_malloc(sizeof(H5Z_datval_ptrs))))
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
|
|
"unable to allocate memory for data transform array storage")
|
|
|
|
/* copy the user's string into the property */
|
|
if (NULL == (data_xform_prop->xform_exp = (char *)H5MM_xstrdup(expr)))
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
|
|
"unable to allocate memory for data transform expression")
|
|
|
|
/* Find the number of times "x" is used in this equation, and allocate room for storing that many points
|
|
* A more sophisticated check is needed to support scientific notation.
|
|
*/
|
|
for (i = 0; i < HDstrlen(expr); i++) {
|
|
if (HDisalpha(expr[i])) {
|
|
if ((i > 0) && (i < (HDstrlen(expr) - 1))) {
|
|
if (((expr[i] == 'E') || (expr[i] == 'e')) &&
|
|
(HDisdigit(expr[i - 1]) || (expr[i - 1] == '.')) &&
|
|
(HDisdigit(expr[i + 1]) || (expr[i + 1] == '-') || (expr[i + 1] == '+')))
|
|
continue;
|
|
} /* end if */
|
|
|
|
count++;
|
|
} /* end if */
|
|
} /* end for */
|
|
|
|
/* When there are no "x"'s in the equation (ie, simple transform case),
|
|
* we don't need to allocate any space since no array will have to be
|
|
* stored */
|
|
if (count > 0)
|
|
if (NULL ==
|
|
(data_xform_prop->dat_val_pointers->ptr_dat_val = (void **)H5MM_calloc(count * sizeof(void *))))
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL,
|
|
"unable to allocate memory for pointers in transform array")
|
|
|
|
/* Initialize the num_ptrs field, which will be used to keep track of the number of copies
|
|
* of the data we have for polynomial transforms */
|
|
data_xform_prop->dat_val_pointers->num_ptrs = 0;
|
|
|
|
/* we generate the parse tree right here and store a pointer to its root in the property. */
|
|
if ((data_xform_prop->parse_root =
|
|
(H5Z_node *)H5Z__xform_parse(expr, data_xform_prop->dat_val_pointers)) == NULL)
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "unable to generate parse tree from expression")
|
|
|
|
/* Sanity check
|
|
* count should be the same num_ptrs */
|
|
if (count != data_xform_prop->dat_val_pointers->num_ptrs)
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, NULL,
|
|
"error copying the parse tree, did not find correct number of \"variables\"")
|
|
|
|
/* Assign return value */
|
|
ret_value = data_xform_prop;
|
|
|
|
done:
|
|
/* Clean up on error */
|
|
if (ret_value == NULL) {
|
|
if (data_xform_prop) {
|
|
if (data_xform_prop->parse_root)
|
|
H5Z__xform_destroy_parse_tree(data_xform_prop->parse_root);
|
|
if (data_xform_prop->xform_exp)
|
|
H5MM_xfree(data_xform_prop->xform_exp);
|
|
if (count > 0 && data_xform_prop->dat_val_pointers->ptr_dat_val)
|
|
H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val);
|
|
if (data_xform_prop->dat_val_pointers)
|
|
H5MM_xfree(data_xform_prop->dat_val_pointers);
|
|
H5MM_xfree(data_xform_prop);
|
|
} /* end if */
|
|
} /* end if */
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* H5Z_xform_create() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z_xform_destroy
|
|
*
|
|
* Purpose: Destroy a data transform object.
|
|
*
|
|
* Return:
|
|
* Success: SUCCEED
|
|
* Failure: FAIL
|
|
*
|
|
* Programmer: Quincey Koziol
|
|
*
|
|
* Date: May 4, 2004
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5Z_xform_destroy(H5Z_data_xform_t *data_xform_prop)
|
|
{
|
|
FUNC_ENTER_NOAPI_NOINIT_NOERR
|
|
|
|
if (data_xform_prop) {
|
|
/* Destroy the parse tree */
|
|
H5Z__xform_destroy_parse_tree(data_xform_prop->parse_root);
|
|
|
|
/* Free the expression */
|
|
H5MM_xfree(data_xform_prop->xform_exp);
|
|
|
|
/* Free the pointers to the temp. arrays, if there are any */
|
|
if (data_xform_prop->dat_val_pointers->num_ptrs > 0)
|
|
H5MM_xfree(data_xform_prop->dat_val_pointers->ptr_dat_val);
|
|
|
|
/* Free the data storage struct */
|
|
H5MM_xfree(data_xform_prop->dat_val_pointers);
|
|
|
|
/* Free the node */
|
|
H5MM_xfree(data_xform_prop);
|
|
} /* end if */
|
|
|
|
FUNC_LEAVE_NOAPI(SUCCEED)
|
|
} /* H5Z_xform_destroy() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z_xform_copy
|
|
*
|
|
* Purpose: Clone a data transform object.
|
|
*
|
|
* Return:
|
|
* Success: SUCCEED
|
|
* Failure: FAIL
|
|
*
|
|
* Programmer: Quincey Koziol
|
|
*
|
|
* Date: May 4, 2004
|
|
*
|
|
* Comments: This is an "in-place" copy, since this routine gets called
|
|
* after the top-level copy has been performed and this routine finishes
|
|
* the "deep" part of the copy.
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
herr_t
|
|
H5Z_xform_copy(H5Z_data_xform_t **data_xform_prop)
|
|
{
|
|
unsigned int i;
|
|
unsigned int count = 0;
|
|
H5Z_data_xform_t *new_data_xform_prop = NULL;
|
|
herr_t ret_value = SUCCEED;
|
|
|
|
FUNC_ENTER_NOAPI(FAIL)
|
|
|
|
if (*data_xform_prop) {
|
|
/* Allocate new node */
|
|
if (NULL == (new_data_xform_prop = (H5Z_data_xform_t *)H5MM_calloc(sizeof(H5Z_data_xform_t))))
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL, "unable to allocate memory for data transform info")
|
|
|
|
/* Copy string */
|
|
if (NULL == (new_data_xform_prop->xform_exp = (char *)H5MM_xstrdup((*data_xform_prop)->xform_exp)))
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
|
|
"unable to allocate memory for data transform expression")
|
|
|
|
if (NULL ==
|
|
(new_data_xform_prop->dat_val_pointers = (H5Z_datval_ptrs *)H5MM_malloc(sizeof(H5Z_datval_ptrs))))
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
|
|
"unable to allocate memory for data transform array storage")
|
|
|
|
/* Find the number of times "x" is used in this equation, and allocate room for storing that many
|
|
* points */
|
|
for (i = 0; i < HDstrlen(new_data_xform_prop->xform_exp); i++)
|
|
if (HDisalpha(new_data_xform_prop->xform_exp[i]))
|
|
count++;
|
|
|
|
if (count > 0)
|
|
if (NULL == (new_data_xform_prop->dat_val_pointers->ptr_dat_val =
|
|
(void **)H5MM_calloc(count * sizeof(void *))))
|
|
HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, FAIL,
|
|
"unable to allocate memory for pointers in transform array")
|
|
|
|
/* Zero out num_pointers prior to H5Z_xform_cop_tree call; that call will increment it to the right
|
|
* amount */
|
|
new_data_xform_prop->dat_val_pointers->num_ptrs = 0;
|
|
|
|
/* Copy parse tree */
|
|
if ((new_data_xform_prop->parse_root = (H5Z_node *)H5Z__xform_copy_tree(
|
|
(*data_xform_prop)->parse_root, (*data_xform_prop)->dat_val_pointers,
|
|
new_data_xform_prop->dat_val_pointers)) == NULL)
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "error copying the parse tree")
|
|
|
|
/* Sanity check
|
|
* count should be the same num_ptrs */
|
|
if (count != new_data_xform_prop->dat_val_pointers->num_ptrs)
|
|
HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL,
|
|
"error copying the parse tree, did not find correct number of \"variables\"")
|
|
|
|
/* Copy new information on top of old information */
|
|
*data_xform_prop = new_data_xform_prop;
|
|
} /* end if */
|
|
|
|
done:
|
|
/* Clean up on error */
|
|
if (ret_value < 0) {
|
|
if (new_data_xform_prop) {
|
|
if (new_data_xform_prop->parse_root)
|
|
H5Z__xform_destroy_parse_tree(new_data_xform_prop->parse_root);
|
|
if (new_data_xform_prop->xform_exp)
|
|
H5MM_xfree(new_data_xform_prop->xform_exp);
|
|
H5MM_xfree(new_data_xform_prop);
|
|
} /* end if */
|
|
} /* end if */
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* H5Z_xform_copy() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z_xform_noop
|
|
*
|
|
* Purpose: Checks if a data transform will be performed
|
|
*
|
|
* Return: TRUE for no data transform, FALSE for a data transform
|
|
*
|
|
* Programmer: Quincey Koziol
|
|
*
|
|
* Date: May 4, 2004
|
|
*
|
|
* Comments: Can't fail
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
hbool_t
|
|
H5Z_xform_noop(const H5Z_data_xform_t *data_xform_prop)
|
|
{
|
|
hbool_t ret_value = TRUE; /* Return value */
|
|
|
|
FUNC_ENTER_NOAPI_NOINIT_NOERR
|
|
|
|
if (data_xform_prop) {
|
|
ret_value = FALSE;
|
|
|
|
/* Check for trivial data transformation: expression = "x" */
|
|
if ((HDstrlen(data_xform_prop->xform_exp) == 1) && data_xform_prop->dat_val_pointers &&
|
|
(data_xform_prop->dat_val_pointers->num_ptrs == 1)) {
|
|
ret_value = TRUE;
|
|
} /* end if */
|
|
} /* end if */
|
|
|
|
FUNC_LEAVE_NOAPI(ret_value)
|
|
} /* H5Z_xform_noop() */
|
|
|
|
/*-------------------------------------------------------------------------
|
|
* Function: H5Z_xform_extract_xform_str
|
|
*
|
|
* Purpose: Extracts the pointer to the data transform strings from the
|
|
* data transform property.`
|
|
* Return:
|
|
* Pointer to a copy of the string in the data_xform property.
|
|
*
|
|
* Programmer: Leon Arber
|
|
*
|
|
* Date: Sept. 4, 2004
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
const char *
|
|
H5Z_xform_extract_xform_str(const H5Z_data_xform_t *data_xform_prop)
|
|
{
|
|
FUNC_ENTER_NOAPI_NOINIT_NOERR
|
|
|
|
/* There should be no way that this can be NULL since the function
|
|
* that calls this one checks to make sure it isn't before
|
|
* passing them */
|
|
HDassert(data_xform_prop);
|
|
|
|
FUNC_LEAVE_NOAPI(data_xform_prop->xform_exp)
|
|
} /* H5Z_xform_extract_xform_str() */
|