#ifndef GENERICHASH_H
#define GENERICHASH_H
#include <stdio.h>
#include <errno.h>
#include <genericStack.h>
#include <genericHash/cloak.h>
/* A hash is nothing else but a generic stack of generic stacks */
typedef int (*genericHashKeyIndFunction_t)(void *userDatavp, genericStackItemType_t itemType, void **pp);
typedef short (*genericHashKeyCmpFunction_t)(void *userDatavp, void **pp1, void **pp2);
typedef void *(*genericHashKeyCopyFunction_t)(void *userDatavp, void **pp);
typedef void (*genericHashKeyFreeFunction_t)(void *userDatavp, void **pp);
typedef void *(*genericHashValCopyFunction_t)(void *userDatavp, void **pp);
typedef void (*genericHashValFreeFunction_t)(void *userDatavp, void **pp);
typedef struct genericHash {
int wantedSubSize;
genericHashKeyIndFunction_t keyIndFunctionp;
genericHashKeyCmpFunction_t keyCmpFunctionp;
genericHashKeyCopyFunction_t keyCopyFunctionp;
genericHashKeyFreeFunction_t keyFreeFunctionp;
genericHashValCopyFunction_t valCopyFunctionp;
genericHashValFreeFunction_t valFreeFunctionp;
/* keyStackp and valStackp leave in parallel */
genericStack_t keyStack;
genericStack_t *keyStackp;
genericStack_t valStack;
genericStack_t *valStackp;
int used;
short error;
} genericHash_t;
/* ====================================================================== */
/* Error detection */
/* ====================================================================== */
#define GENERICHASH_ERROR(hashName) ((hashName == NULL) || (hashName->error != 0))
/* ====================================================================== */
/* For getters and setters */
/* ====================================================================== */
#define GENERICHASH_KEYCMPFUNCTION(hashName) hashName->keyCmpFunctionp
#define GENERICHASH_KEYCOPYFUNCTION(hashName) hashName->keyCopyFunctionp
#define GENERICHASH_KEYFREEFUNCTION(hashName) hashName->keyFreeFunctionp
#define GENERICHASH_VALCOPYFUNCTION(hashName) hashName->valCopyFunctionp
#define GENERICHASH_VALFREEFUNCTION(hashName) hashName->valFreeFunctionp
/* ====================================================================== */
/* Initialization */
/* */
/* wantedSize is an estimated number of rows in the hash */
/* index and comparison function pointers are mandatory. */
/* thisWantedSize is an estimated number of rows in every hash's row */
/* ====================================================================== */
#define GENERICHASH_NEW_ALL(hashName, thisKeyIndFunctionp, thisKeyCmpFunctionp, thisKeyCopyFunctionp, thisKeyFreeFunctionp, thisValCopyFunctionp, thisValFreeFunctionp, wantedSize, thisWantedSubSize) do { \
genericHashKeyIndFunction_t _keyIndFunctionp = (genericHashKeyIndFunction_t) (thisKeyIndFunctionp); \
genericHashKeyCmpFunction_t _keyCmpFunctionp = (genericHashKeyCmpFunction_t) (thisKeyCmpFunctionp); \
genericHashKeyCopyFunction_t _keyCopyFunctionp = (genericHashKeyCopyFunction_t) (thisKeyCopyFunctionp); \
genericHashKeyFreeFunction_t _keyFreeFunctionp = (genericHashKeyFreeFunction_t) (thisKeyFreeFunctionp); \
genericHashValCopyFunction_t _valCopyFunctionp = (genericHashValCopyFunction_t) (thisValCopyFunctionp); \
genericHashValFreeFunction_t _valFreeFunctionp = (genericHashValFreeFunction_t) (thisValFreeFunctionp); \
\
if (_keyIndFunctionp == NULL) { \
hashName = NULL; \
} else { \
hashName = malloc(sizeof(genericHash_t)); \
if (hashName != NULL) { \
hashName->wantedSubSize = (thisWantedSubSize); \
hashName->keyIndFunctionp = _keyIndFunctionp; \
hashName->keyCmpFunctionp = _keyCmpFunctionp; \
hashName->keyCopyFunctionp = _keyCopyFunctionp; \
hashName->keyFreeFunctionp = _keyFreeFunctionp; \
hashName->valCopyFunctionp = _valCopyFunctionp; \
hashName->valFreeFunctionp = _valFreeFunctionp; \
hashName->error = 0; \
hashName->used = 0; \
\
hashName->keyStackp = &(hashName->keyStack); \
GENERICSTACK_INIT_SIZED(hashName->keyStackp, wantedSize); \
if (GENERICSTACK_ERROR(hashName->keyStackp)) { \
free(hashName); \
hashName = NULL; \
} else { \
hashName->valStackp = &(hashName->valStack); \
GENERICSTACK_INIT_SIZED(hashName->valStackp, wantedSize); \
if (GENERICSTACK_ERROR(hashName->valStackp)) { \
GENERICSTACK_RESET(hashName->keyStackp); \
free(hashName); \
hashName = NULL; \
} \
} \
} \
} \
} while (0)
#define GENERICHASH_INIT_ALL(hashName, thisKeyIndFunctionp, thisKeyCmpFunctionp, thisKeyCopyFunctionp, thisKeyFreeFunctionp, thisValCopyFunctionp, thisValFreeFunctionp, wantedSize, thisWantedSubSize) do { \
genericHashKeyIndFunction_t _keyIndFunctionp = (genericHashKeyIndFunction_t) (thisKeyIndFunctionp); \
genericHashKeyCmpFunction_t _keyCmpFunctionp = (genericHashKeyCmpFunction_t) (thisKeyCmpFunctionp); \
genericHashKeyCopyFunction_t _keyCopyFunctionp = (genericHashKeyCopyFunction_t) (thisKeyCopyFunctionp); \
genericHashKeyFreeFunction_t _keyFreeFunctionp = (genericHashKeyFreeFunction_t) (thisKeyFreeFunctionp); \
genericHashValCopyFunction_t _valCopyFunctionp = (genericHashValCopyFunction_t) (thisValCopyFunctionp); \
genericHashValFreeFunction_t _valFreeFunctionp = (genericHashValFreeFunction_t) (thisValFreeFunctionp); \
\
hashName->error = 0; \
hashName->used = 0; \
\
if (_keyIndFunctionp == NULL) { \
hashName->error = 1; \
} else { \
hashName->wantedSubSize = (thisWantedSubSize); \
hashName->keyIndFunctionp = _keyIndFunctionp; \
hashName->keyCmpFunctionp = _keyCmpFunctionp; \
hashName->keyCopyFunctionp = _keyCopyFunctionp; \
hashName->keyFreeFunctionp = _keyFreeFunctionp; \
hashName->valCopyFunctionp = _valCopyFunctionp; \
hashName->valFreeFunctionp = _valFreeFunctionp; \
\
hashName->keyStackp = &(hashName->keyStack); \
GENERICSTACK_INIT_SIZED(hashName->keyStackp, wantedSize); \
if (GENERICSTACK_ERROR(hashName->keyStackp)) { \
hashName->error = 1; \
} else { \
hashName->valStackp = &(hashName->valStack); \
GENERICSTACK_INIT_SIZED(hashName->valStackp, wantedSize); \
if (GENERICSTACK_ERROR(hashName->valStackp)) { \
GENERICSTACK_RESET(hashName->keyStackp); \
hashName->error = 1; \
} \
} \
} \
} while (0)
#define GENERICHASH_NEW(hashName, thisKeyIndFunctionp) GENERICHASH_NEW_ALL(hashName, thisKeyIndFunctionp, NULL, NULL, NULL, NULL, NULL, 0, 0)
#define GENERICHASH_INIT(hashName, thisKeyIndFunctionp) GENERICHASH_INIT_ALL(hashName, thisKeyIndFunctionp, NULL, NULL, NULL, NULL, NULL, 0, 0)
/* ====================================================================== */
/* Usage. Take care alos this is an lvalue, this must never be modified. */
/* ====================================================================== */
#define GENERICHASH_USED(hashName) (hashName)->used
/* ====================================================================== */
/* Copy key/value to internal variables */
/* ====================================================================== */
/* We use the cloak hacks to prevent unnecessary code generation */
#define GENERICHASH_COMPARE_PTR(x) x
#define _GENERICHASH_COPY(hashName, userDatavp, keyType, keyVal, keyValCopy, valType, valVal, valValCopy) do { \
\
GENERICHASH_IIF(GENERICHASH_EQUAL(keyType, PTR)) ( \
if (hashName->keyCopyFunctionp != NULL) { \
GENERICSTACKITEMTYPE2TYPE_##keyType _keyValForCopy = (keyVal); \
GENERICSTACKITEMTYPE2TYPE_##keyType _p = hashName->keyCopyFunctionp((void *) userDatavp, &_keyValForCopy); \
if ((_keyValForCopy != NULL) && (_p == NULL)) { \
hashName->error = 1; \
} else { \
keyValCopy = _p; \
} \
} else { \
keyValCopy = keyVal; \
} \
, \
keyValCopy = keyVal; \
) \
GENERICHASH_IIF(GENERICHASH_EQUAL(valType, PTR)) ( \
if (hashName->valCopyFunctionp != NULL) { \
GENERICSTACKITEMTYPE2TYPE_##valType _valValForCopy = (valVal); \
GENERICSTACKITEMTYPE2TYPE_##valType _p = hashName->valCopyFunctionp((void *) userDatavp, &_valValForCopy); \
if ((_valValForCopy != NULL) && (_p == NULL)) { \
hashName->error = 1; \
} else { \
valValCopy = _p; \
} \
} else { \
valValCopy = valVal; \
} \
, \
valValCopy = valVal; \
) \
} while (0)
/* ====================================================================== */
/* Push internal variables in the hash */
/* ====================================================================== */
#define _GENERICHASH_PUSH(hashName, userDatavp, keyType, keyVal, valType, valVal, subKeyStackp, subValStackp) do { \
GENERICSTACKITEMTYPE2TYPE_##keyType _keyValCopy; \
GENERICSTACKITEMTYPE2TYPE_##valType _valValCopy; \
\
_GENERICHASH_COPY(hashName, userDatavp, keyType, keyVal, _keyValCopy, valType, valVal, _valValCopy); \
if (hashName->error == 0) { \
GENERICSTACK_PUSH_##keyType(subKeyStackp, _keyValCopy); \
GENERICSTACK_PUSH_##valType(subValStackp, _valValCopy); \
if (GENERICSTACK_ERROR(subKeyStackp) || GENERICSTACK_ERROR(subValStackp)) { \
hashName->error = 1; \
} else { \
hashName->used++; \
} \
} \
} while (0)
/* ====================================================================== */
/* Set internal variables in the hash */
/* ====================================================================== */
#define _GENERICHASH_SET(hashName, userDatavp, keyType, keyVal, valType, valVal, subKeyStackp, subValStackp, index) do { \
GENERICSTACKITEMTYPE2TYPE_##keyType _keyValCopy; \
GENERICSTACKITEMTYPE2TYPE_##valType _valValCopy; \
\
_GENERICHASH_COPY(hashName, userDatavp, keyType, keyVal, _keyValCopy, valType, valVal, _valValCopy); \
if (hashName->error == 0) { \
GENERICSTACK_SET_##keyType(subKeyStackp, _keyValCopy, index); \
GENERICSTACK_SET_##valType(subValStackp, _valValCopy, index); \
if (GENERICSTACK_ERROR(subKeyStackp) || GENERICSTACK_ERROR(subValStackp)) { \
hashName->error = 1; \
} \
} \
} while (0)
/* ====================================================================== */
/* Set external variables in the hash */
/* ====================================================================== */
#define GENERICHASH_SET(hashName, userDatavp, keyType, keyVal, valType, valVal) do { \
GENERICSTACKITEMTYPE2TYPE_##keyType _keyVal = (GENERICSTACKITEMTYPE2TYPE_##keyType) (keyVal); \
int _subStackIndex = hashName->keyIndFunctionp((void *) userDatavp, GENERICSTACKITEMTYPE_##keyType, (void **) &_keyVal); \
\
GENERICHASH_SET_BY_IND(hashName, userDatavp, keyType, keyVal, valType, valVal, _subStackIndex); \
} while (0)
#define GENERICHASH_SET_BY_IND(hashName, userDatavp, keyType, keyVal, valType, valVal, subStackIndex) do { \
GENERICSTACKITEMTYPE2TYPE_##keyType _keyVal = (GENERICSTACKITEMTYPE2TYPE_##keyType) (keyVal); \
hashName->error = 0; \
\
if (subStackIndex < 0 ) { \
errno = EINVAL; \
hashName->error = 1; \
} else { \
GENERICSTACKITEMTYPE2TYPE_##valType _valVal = (GENERICSTACKITEMTYPE2TYPE_##valType) (valVal); \
if ((subStackIndex >= GENERICSTACK_USED(hashName->keyStackp)) || \
(subStackIndex >= GENERICSTACK_USED(hashName->valStackp)) || \
(GENERICSTACKITEMTYPE(hashName->keyStackp, subStackIndex) != GENERICSTACKITEMTYPE_PTR) || \
(GENERICSTACKITEMTYPE(hashName->valStackp, subStackIndex) != GENERICSTACKITEMTYPE_PTR)) { \
genericStack_t *_subKeyStackp; \
genericStack_t *_subValStackp; \
\
GENERICSTACK_NEW_SIZED(_subKeyStackp, hashName->wantedSubSize); \
GENERICSTACK_NEW_SIZED(_subValStackp, hashName->wantedSubSize); \
if (GENERICSTACK_ERROR(_subKeyStackp) || GENERICSTACK_ERROR(_subValStackp)) { \
GENERICSTACK_FREE(_subKeyStackp); \
GENERICSTACK_FREE(_subValStackp); \
hashName->error = 1; \
} else { \
GENERICSTACK_SET_PTR(hashName->keyStackp, _subKeyStackp, subStackIndex); \
GENERICSTACK_SET_PTR(hashName->valStackp, _subValStackp, subStackIndex); \
if (GENERICSTACK_ERROR(hashName->keyStackp) || GENERICSTACK_ERROR(hashName->valStackp)) { \
GENERICSTACK_FREE(_subKeyStackp); \
GENERICSTACK_FREE(_subValStackp); \
GENERICSTACK_SET_NA(hashName->keyStackp, subStackIndex); \
GENERICSTACK_SET_NA(hashName->valStackp, subStackIndex); \
hashName->error = 1; \
} else { \
_GENERICHASH_PUSH(hashName, userDatavp, keyType, _keyVal, valType, _valVal, _subKeyStackp, _subValStackp); \
} \
} \
} else { \
genericStack_t *_subKeyStackp = (genericStack_t *) GENERICSTACK_GET_PTR(hashName->keyStackp, subStackIndex); \
genericStack_t *_subValStackp = (genericStack_t *) GENERICSTACK_GET_PTR(hashName->valStackp, subStackIndex); \
int _subStackused = GENERICSTACK_USED(_subKeyStackp); \
int _i; \
\
for (_i = 0; _i < _subStackused; _i++) { \
GENERICSTACKITEMTYPE2TYPE_##keyType _gotKeyVal; \
if ((GENERICSTACKITEMTYPE(_subKeyStackp, _i) != GENERICSTACKITEMTYPE_##keyType)) { \
continue; \
} \
\
_gotKeyVal = GENERICSTACK_GET_##keyType(_subKeyStackp, _i); \
GENERICHASH_IIF(GENERICHASH_EQUAL(keyType, PTR)) ( \
if (hashName->keyCmpFunctionp != NULL) { \
if (! hashName->keyCmpFunctionp((void *) userDatavp, &_keyVal, &_gotKeyVal)) { \
continue; \
} \
} else { \
if (_keyVal != _gotKeyVal) { \
continue; \
} \
} \
, \
if (_keyVal != _gotKeyVal) { \
continue; \
} \
) \
\
GENERICHASH_IIF(GENERICHASH_EQUAL(keyType, PTR)) ( \
if ((_gotKeyVal != NULL) && (hashName->keyFreeFunctionp != NULL)) { \
hashName->keyFreeFunctionp((void *) userDatavp, &_gotKeyVal); \
} \
, \
) \
if ((GENERICSTACKITEMTYPE(_subValStackp, _i) == GENERICSTACKITEMTYPE_PTR)) { \
GENERICSTACKITEMTYPE2TYPE_PTR _gotValVal = GENERICSTACK_GET_PTR(_subValStackp, _i); \
if ((_gotValVal != NULL) && (hashName->valFreeFunctionp != NULL)) { \
hashName->valFreeFunctionp((void *) userDatavp, &_gotValVal); \
} \
} \
\
_GENERICHASH_SET(hashName, userDatavp, keyType, _keyVal, valType, _valVal, _subKeyStackp, _subValStackp, _i); \
break; \
} \
if (_i >= _subStackused) { \
_GENERICHASH_PUSH(hashName, userDatavp, keyType, _keyVal, valType, _valVal, _subKeyStackp, _subValStackp); \
} \
} \
} \
} while (0)
/* ====================================================================== */
/* Find and eventually remove in the hash */
/* ====================================================================== */
#define _GENERICHASH_FIND_REMOVE(hashName, userDatavp, keyType, keyVal, valType, valValp, findResult, remove) do { \
\
if (hashName->keyIndFunctionp == NULL) { \
errno = EINVAL; \
hashName->error = 1; \
} else { \
int _subStackIndex = hashName->keyIndFunctionp((void *) userDatavp, GENERICSTACKITEMTYPE_##keyType, (void **) &keyVal); \
_GENERICHASH_FIND_REMOVE_BY_IND(hashName, userDatavp, keyType, keyVal, valType, valValp, findResult, _subStackIndex, remove); \
} \
} while (0)
#define _GENERICHASH_FIND_REMOVE_BY_IND(hashName, userDatavp, keyType, keyVal, valType, valValp, findResult, _subStackIndex, remove) do { \
\
if (_subStackIndex < 0) { \
errno = EINVAL; \
hashName->error = 1; \
} else { \
findResult = 0; \
\
if ((_subStackIndex < GENERICSTACK_USED(hashName->keyStackp)) \
&& \
(GENERICSTACKITEMTYPE(hashName->keyStackp, _subStackIndex) == GENERICSTACKITEMTYPE_PTR)) { \
genericStack_t *_subKeyStackp = (genericStack_t *) GENERICSTACK_GET_PTR(hashName->keyStackp, _subStackIndex); \
genericStack_t *_subValStackp = (genericStack_t *) GENERICSTACK_GET_PTR(hashName->valStackp, _subStackIndex); \
int _subStackused = GENERICSTACK_USED(_subKeyStackp); \
int _i; \
\
for (_i = 0; _i < _subStackused; _i++) { \
GENERICSTACKITEMTYPE2TYPE_##keyType _gotKeyVal; \
\
if ((GENERICSTACKITEMTYPE(_subKeyStackp, _i) != GENERICSTACKITEMTYPE_##keyType)) { \
continue; \
} \
\
_gotKeyVal = GENERICSTACK_GET_##keyType(_subKeyStackp, _i); \
GENERICHASH_IIF(GENERICHASH_EQUAL(keyType, PTR)) ( \
if ((GENERICSTACKITEMTYPE_##keyType == GENERICSTACKITEMTYPE_PTR) && (hashName->keyCmpFunctionp != NULL)) { \
if (! hashName->keyCmpFunctionp((void *) userDatavp, (void **) &keyVal, (void **) &_gotKeyVal)) { \
continue; \
} \
} else { \
if (keyVal != _gotKeyVal) { \
continue; \
} \
} \
, \
if (keyVal != _gotKeyVal) { \
continue; \
} \
) \
findResult = 1; \
\
if ((valValp) != NULL) { \
GENERICSTACKITEMTYPE2TYPE_##valType *_valValp = (GENERICSTACKITEMTYPE2TYPE_##valType *) (valValp); \
*_valValp = GENERICSTACK_GET_##valType(_subValStackp, _i); \
} \
if (remove) { \
GENERICHASH_IIF(GENERICHASH_EQUAL(keyType, PTR)) ( \
if ((_gotKeyVal != NULL) && (hashName->keyFreeFunctionp != NULL)) { \
hashName->keyFreeFunctionp((void *) userDatavp, &_gotKeyVal); \
} \
, \
) \
GENERICSTACK_SET_NA(_subKeyStackp, _i); \
GENERICSTACK_SWITCH(_subKeyStackp, _i, -1); \
GENERICSTACK_POP_NA(_subKeyStackp); \
\
if ((valValp) == NULL) { \
if ((GENERICSTACKITEMTYPE(_subValStackp, _i) == GENERICSTACKITEMTYPE_PTR) && (hashName->valFreeFunctionp == NULL)) { \
GENERICSTACKITEMTYPE2TYPE_PTR _valVal = GENERICSTACK_GET_PTR(_subValStackp, _i); \
if (_valVal != NULL) { \
hashName->valFreeFunctionp((void *) userDatavp, &_valVal); \
} \
} \
} \
GENERICSTACK_SET_NA(_subValStackp, _i); \
GENERICSTACK_SWITCH(_subValStackp, _i, -1); \
GENERICSTACK_POP_NA(_subValStackp); \
hashName->used--; \
} \
break; \
} \
} \
} \
} while (0)
#define GENERICHASH_FIND(hashName, userDatavp, keyType, keyVal, valType, valValp, findResult) _GENERICHASH_FIND_REMOVE(hashName, userDatavp, keyType, keyVal, valType, valValp, findResult, 0)
#define GENERICHASH_REMOVE(hashName, userDatavp, keyType, keyVal, valType, valValp, findResult) _GENERICHASH_FIND_REMOVE(hashName, userDatavp, keyType, keyVal, valType, valValp, findResult, 1)
#define GENERICHASH_FIND_BY_IND(hashName, userDatavp, keyType, keyVal, valType, valValp, findResult, index) _GENERICHASH_FIND_REMOVE_BY_IND(hashName, userDatavp, keyType, keyVal, valType, valValp, findResult, index, 0)
#define GENERICHASH_REMOVE_BY_IND(hashName, userDatavp, keyType, keyVal, valType, valValp, findResult, index) _GENERICHASH_FIND_REMOVE_BY_IND(hashName, userDatavp, keyType, keyVal, valType, valValp, findResult, index, 1)
/* ====================================================================== */
/* Memory release */
/* ====================================================================== */
#define _GENERICHASH_INTERNAL_RESET(hashName, userDatavp, resetmode) do { \
int _usedl = GENERICSTACK_USED(hashName->keyStackp); \
int _i; \
for (_i = 0; _i < _usedl; _i++) { \
if ((GENERICSTACKITEMTYPE(hashName->keyStackp, _i) == GENERICSTACKITEMTYPE_PTR) && \
(GENERICSTACKITEMTYPE(hashName->valStackp, _i) == GENERICSTACKITEMTYPE_PTR)) { \
genericStack_t *_subKeyStackp = (genericStack_t *) GENERICSTACK_GET_PTR(hashName->keyStackp, _i); \
genericStack_t *_subValStackp = (genericStack_t *) GENERICSTACK_GET_PTR(hashName->valStackp, _i); \
int _subStackused = GENERICSTACK_USED(_subKeyStackp); \
int _j; \
\
for (_j = 0; _j < _subStackused; _j++) { \
if ((GENERICSTACKITEMTYPE(_subKeyStackp, _j) == GENERICSTACKITEMTYPE_PTR) && (hashName->keyFreeFunctionp != NULL)) { \
GENERICSTACKITEMTYPE2TYPE_PTR _keyValp = GENERICSTACK_GET_PTR(_subKeyStackp, _j); \
if (_keyValp != NULL) { \
hashName->keyFreeFunctionp(userDatavp, &_keyValp); \
} \
} \
if ((GENERICSTACKITEMTYPE(_subValStackp, _j) == GENERICSTACKITEMTYPE_PTR) && (hashName->valFreeFunctionp != NULL)) { \
GENERICSTACKITEMTYPE2TYPE_PTR _valValp = GENERICSTACK_GET_PTR(_subValStackp, _j); \
if (_valValp != NULL) { \
hashName->valFreeFunctionp(userDatavp, &_valValp); \
} \
} \
} \
GENERICSTACK_FREE(_subKeyStackp); \
GENERICSTACK_FREE(_subValStackp); \
} \
} \
if (resetmode) { \
GENERICSTACK_RESET(hashName->keyStackp); \
GENERICSTACK_RESET(hashName->valStackp); \
} else { \
GENERICSTACK_USED(hashName->keyStackp) = 0; \
GENERICSTACK_USED(hashName->valStackp) = 0; \
} \
\
hashName->error = 0; \
hashName->used = 0; \
} while (0)
#define GENERICHASH_RESET(hashName, userDatavp) _GENERICHASH_INTERNAL_RESET(hashName, userDatavp, 1)
#define GENERICHASH_RELAX(hashName, userDatavp) _GENERICHASH_INTERNAL_RESET(hashName, userDatavp, 0)
#define GENERICHASH_FREE(hashName, userDatavp) do { \
if (hashName != NULL) { \
GENERICHASH_RESET(hashName, userDatavp); \
free(hashName); \
hashName = NULL; \
} \
} while (0)
#endif /* GENERICHASH_H */