Browse Source

Update uthash to version 2.1.0

pull/128/head
emanuele-f 5 years ago
parent
commit
b5c59c0e56
  1. 540
      uthash.h

540
uthash.h

@ -1,5 +1,5 @@
/* /*
Copyright (c) 2003-2017, Troy D. Hanson http://troydhanson.github.com/uthash/ Copyright (c) 2003-2018, Troy D. Hanson http://troydhanson.github.com/uthash/
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -24,31 +24,32 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef UTHASH_H #ifndef UTHASH_H
#define UTHASH_H #define UTHASH_H
#define UTHASH_VERSION 2.0.2 #define UTHASH_VERSION 2.1.0
#include <string.h> /* memcmp,strlen */ #include <string.h> /* memcmp, memset, strlen */
#include <stddef.h> /* ptrdiff_t */ #include <stddef.h> /* ptrdiff_t */
#include <stdlib.h> /* exit() */ #include <stdlib.h> /* exit */
/* These macros use decltype or the earlier __typeof GNU extension. /* These macros use decltype or the earlier __typeof GNU extension.
As decltype is only available in newer compilers (VS2010 or gcc 4.3+ As decltype is only available in newer compilers (VS2010 or gcc 4.3+
when compiling c++ source) this code uses whatever method is needed when compiling c++ source) this code uses whatever method is needed
or, for VS2008 where neither is available, uses casting workarounds. */ or, for VS2008 where neither is available, uses casting workarounds. */
#if !defined(DECLTYPE) && !defined(NO_DECLTYPE)
#if defined(_MSC_VER) /* MS compiler */ #if defined(_MSC_VER) /* MS compiler */
#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ #if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
#define DECLTYPE(x) (decltype(x)) #define DECLTYPE(x) (decltype(x))
#else /* VS2008 or older (or VS2010 in C mode) */ #else /* VS2008 or older (or VS2010 in C mode) */
#define NO_DECLTYPE #define NO_DECLTYPE
#define DECLTYPE(x)
#endif #endif
#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__) #elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__)
#define NO_DECLTYPE #define NO_DECLTYPE
#define DECLTYPE(x)
#else /* GNU, Sun and other compilers */ #else /* GNU, Sun and other compilers */
#define DECLTYPE(x) (__typeof(x)) #define DECLTYPE(x) (__typeof(x))
#endif #endif
#endif
#ifdef NO_DECLTYPE #ifdef NO_DECLTYPE
#define DECLTYPE(x)
#define DECLTYPE_ASSIGN(dst,src) \ #define DECLTYPE_ASSIGN(dst,src) \
do { \ do { \
char **_da_dst = (char**)(&(dst)); \ char **_da_dst = (char**)(&(dst)); \
@ -78,22 +79,30 @@ typedef unsigned int uint32_t;
typedef unsigned char uint8_t; typedef unsigned char uint8_t;
#endif #endif
#ifndef uthash_fatal
#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */
#endif
#ifndef uthash_malloc #ifndef uthash_malloc
#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ #define uthash_malloc(sz) malloc(sz) /* malloc fcn */
#endif #endif
#ifndef uthash_free #ifndef uthash_free
#define uthash_free(ptr,sz) free(ptr) /* free fcn */ #define uthash_free(ptr,sz) free(ptr) /* free fcn */
#endif #endif
#ifndef uthash_bzero
#define uthash_bzero(a,n) memset(a,'\0',n)
#endif
#ifndef uthash_strlen #ifndef uthash_strlen
#define uthash_strlen(s) strlen(s) #define uthash_strlen(s) strlen(s)
#endif #endif
#ifndef uthash_memcmp
#ifdef uthash_memcmp
/* This warning will not catch programs that define uthash_memcmp AFTER including uthash.h. */
#warning "uthash_memcmp is deprecated; please use HASH_KEYCMP instead"
#else
#define uthash_memcmp(a,b,n) memcmp(a,b,n) #define uthash_memcmp(a,b,n) memcmp(a,b,n)
#endif #endif
#ifndef HASH_KEYCMP
#define HASH_KEYCMP(a,b,n) uthash_memcmp(a,b,n)
#endif
#ifndef uthash_noexpand_fyi #ifndef uthash_noexpand_fyi
#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ #define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
#endif #endif
@ -101,6 +110,32 @@ typedef unsigned char uint8_t;
#define uthash_expand_fyi(tbl) /* can be defined to log expands */ #define uthash_expand_fyi(tbl) /* can be defined to log expands */
#endif #endif
#ifndef HASH_NONFATAL_OOM
#define HASH_NONFATAL_OOM 0
#endif
#if HASH_NONFATAL_OOM
/* malloc failures can be recovered from */
#ifndef uthash_nonfatal_oom
#define uthash_nonfatal_oom(obj) do {} while (0) /* non-fatal OOM error */
#endif
#define HASH_RECORD_OOM(oomed) do { (oomed) = 1; } while (0)
#define IF_HASH_NONFATAL_OOM(x) x
#else
/* malloc failures result in lost memory, hash tables are unusable */
#ifndef uthash_fatal
#define uthash_fatal(msg) exit(-1) /* fatal OOM error */
#endif
#define HASH_RECORD_OOM(oomed) uthash_fatal("out of memory")
#define IF_HASH_NONFATAL_OOM(x)
#endif
/* initial number of buckets */ /* initial number of buckets */
#define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS 32U /* initial number of buckets */
#define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */ #define HASH_INITIAL_NUM_BUCKETS_LOG2 5U /* lg2 of initial number of buckets */
@ -111,6 +146,16 @@ typedef unsigned char uint8_t;
/* calculate the hash handle from element address elp */ /* calculate the hash handle from element address elp */
#define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho))) #define HH_FROM_ELMT(tbl,elp) ((UT_hash_handle *)(((char*)(elp)) + ((tbl)->hho)))
#define HASH_ROLLBACK_BKT(hh, head, itemptrhh) \
do { \
struct UT_hash_handle *_hd_hh_item = (itemptrhh); \
unsigned _hd_bkt; \
HASH_TO_BKT(_hd_hh_item->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
(head)->hh.tbl->buckets[_hd_bkt].count++; \
_hd_hh_item->hh_next = NULL; \
_hd_hh_item->hh_prev = NULL; \
} while (0)
#define HASH_VALUE(keyptr,keylen,hashv) \ #define HASH_VALUE(keyptr,keylen,hashv) \
do { \ do { \
HASH_FCN(keyptr, keylen, hashv); \ HASH_FCN(keyptr, keylen, hashv); \
@ -130,21 +175,27 @@ do {
#define HASH_FIND(hh,head,keyptr,keylen,out) \ #define HASH_FIND(hh,head,keyptr,keylen,out) \
do { \ do { \
(out) = NULL; \
if (head) { \
unsigned _hf_hashv; \ unsigned _hf_hashv; \
HASH_VALUE(keyptr, keylen, _hf_hashv); \ HASH_VALUE(keyptr, keylen, _hf_hashv); \
HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \
} \
} while (0) } while (0)
#ifdef HASH_BLOOM #ifdef HASH_BLOOM
#define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM) #define HASH_BLOOM_BITLEN (1UL << HASH_BLOOM)
#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL) #define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8UL) + (((HASH_BLOOM_BITLEN%8UL)!=0UL) ? 1UL : 0UL)
#define HASH_BLOOM_MAKE(tbl) \ #define HASH_BLOOM_MAKE(tbl,oomed) \
do { \ do { \
(tbl)->bloom_nbits = HASH_BLOOM; \ (tbl)->bloom_nbits = HASH_BLOOM; \
(tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \ if (!(tbl)->bloom_bv) { \
memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \ HASH_RECORD_OOM(oomed); \
} else { \
uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
(tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
} \
} while (0) } while (0)
#define HASH_BLOOM_FREE(tbl) \ #define HASH_BLOOM_FREE(tbl) \
@ -156,36 +207,49 @@ do {
#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U))) #define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U)))
#define HASH_BLOOM_ADD(tbl,hashv) \ #define HASH_BLOOM_ADD(tbl,hashv) \
HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U))) HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U)))
#define HASH_BLOOM_TEST(tbl,hashv) \ #define HASH_BLOOM_TEST(tbl,hashv) \
HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1U))) HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U)))
#else #else
#define HASH_BLOOM_MAKE(tbl) #define HASH_BLOOM_MAKE(tbl,oomed)
#define HASH_BLOOM_FREE(tbl) #define HASH_BLOOM_FREE(tbl)
#define HASH_BLOOM_ADD(tbl,hashv) #define HASH_BLOOM_ADD(tbl,hashv)
#define HASH_BLOOM_TEST(tbl,hashv) (1) #define HASH_BLOOM_TEST(tbl,hashv) (1)
#define HASH_BLOOM_BYTELEN 0U #define HASH_BLOOM_BYTELEN 0U
#endif #endif
#define HASH_MAKE_TABLE(hh,head) \ #define HASH_MAKE_TABLE(hh,head,oomed) \
do { \ do { \
(head)->hh.tbl = (UT_hash_table*)uthash_malloc( \ (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \
sizeof(UT_hash_table)); \ if (!(head)->hh.tbl) { \
if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \ HASH_RECORD_OOM(oomed); \
memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \ } else { \
uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \
(head)->hh.tbl->tail = &((head)->hh); \ (head)->hh.tbl->tail = &((head)->hh); \
(head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
(head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
(head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
(head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \ HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \
if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \
memset((head)->hh.tbl->buckets, 0, \
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
HASH_BLOOM_MAKE((head)->hh.tbl); \
(head)->hh.tbl->signature = HASH_SIGNATURE; \ (head)->hh.tbl->signature = HASH_SIGNATURE; \
if (!(head)->hh.tbl->buckets) { \
HASH_RECORD_OOM(oomed); \
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
} else { \
uthash_bzero((head)->hh.tbl->buckets, \
HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \
HASH_BLOOM_MAKE((head)->hh.tbl, oomed); \
IF_HASH_NONFATAL_OOM( \
if (oomed) { \
uthash_free((head)->hh.tbl->buckets, \
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
} \
) \
} \
} \
} while (0) } while (0)
#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ #define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \
@ -230,24 +294,87 @@ do {
(head)->hh.tbl->tail = &((add)->hh); \ (head)->hh.tbl->tail = &((add)->hh); \
} while (0) } while (0)
#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \ #define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \
do { \
do { \
if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) { \
break; \
} \
} while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \
} while (0)
#ifdef NO_DECLTYPE
#undef HASH_AKBI_INNER_LOOP
#define HASH_AKBI_INNER_LOOP(hh,head,add,cmpfcn) \
do { \
char *_hs_saved_head = (char*)(head); \
do { \
DECLTYPE_ASSIGN(head, _hs_iter); \
if (cmpfcn(head, add) > 0) { \
DECLTYPE_ASSIGN(head, _hs_saved_head); \
break; \
} \
DECLTYPE_ASSIGN(head, _hs_saved_head); \
} while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \
} while (0)
#endif
#if HASH_NONFATAL_OOM
#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \
do { \ do { \
if (!(oomed)) { \
unsigned _ha_bkt; \ unsigned _ha_bkt; \
(head)->hh.tbl->num_items++; \
HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \
HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \
if (oomed) { \
HASH_ROLLBACK_BKT(hh, head, &(add)->hh); \
HASH_DELETE_HH(hh, head, &(add)->hh); \
(add)->hh.tbl = NULL; \
uthash_nonfatal_oom(add); \
} else { \
HASH_BLOOM_ADD((head)->hh.tbl, hashval); \
HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \
} \
} else { \
(add)->hh.tbl = NULL; \
uthash_nonfatal_oom(add); \
} \
} while (0)
#else
#define HASH_ADD_TO_TABLE(hh,head,keyptr,keylen_in,hashval,add,oomed) \
do { \
unsigned _ha_bkt; \
(head)->hh.tbl->num_items++; \
HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \
HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], hh, &(add)->hh, oomed); \
HASH_BLOOM_ADD((head)->hh.tbl, hashval); \
HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \
} while (0)
#endif
#define HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh,head,keyptr,keylen_in,hashval,add,cmpfcn) \
do { \
IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \
(add)->hh.hashv = (hashval); \ (add)->hh.hashv = (hashval); \
(add)->hh.key = (char*) (keyptr); \ (add)->hh.key = (char*) (keyptr); \
(add)->hh.keylen = (unsigned) (keylen_in); \ (add)->hh.keylen = (unsigned) (keylen_in); \
if (!(head)) { \ if (!(head)) { \
(add)->hh.next = NULL; \ (add)->hh.next = NULL; \
(add)->hh.prev = NULL; \ (add)->hh.prev = NULL; \
HASH_MAKE_TABLE(hh, add, _ha_oomed); \
IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \
(head) = (add); \ (head) = (add); \
HASH_MAKE_TABLE(hh, head); \ IF_HASH_NONFATAL_OOM( } ) \
} else { \ } else { \
void *_hs_iter = (head); \ void *_hs_iter = (head); \
(add)->hh.tbl = (head)->hh.tbl; \ (add)->hh.tbl = (head)->hh.tbl; \
do { \ HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \
if (cmpfcn(DECLTYPE(head)(_hs_iter), add) > 0) \
break; \
} while ((_hs_iter = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->next)); \
if (_hs_iter) { \ if (_hs_iter) { \
(add)->hh.next = _hs_iter; \ (add)->hh.next = _hs_iter; \
if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \
@ -260,12 +387,8 @@ do {
HASH_APPEND_LIST(hh, head, add); \ HASH_APPEND_LIST(hh, head, add); \
} \ } \
} \ } \
(head)->hh.tbl->num_items++; \ HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \
HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \
HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh); \
HASH_BLOOM_ADD((head)->hh.tbl, hashval); \
HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \
HASH_FSCK(hh, head); \
} while (0) } while (0)
#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ #define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \
@ -283,25 +406,23 @@ do {
#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ #define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \
do { \ do { \
unsigned _ha_bkt; \ IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \
(add)->hh.hashv = (hashval); \ (add)->hh.hashv = (hashval); \
(add)->hh.key = (char*) (keyptr); \ (add)->hh.key = (char*) (keyptr); \
(add)->hh.keylen = (unsigned) (keylen_in); \ (add)->hh.keylen = (unsigned) (keylen_in); \
if (!(head)) { \ if (!(head)) { \
(add)->hh.next = NULL; \ (add)->hh.next = NULL; \
(add)->hh.prev = NULL; \ (add)->hh.prev = NULL; \
HASH_MAKE_TABLE(hh, add, _ha_oomed); \
IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \
(head) = (add); \ (head) = (add); \
HASH_MAKE_TABLE(hh, head); \ IF_HASH_NONFATAL_OOM( } ) \
} else { \ } else { \
(add)->hh.tbl = (head)->hh.tbl; \ (add)->hh.tbl = (head)->hh.tbl; \
HASH_APPEND_LIST(hh, head, add); \ HASH_APPEND_LIST(hh, head, add); \
} \ } \
(head)->hh.tbl->num_items++; \ HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \
HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _ha_bkt); \ HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \
HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt], &(add)->hh); \
HASH_BLOOM_ADD((head)->hh.tbl, hashval); \
HASH_EMIT_KEY(hh, head, keyptr, keylen_in); \
HASH_FSCK(hh, head); \
} while (0) } while (0)
#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
@ -335,48 +456,53 @@ do {
* scratch pointer rather than through the repointed (users) symbol. * scratch pointer rather than through the repointed (users) symbol.
*/ */
#define HASH_DELETE(hh,head,delptr) \ #define HASH_DELETE(hh,head,delptr) \
HASH_DELETE_HH(hh, head, &(delptr)->hh)
#define HASH_DELETE_HH(hh,head,delptrhh) \
do { \ do { \
struct UT_hash_handle *_hd_hh_del; \ struct UT_hash_handle *_hd_hh_del = (delptrhh); \
if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \ if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \
uthash_free((head)->hh.tbl->buckets, \
(head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
HASH_BLOOM_FREE((head)->hh.tbl); \ HASH_BLOOM_FREE((head)->hh.tbl); \
uthash_free((head)->hh.tbl->buckets, \
(head)->hh.tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
head = NULL; \ (head) = NULL; \
} else { \ } else { \
unsigned _hd_bkt; \ unsigned _hd_bkt; \
_hd_hh_del = &((delptr)->hh); \ if (_hd_hh_del == (head)->hh.tbl->tail) { \
if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \ (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \
(head)->hh.tbl->tail = \ } \
(UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \ if (_hd_hh_del->prev != NULL) { \
(head)->hh.tbl->hho); \ HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \
} \
if ((delptr)->hh.prev != NULL) { \
((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \
(head)->hh.tbl->hho))->next = (delptr)->hh.next; \
} else { \ } else { \
DECLTYPE_ASSIGN(head,(delptr)->hh.next); \ DECLTYPE_ASSIGN(head, _hd_hh_del->next); \
} \ } \
if (_hd_hh_del->next != NULL) { \ if (_hd_hh_del->next != NULL) { \
((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \ HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \
(head)->hh.tbl->hho))->prev = \
_hd_hh_del->prev; \
} \ } \
HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
(head)->hh.tbl->num_items--; \ (head)->hh.tbl->num_items--; \
} \ } \
HASH_FSCK(hh,head); \ HASH_FSCK(hh, head, "HASH_DELETE_HH"); \
} while (0) } while (0)
/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ /* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
#define HASH_FIND_STR(head,findstr,out) \ #define HASH_FIND_STR(head,findstr,out) \
HASH_FIND(hh,head,findstr,(unsigned)uthash_strlen(findstr),out) do { \
unsigned _uthash_hfstr_keylen = (unsigned)uthash_strlen(findstr); \
HASH_FIND(hh, head, findstr, _uthash_hfstr_keylen, out); \
} while (0)
#define HASH_ADD_STR(head,strfield,add) \ #define HASH_ADD_STR(head,strfield,add) \
HASH_ADD(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add) do { \
unsigned _uthash_hastr_keylen = (unsigned)uthash_strlen((add)->strfield); \
HASH_ADD(hh, head, strfield[0], _uthash_hastr_keylen, add); \
} while (0)
#define HASH_REPLACE_STR(head,strfield,add,replaced) \ #define HASH_REPLACE_STR(head,strfield,add,replaced) \
HASH_REPLACE(hh,head,strfield[0],(unsigned)uthash_strlen(add->strfield),add,replaced) do { \
unsigned _uthash_hrstr_keylen = (unsigned)uthash_strlen((add)->strfield); \
HASH_REPLACE(hh, head, strfield[0], _uthash_hrstr_keylen, add, replaced); \
} while (0)
#define HASH_FIND_INT(head,findint,out) \ #define HASH_FIND_INT(head,findint,out) \
HASH_FIND(hh,head,findint,sizeof(int),out) HASH_FIND(hh,head,findint,sizeof(int),out)
#define HASH_ADD_INT(head,intfield,add) \ #define HASH_ADD_INT(head,intfield,add) \
@ -397,22 +523,21 @@ do {
*/ */
#ifdef HASH_DEBUG #ifdef HASH_DEBUG
#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) #define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
#define HASH_FSCK(hh,head) \ #define HASH_FSCK(hh,head,where) \
do { \ do { \
struct UT_hash_handle *_thh; \ struct UT_hash_handle *_thh; \
if (head) { \ if (head) { \
unsigned _bkt_i; \ unsigned _bkt_i; \
unsigned _count; \ unsigned _count = 0; \
char *_prev; \ char *_prev; \
_count = 0; \ for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \
for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \
unsigned _bkt_count = 0; \ unsigned _bkt_count = 0; \
_thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
_prev = NULL; \ _prev = NULL; \
while (_thh) { \ while (_thh) { \
if (_prev != (char*)(_thh->hh_prev)) { \ if (_prev != (char*)(_thh->hh_prev)) { \
HASH_OOPS("invalid hh_prev %p, actual %p\n", \ HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \
_thh->hh_prev, _prev ); \ (where), (void*)_thh->hh_prev, (void*)_prev); \
} \ } \
_bkt_count++; \ _bkt_count++; \
_prev = (char*)(_thh); \ _prev = (char*)(_thh); \
@ -420,36 +545,34 @@ do {
} \ } \
_count += _bkt_count; \ _count += _bkt_count; \
if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
HASH_OOPS("invalid bucket count %u, actual %u\n", \ HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \
(head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
} \ } \
} \ } \
if (_count != (head)->hh.tbl->num_items) { \ if (_count != (head)->hh.tbl->num_items) { \
HASH_OOPS("invalid hh item count %u, actual %u\n", \ HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \
(head)->hh.tbl->num_items, _count ); \ (where), (head)->hh.tbl->num_items, _count); \
} \ } \
/* traverse hh in app order; check next/prev integrity, count */ \
_count = 0; \ _count = 0; \
_prev = NULL; \ _prev = NULL; \
_thh = &(head)->hh; \ _thh = &(head)->hh; \
while (_thh) { \ while (_thh) { \
_count++; \ _count++; \
if (_prev !=(char*)(_thh->prev)) { \ if (_prev != (char*)_thh->prev) { \
HASH_OOPS("invalid prev %p, actual %p\n", \ HASH_OOPS("%s: invalid prev %p, actual %p\n", \
_thh->prev, _prev ); \ (where), (void*)_thh->prev, (void*)_prev); \
} \ } \
_prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
_thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \ _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \
(head)->hh.tbl->hho) : NULL ); \
} \ } \
if (_count != (head)->hh.tbl->num_items) { \ if (_count != (head)->hh.tbl->num_items) { \
HASH_OOPS("invalid app item count %u, actual %u\n", \ HASH_OOPS("%s: invalid app item count %u, actual %u\n", \
(head)->hh.tbl->num_items, _count ); \ (where), (head)->hh.tbl->num_items, _count); \
} \ } \
} \ } \
} while (0) } while (0)
#else #else
#define HASH_FSCK(hh,head) #define HASH_FSCK(hh,head,where)
#endif #endif
/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to /* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
@ -476,8 +599,8 @@ do {
/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ /* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
#define HASH_BER(key,keylen,hashv) \ #define HASH_BER(key,keylen,hashv) \
do { \ do { \
unsigned _hb_keylen=(unsigned)keylen; \ unsigned _hb_keylen = (unsigned)keylen; \
const unsigned char *_hb_key=(const unsigned char*)(key); \ const unsigned char *_hb_key = (const unsigned char*)(key); \
(hashv) = 0; \ (hashv) = 0; \
while (_hb_keylen-- != 0U) { \ while (_hb_keylen-- != 0U) { \
(hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \
@ -490,9 +613,9 @@ do {
#define HASH_SAX(key,keylen,hashv) \ #define HASH_SAX(key,keylen,hashv) \
do { \ do { \
unsigned _sx_i; \ unsigned _sx_i; \
const unsigned char *_hs_key=(const unsigned char*)(key); \ const unsigned char *_hs_key = (const unsigned char*)(key); \
hashv = 0; \ hashv = 0; \
for(_sx_i=0; _sx_i < keylen; _sx_i++) { \ for (_sx_i=0; _sx_i < keylen; _sx_i++) { \
hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
} \ } \
} while (0) } while (0)
@ -500,9 +623,9 @@ do {
#define HASH_FNV(key,keylen,hashv) \ #define HASH_FNV(key,keylen,hashv) \
do { \ do { \
unsigned _fn_i; \ unsigned _fn_i; \
const unsigned char *_hf_key=(const unsigned char*)(key); \ const unsigned char *_hf_key = (const unsigned char*)(key); \
hashv = 2166136261U; \ (hashv) = 2166136261U; \
for(_fn_i=0; _fn_i < keylen; _fn_i++) { \ for (_fn_i=0; _fn_i < keylen; _fn_i++) { \
hashv = hashv ^ _hf_key[_fn_i]; \ hashv = hashv ^ _hf_key[_fn_i]; \
hashv = hashv * 16777619U; \ hashv = hashv * 16777619U; \
} \ } \
@ -683,7 +806,7 @@ do { \
const uint8_t *_mur_tail; \ const uint8_t *_mur_tail; \
const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \ const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \
int _mur_i; \ int _mur_i; \
for(_mur_i = -_mur_nblocks; _mur_i!=0; _mur_i++) { \ for (_mur_i = -_mur_nblocks; _mur_i != 0; _mur_i++) { \
_mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \
_mur_k1 *= _mur_c1; \ _mur_k1 *= _mur_c1; \
_mur_k1 = MUR_ROTL32(_mur_k1,15); \ _mur_k1 = MUR_ROTL32(_mur_k1,15); \
@ -695,7 +818,8 @@ do { \
} \ } \
_mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4)); \ _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4)); \
_mur_k1=0; \ _mur_k1=0; \
switch((keylen) & 3U) { \ switch ((keylen) & 3U) { \
case 0: break; \
case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \ case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \
case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8; /* FALLTHROUGH */ \ case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8; /* FALLTHROUGH */ \
case 1: _mur_k1 ^= (uint32_t)_mur_tail[0]; \ case 1: _mur_k1 ^= (uint32_t)_mur_tail[0]; \
@ -720,7 +844,7 @@ do {
} \ } \
while ((out) != NULL) { \ while ((out) != NULL) { \
if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \
if (uthash_memcmp((out)->hh.key, keyptr, keylen_in) == 0) { \ if (HASH_KEYCMP((out)->hh.key, keyptr, keylen_in) == 0) { \
break; \ break; \
} \ } \
} \ } \
@ -733,31 +857,42 @@ do {
} while (0) } while (0)
/* add an item to a bucket */ /* add an item to a bucket */
#define HASH_ADD_TO_BKT(head,addhh) \ #define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \
do { \ do { \
head.count++; \ UT_hash_bucket *_ha_head = &(head); \
(addhh)->hh_next = head.hh_head; \ _ha_head->count++; \
(addhh)->hh_next = _ha_head->hh_head; \
(addhh)->hh_prev = NULL; \ (addhh)->hh_prev = NULL; \
if (head.hh_head != NULL) { (head).hh_head->hh_prev = (addhh); } \ if (_ha_head->hh_head != NULL) { \
(head).hh_head=addhh; \ _ha_head->hh_head->hh_prev = (addhh); \
if ((head.count >= ((head.expand_mult+1U) * HASH_BKT_CAPACITY_THRESH)) \ } \
&& ((addhh)->tbl->noexpand != 1U)) { \ _ha_head->hh_head = (addhh); \
HASH_EXPAND_BUCKETS((addhh)->tbl); \ if ((_ha_head->count >= ((_ha_head->expand_mult + 1U) * HASH_BKT_CAPACITY_THRESH)) \
&& !(addhh)->tbl->noexpand) { \
HASH_EXPAND_BUCKETS(addhh,(addhh)->tbl, oomed); \
IF_HASH_NONFATAL_OOM( \
if (oomed) { \
HASH_DEL_IN_BKT(head,addhh); \
} \
) \
} \ } \
} while (0) } while (0)
/* remove an item from a given bucket */ /* remove an item from a given bucket */
#define HASH_DEL_IN_BKT(hh,head,hh_del) \ #define HASH_DEL_IN_BKT(head,delhh) \
(head).count--; \ do { \
if ((head).hh_head == hh_del) { \ UT_hash_bucket *_hd_head = &(head); \
(head).hh_head = hh_del->hh_next; \ _hd_head->count--; \
if (_hd_head->hh_head == (delhh)) { \
_hd_head->hh_head = (delhh)->hh_next; \
} \ } \
if (hh_del->hh_prev) { \ if ((delhh)->hh_prev) { \
hh_del->hh_prev->hh_next = hh_del->hh_next; \ (delhh)->hh_prev->hh_next = (delhh)->hh_next; \
} \ } \
if (hh_del->hh_next) { \ if ((delhh)->hh_next) { \
hh_del->hh_next->hh_prev = hh_del->hh_prev; \ (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \
} } \
} while (0)
/* Bucket expansion has the effect of doubling the number of buckets /* Bucket expansion has the effect of doubling the number of buckets
* and redistributing the items into the new buckets. Ideally the * and redistributing the items into the new buckets. Ideally the
@ -788,52 +923,56 @@ do {
* ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
* *
*/ */
#define HASH_EXPAND_BUCKETS(tbl) \ #define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \
do { \ do { \
unsigned _he_bkt; \ unsigned _he_bkt; \
unsigned _he_bkt_i; \ unsigned _he_bkt_i; \
struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
_he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \
if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \ if (!_he_new_buckets) { \
memset(_he_new_buckets, 0, \ HASH_RECORD_OOM(oomed); \
2UL * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \ } else { \
tbl->ideal_chain_maxlen = \ uthash_bzero(_he_new_buckets, \
(tbl->num_items >> (tbl->log2_num_buckets+1U)) + \ 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \
(((tbl->num_items & ((tbl->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ (tbl)->ideal_chain_maxlen = \
tbl->nonideal_items = 0; \ ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \
for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \ ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \
{ \ (tbl)->nonideal_items = 0; \
_he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \ for (_he_bkt_i = 0; _he_bkt_i < (tbl)->num_buckets; _he_bkt_i++) { \
_he_thh = (tbl)->buckets[ _he_bkt_i ].hh_head; \
while (_he_thh != NULL) { \ while (_he_thh != NULL) { \
_he_hh_nxt = _he_thh->hh_next; \ _he_hh_nxt = _he_thh->hh_next; \
HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2U, _he_bkt); \ HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \
_he_newbkt = &(_he_new_buckets[ _he_bkt ]); \ _he_newbkt = &(_he_new_buckets[_he_bkt]); \
if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \ if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \
tbl->nonideal_items++; \ (tbl)->nonideal_items++; \
_he_newbkt->expand_mult = _he_newbkt->count / \ if (_he_newbkt->count > _he_newbkt->expand_mult * (tbl)->ideal_chain_maxlen) { \
tbl->ideal_chain_maxlen; \ _he_newbkt->expand_mult++; \
} \
} \ } \
_he_thh->hh_prev = NULL; \ _he_thh->hh_prev = NULL; \
_he_thh->hh_next = _he_newbkt->hh_head; \ _he_thh->hh_next = _he_newbkt->hh_head; \
if (_he_newbkt->hh_head != NULL) { _he_newbkt->hh_head->hh_prev = \ if (_he_newbkt->hh_head != NULL) { \
_he_thh; } \ _he_newbkt->hh_head->hh_prev = _he_thh; \
} \
_he_newbkt->hh_head = _he_thh; \ _he_newbkt->hh_head = _he_thh; \
_he_thh = _he_hh_nxt; \ _he_thh = _he_hh_nxt; \
} \ } \
} \ } \
uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \ uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \
tbl->num_buckets *= 2U; \ (tbl)->num_buckets *= 2U; \
tbl->log2_num_buckets++; \ (tbl)->log2_num_buckets++; \
tbl->buckets = _he_new_buckets; \ (tbl)->buckets = _he_new_buckets; \
tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \ (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \
(tbl->ineff_expands+1U) : 0U; \ ((tbl)->ineff_expands+1U) : 0U; \
if (tbl->ineff_expands > 1U) { \ if ((tbl)->ineff_expands > 1U) { \
tbl->noexpand=1; \ (tbl)->noexpand = 1; \
uthash_noexpand_fyi(tbl); \ uthash_noexpand_fyi(tbl); \
} \ } \
uthash_expand_fyi(tbl); \ uthash_expand_fyi(tbl); \
} \
} while (0) } while (0)
@ -859,72 +998,69 @@ do {
_hs_nmerges++; \ _hs_nmerges++; \
_hs_q = _hs_p; \ _hs_q = _hs_p; \
_hs_psize = 0; \ _hs_psize = 0; \
for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \ for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \
_hs_psize++; \ _hs_psize++; \
_hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ _hs_q = ((_hs_q->next != NULL) ? \
((void*)((char*)(_hs_q->next) + \ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \
(head)->hh.tbl->hho)) : NULL); \ if (_hs_q == NULL) { \
if (! (_hs_q) ) { break; } \ break; \
} \
} \ } \
_hs_qsize = _hs_insize; \ _hs_qsize = _hs_insize; \
while ((_hs_psize > 0U) || ((_hs_qsize > 0U) && (_hs_q != NULL))) {\ while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \
if (_hs_psize == 0U) { \ if (_hs_psize == 0U) { \
_hs_e = _hs_q; \ _hs_e = _hs_q; \
_hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ _hs_q = ((_hs_q->next != NULL) ? \
((void*)((char*)(_hs_q->next) + \ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \
(head)->hh.tbl->hho)) : NULL); \
_hs_qsize--; \ _hs_qsize--; \
} else if ( (_hs_qsize == 0U) || (_hs_q == NULL) ) { \ } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \
_hs_e = _hs_p; \ _hs_e = _hs_p; \
if (_hs_p != NULL){ \ if (_hs_p != NULL) { \
_hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ? \ _hs_p = ((_hs_p->next != NULL) ? \
((void*)((char*)(_hs_p->next) + \ HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \
(head)->hh.tbl->hho)) : NULL); \
} \ } \
_hs_psize--; \ _hs_psize--; \
} else if (( \ } else if ((cmpfcn( \
cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \
DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \ DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \
) <= 0) { \ )) <= 0) { \
_hs_e = _hs_p; \ _hs_e = _hs_p; \
if (_hs_p != NULL){ \ if (_hs_p != NULL) { \
_hs_p = (UT_hash_handle*)((_hs_p->next != NULL) ? \ _hs_p = ((_hs_p->next != NULL) ? \
((void*)((char*)(_hs_p->next) + \ HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \
(head)->hh.tbl->hho)) : NULL); \
} \ } \
_hs_psize--; \ _hs_psize--; \
} else { \ } else { \
_hs_e = _hs_q; \ _hs_e = _hs_q; \
_hs_q = (UT_hash_handle*)((_hs_q->next != NULL) ? \ _hs_q = ((_hs_q->next != NULL) ? \
((void*)((char*)(_hs_q->next) + \ HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \
(head)->hh.tbl->hho)) : NULL); \
_hs_qsize--; \ _hs_qsize--; \
} \ } \
if ( _hs_tail != NULL ) { \ if ( _hs_tail != NULL ) { \
_hs_tail->next = ((_hs_e != NULL) ? \ _hs_tail->next = ((_hs_e != NULL) ? \
ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \ ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \
} else { \ } else { \
_hs_list = _hs_e; \ _hs_list = _hs_e; \
} \ } \
if (_hs_e != NULL) { \ if (_hs_e != NULL) { \
_hs_e->prev = ((_hs_tail != NULL) ? \ _hs_e->prev = ((_hs_tail != NULL) ? \
ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \ ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \
} \ } \
_hs_tail = _hs_e; \ _hs_tail = _hs_e; \
} \ } \
_hs_p = _hs_q; \ _hs_p = _hs_q; \
} \ } \
if (_hs_tail != NULL){ \ if (_hs_tail != NULL) { \
_hs_tail->next = NULL; \ _hs_tail->next = NULL; \
} \ } \
if ( _hs_nmerges <= 1U ) { \ if (_hs_nmerges <= 1U) { \
_hs_looping=0; \ _hs_looping = 0; \
(head)->hh.tbl->tail = _hs_tail; \ (head)->hh.tbl->tail = _hs_tail; \
DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
} \ } \
_hs_insize *= 2U; \ _hs_insize *= 2U; \
} \ } \
HASH_FSCK(hh,head); \ HASH_FSCK(hh, head, "HASH_SRT"); \
} \ } \
} while (0) } while (0)
@ -936,54 +1072,74 @@ do {
#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
do { \ do { \
unsigned _src_bkt, _dst_bkt; \ unsigned _src_bkt, _dst_bkt; \
void *_last_elt=NULL, *_elt; \ void *_last_elt = NULL, *_elt; \
UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \
ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \
if (src != NULL) { \ if ((src) != NULL) { \
for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \ for (_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \ for (_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \
_src_hh != NULL; \ _src_hh != NULL; \
_src_hh = _src_hh->hh_next) { \ _src_hh = _src_hh->hh_next) { \
_elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
if (cond(_elt)) { \ if (cond(_elt)) { \
IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \
_dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \
_dst_hh->key = _src_hh->key; \ _dst_hh->key = _src_hh->key; \
_dst_hh->keylen = _src_hh->keylen; \ _dst_hh->keylen = _src_hh->keylen; \
_dst_hh->hashv = _src_hh->hashv; \ _dst_hh->hashv = _src_hh->hashv; \
_dst_hh->prev = _last_elt; \ _dst_hh->prev = _last_elt; \
_dst_hh->next = NULL; \ _dst_hh->next = NULL; \
if (_last_elt_hh != NULL) { _last_elt_hh->next = _elt; } \ if (_last_elt_hh != NULL) { \
if (dst == NULL) { \ _last_elt_hh->next = _elt; \
DECLTYPE_ASSIGN(dst,_elt); \ } \
HASH_MAKE_TABLE(hh_dst,dst); \ if ((dst) == NULL) { \
DECLTYPE_ASSIGN(dst, _elt); \
HASH_MAKE_TABLE(hh_dst, dst, _hs_oomed); \
IF_HASH_NONFATAL_OOM( \
if (_hs_oomed) { \
uthash_nonfatal_oom(_elt); \
(dst) = NULL; \
continue; \
} \
) \
} else { \ } else { \
_dst_hh->tbl = (dst)->hh_dst.tbl; \ _dst_hh->tbl = (dst)->hh_dst.tbl; \
} \ } \
HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \ HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \
(dst)->hh_dst.tbl->num_items++; \ (dst)->hh_dst.tbl->num_items++; \
IF_HASH_NONFATAL_OOM( \
if (_hs_oomed) { \
HASH_ROLLBACK_BKT(hh_dst, dst, _dst_hh); \
HASH_DELETE_HH(hh_dst, dst, _dst_hh); \
_dst_hh->tbl = NULL; \
uthash_nonfatal_oom(_elt); \
continue; \
} \
) \
HASH_BLOOM_ADD(_dst_hh->tbl, _dst_hh->hashv); \
_last_elt = _elt; \ _last_elt = _elt; \
_last_elt_hh = _dst_hh; \ _last_elt_hh = _dst_hh; \
} \ } \
} \ } \
} \ } \
} \ } \
HASH_FSCK(hh_dst,dst); \ HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \
} while (0) } while (0)
#define HASH_CLEAR(hh,head) \ #define HASH_CLEAR(hh,head) \
do { \ do { \
if (head != NULL) { \ if ((head) != NULL) { \
HASH_BLOOM_FREE((head)->hh.tbl); \
uthash_free((head)->hh.tbl->buckets, \ uthash_free((head)->hh.tbl->buckets, \
(head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \ (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \
HASH_BLOOM_FREE((head)->hh.tbl); \
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \ uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
(head)=NULL; \ (head) = NULL; \
} \ } \
} while (0) } while (0)
#define HASH_OVERHEAD(hh,head) \ #define HASH_OVERHEAD(hh,head) \
((head != NULL) ? ( \ (((head) != NULL) ? ( \
(size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \
((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \
sizeof(UT_hash_table) + \ sizeof(UT_hash_table) + \

Loading…
Cancel
Save