hdf5/src/H5Ztrans.c
Scot Breitenfeld f859cb732b
Fixed Spelling Errors (#1166)
* 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>
2021-12-07 08:27:29 -06:00

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() */