From 4d7f41980a32fdfef4215a8e009c760b5c17b004 Mon Sep 17 00:00:00 2001 From: bolvan Date: Sun, 22 Jul 2018 22:27:28 +0300 Subject: [PATCH] strpool moved to uthash --- binaries/armhf/tpws | Bin 58488 -> 62584 bytes binaries/mips32r1-lsb/tpws | Bin 102556 -> 106892 bytes binaries/mips32r1-msb/tpws | Bin 87936 -> 95824 bytes binaries/x86/tpws | Bin 54380 -> 58476 bytes binaries/x86_64/tpws | Bin 77168 -> 79920 bytes readme.txt | 2 +- tpws/chartree.c | 83 --- tpws/chartree.h | 16 - tpws/strpool.c | 50 ++ tpws/strpool.h | 18 + tpws/tpws.c | 16 +- tpws/uthash.h | 1217 ++++++++++++++++++++++++++++++++++++ 12 files changed, 1294 insertions(+), 108 deletions(-) delete mode 100644 tpws/chartree.c delete mode 100644 tpws/chartree.h create mode 100644 tpws/strpool.c create mode 100644 tpws/strpool.h create mode 100644 tpws/uthash.h diff --git a/binaries/armhf/tpws b/binaries/armhf/tpws index c3a748f11d3a94b57a3f125eae5bf65a9c47fad2..f3d5341bec64d66e9d0ece08a62e19dac5c81c7f 100755 GIT binary patch delta 13710 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 delta 10310 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 K<~`fu=KlbiJU{>d diff --git a/binaries/mips32r1-lsb/tpws b/binaries/mips32r1-lsb/tpws index 568e340ef8b14fb286da0b3a32860589c8d49b43..ab108f0b028de4b6e7ccf60144d50adaa92e77d8 100755 GIT binary patch delta 18913 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� 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 Dm;Z*| delta 13848 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 diff --git a/binaries/mips32r1-msb/tpws b/binaries/mips32r1-msb/tpws index 9648b7273c9146a9e2be51d5d311176c5adee1d0..30528131527de3d704363b62e060f04887185680 100755 GIT binary patch delta 28676 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 delta 23833 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 LivCczG4_7}!$D2_ diff --git a/binaries/x86/tpws b/binaries/x86/tpws index 3547e1552a0e1ee5804944825c238f28277c9b65..4105ed11e7d737806c7661adc59ccc85de62d57a 100755 GIT binary patch delta 14733 zcma)j3tUvy_WwDD85wbKP(e`v5%B#2MFkZc!SR)k5yS_EtSIAc(k~yMXI%qv_n;yZ?pBj}$5_IEWGXU7@V*h3F$v}6SRnrPGEJC)m`fY6_uh>j}x(n{oR>9)AhEn;l zOry!&Y5>0@5ps6btw|jcniJtB=;iga{t*b+)vvd*L@8JLVKn=GNHp6eb)UI5kvHIO z6Sw<{v%m^hsqc^El^tz$ZXu1g@OFVFM*OYnf@MsV28>>`oL72$7EeeZ5a3{~YV
    +j_D=vDzB{n9XeG{RHWxiA(3KHxlOSF;Cmn|Ii1 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 ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются. в файле должен быть хост на каждой строке. ; список читается 1 раз при старте и хранится в памяти в виде иерархической структуры для быстрого поиска. - ; для списка РКН может потребоваться система с 128 Mb памяти ! расчитывайте требование RAM для процесса как 10-15 кратный размер файла списка. + ; для списка РКН может потребоваться система с 128 Mb памяти ! расчитывайте требование RAM для процесса как 3-5 кратный размер файла списка. ; по сигналу HUP список будет перечитан при следующем принятом соединении Параметры манипуляции могут сочетаться в любых комбинациях. Есть исключения : split-pos заменяет split-http-req. hostdot и hosttab взаимоисключающи. diff --git a/tpws/chartree.c b/tpws/chartree.c deleted file mode 100644 index 4668eb5..0000000 --- a/tpws/chartree.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "chartree.h" -#include -#include - -static cptr *CharTreeInit(char c) -{ - cptr *p; - p=(cptr *)calloc(1,sizeof(cptr)); - if (p) p->chr = c; - return p; -} -void CharTreeDestroy(cptr *p) -{ - cptr *p2; - while (p) - { - CharTreeDestroy(p->leaf); - p2 = p; - p = p->next; - free(p2); - } -} -static cptr *CharTreeFindChar(cptr *p,char c) -{ - while (p) - { - if (p->chr==c) return p; - p = p->next; - } - return NULL; -} -bool CharTreeAddStr(cptr **pp,const char *s) -{ - cptr *p; - if (*pp) - { - if (!(p=CharTreeFindChar(*pp,*s))) - { - // already present. append to list head - if (!(p = CharTreeInit(*s))) - return false; - p->next = *pp; - *pp = p; - } - } - else - if (!(p = *pp = CharTreeInit(*s))) return false; - if (!*s) return true; - return CharTreeAddStr(&p->leaf,s+1); -} -bool CharTreeCheckStr(cptr *p,const char *s) -{ - p = CharTreeFindChar(p,*s); - if (!p) return false; - if (!*s) return true; - return CharTreeCheckStr(p->leaf,s+1); -} - -static char *DupLower(const char *s) -{ - char *sp,*sl = strdup(s); - if (!sl) return false; - for(sp=sl;*sp;sp++) *sp=tolower(*sp); - return sl; -} -bool CharTreeAddStrLower(cptr **pp,const char *s) -{ - bool b; - char *sl = DupLower(s); - if (!sl) return false; - b=CharTreeAddStr(pp,sl); - free(sl); - return b; -} -bool CharTreeCheckStrLower(cptr *pp,const char *s) -{ - bool b; - char *sl = DupLower(s); - if (!sl) return false; - b=CharTreeCheckStr(pp,sl); - free(sl); - return b; -} diff --git a/tpws/chartree.h b/tpws/chartree.h deleted file mode 100644 index 6998143..0000000 --- a/tpws/chartree.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include - -typedef struct cptr -{ - char chr; - struct cptr *leaf,*next; -} cptr; - -void CharTreeDestroy(cptr *p); -bool CharTreeAddStr(cptr **pp,const char *s); -bool CharTreeAddStrLower(cptr **pp,const char *s); -bool CharTreeCheckStr(cptr *p,const char *s); -bool CharTreeCheckStrLower(cptr *pp,const char *s); diff --git a/tpws/strpool.c b/tpws/strpool.c new file mode 100644 index 0000000..dc1ecbf --- /dev/null +++ b/tpws/strpool.c @@ -0,0 +1,50 @@ +#include "strpool.h" +#include +#include + +#undef uthash_nonfatal_oom +#define uthash_nonfatal_oom(elt) ut_oom_recover(elt) + +static bool oom=false; +static void ut_oom_recover(strpool *elem) +{ + oom=true; +} + +bool StrPoolAddStr(strpool **pp,const char *s) +{ + strpool *elem; + if (!(elem = (strpool*)malloc(sizeof(strpool)))) + return false; + if (!(elem->str = strdup(s))) + { + free(elem); + return false; + } + oom = false; + HASH_ADD_KEYPTR( hh, *pp, elem->str, strlen(elem->str), elem ); + if (oom) + { + free(elem->str); + free(elem); + return false; + } + return true; +} +bool StrPoolCheckStr(strpool *p,const char *s) +{ + strpool *elem; + HASH_FIND_STR( p, s, elem); + return elem!=NULL; +} + +void StrPoolDestroy(strpool **p) +{ + strpool *elem,*tmp; + HASH_ITER(hh, *p, elem, tmp) { + free(elem->str); + HASH_DEL(*p, elem); + free(elem); + } + *p = NULL; +} diff --git a/tpws/strpool.h b/tpws/strpool.h new file mode 100644 index 0000000..4579d77 --- /dev/null +++ b/tpws/strpool.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +//#define HASH_BLOOM 20 +#define HASH_NONFATAL_OOM 1 +#define HASH_FUNCTION HASH_BER +#include "uthash.h" + +typedef struct strpool { + char *str; /* key */ + UT_hash_handle hh; /* makes this structure hashable */ +} strpool; + +void StrPoolDestroy(strpool **p); +bool StrPoolAddStr(strpool **pp,const char *s); +bool StrPoolCheckStr(strpool *p,const char *s); diff --git a/tpws/tpws.c b/tpws/tpws.c index dda631d..479b9f8 100644 --- a/tpws/tpws.c +++ b/tpws/tpws.c @@ -24,9 +24,9 @@ #include "tpws.h" #include "tpws_conn.h" -#include "chartree.h" +#include "strpool.h" -bool LoadHostList(cptr **hostlist, char *filename) +bool LoadHostList(strpool **hostlist, char *filename) { char *p, s[256]; FILE *F = fopen(filename, "rt"); @@ -42,9 +42,9 @@ bool LoadHostList(cptr **hostlist, char *filename) { for (p = s + strlen(s) - 1; p >= s && (*p == '\r' || *p == '\n'); p--) *p = 0; for (p = s; *p; p++) *p=tolower(*p); - if (!CharTreeAddStr(hostlist, s)) + if (!StrPoolAddStr(hostlist, s)) { - CharTreeDestroy(*hostlist); + StrPoolDestroy(hostlist); *hostlist = NULL; fprintf(stderr, "Not enough memory to store host list : %s\n", filename); fclose(F); @@ -72,7 +72,7 @@ struct params_s int split_pos; int maxconn; char hostfile[256]; - cptr *hostlist; + strpool *hostlist; }; struct params_s params; @@ -104,7 +104,7 @@ void dohup() { if (params.hostlist) { - CharTreeDestroy(params.hostlist); + StrPoolDestroy(¶ms.hostlist); if (!LoadHostList(¶ms.hostlist, params.hostfile)) exit(1); } @@ -221,7 +221,7 @@ bool handle_epollin(tproxy_conn_t *conn, int *data_transferred) { p = Host; while (p) { - bInHostList = CharTreeCheckStr(params.hostlist, p); + bInHostList = StrPoolCheckStr(params.hostlist, p); printf("Hostlist check for %s : %s\n", p, bInHostList ? "positive" : "negative"); if (bInHostList) break; p = strchr(p, '.'); @@ -851,7 +851,7 @@ int main(int argc, char *argv[]) { retval = event_loop(listen_fd); close(listen_fd); - if (params.hostlist) CharTreeDestroy(params.hostlist); + if (params.hostlist) StrPoolDestroy(¶ms.hostlist); fprintf(stderr, "Will exit\n"); diff --git a/tpws/uthash.h b/tpws/uthash.h new file mode 100644 index 0000000..f34c1f9 --- /dev/null +++ b/tpws/uthash.h @@ -0,0 +1,1217 @@ +/* +Copyright (c) 2003-2018, Troy D. Hanson http://troydhanson.github.com/uthash/ +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef UTHASH_H +#define UTHASH_H + +#define UTHASH_VERSION 2.0.2 + +#include /* memcmp, memset, strlen */ +#include /* ptrdiff_t */ +#include /* exit */ + +/* These macros use decltype or the earlier __typeof GNU extension. + As decltype is only available in newer compilers (VS2010 or gcc 4.3+ + when compiling c++ source) this code uses whatever method is needed + or, for VS2008 where neither is available, uses casting workarounds. */ +#if !defined(DECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER) /* MS compiler */ +#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */ +#define DECLTYPE(x) (decltype(x)) +#else /* VS2008 or older (or VS2010 in C mode) */ +#define NO_DECLTYPE +#endif +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__) +#define NO_DECLTYPE +#else /* GNU, Sun and other compilers */ +#define DECLTYPE(x) (__typeof(x)) +#endif +#endif + +#ifdef NO_DECLTYPE +#define DECLTYPE(x) +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + char **_da_dst = (char**)(&(dst)); \ + *_da_dst = (char*)(src); \ +} while (0) +#else +#define DECLTYPE_ASSIGN(dst,src) \ +do { \ + (dst) = DECLTYPE(dst)(src); \ +} while (0) +#endif + +/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */ +#if defined(_WIN32) +#if defined(_MSC_VER) && _MSC_VER >= 1600 +#include +#elif defined(__WATCOMC__) || defined(__MINGW32__) || defined(__CYGWIN__) +#include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif +#elif defined(__GNUC__) && !defined(__VXWORKS__) +#include +#else +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; +#endif + +#ifndef uthash_malloc +#define uthash_malloc(sz) malloc(sz) /* malloc fcn */ +#endif +#ifndef uthash_free +#define uthash_free(ptr,sz) free(ptr) /* free fcn */ +#endif +#ifndef uthash_bzero +#define uthash_bzero(a,n) memset(a,'\0',n) +#endif +#ifndef uthash_memcmp +#define uthash_memcmp(a,b,n) memcmp(a,b,n) +#endif +#ifndef uthash_strlen +#define uthash_strlen(s) strlen(s) +#endif + +#ifndef uthash_noexpand_fyi +#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */ +#endif +#ifndef uthash_expand_fyi +#define uthash_expand_fyi(tbl) /* can be defined to log expands */ +#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 */ +#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_BKT_CAPACITY_THRESH 10U /* expand when bucket count reaches */ + +/* calculate the element whose hash handle address is hhp */ +#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho))) +/* calculate the hash handle from element address elp */ +#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) \ +do { \ + HASH_FCN(keyptr, keylen, hashv); \ +} while (0) + +#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out) \ +do { \ + (out) = NULL; \ + if (head) { \ + unsigned _hf_bkt; \ + HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \ + if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \ + HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \ + } \ + } \ +} while (0) + +#define HASH_FIND(hh,head,keyptr,keylen,out) \ +do { \ + unsigned _hf_hashv; \ + HASH_VALUE(keyptr, keylen, _hf_hashv); \ + HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out); \ +} while (0) + +#ifdef 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_MAKE(tbl,oomed) \ +do { \ + (tbl)->bloom_nbits = HASH_BLOOM; \ + (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \ + if (!(tbl)->bloom_bv) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ + (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \ + } \ +} while (0) + +#define HASH_BLOOM_FREE(tbl) \ +do { \ + uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \ +} while (0) + +#define HASH_BLOOM_BITSET(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) \ + HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#define HASH_BLOOM_TEST(tbl,hashv) \ + HASH_BLOOM_BITTEST((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U))) + +#else +#define HASH_BLOOM_MAKE(tbl,oomed) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_TEST(tbl,hashv) (1) +#define HASH_BLOOM_BYTELEN 0U +#endif + +#define HASH_MAKE_TABLE(hh,head,oomed) \ +do { \ + (head)->hh.tbl = (UT_hash_table*)uthash_malloc(sizeof(UT_hash_table)); \ + if (!(head)->hh.tbl) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero((head)->hh.tbl, sizeof(UT_hash_table)); \ + (head)->hh.tbl->tail = &((head)->hh); \ + (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \ + (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \ + (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \ + (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \ + HASH_INITIAL_NUM_BUCKETS * sizeof(struct UT_hash_bucket)); \ + (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) + +#define HASH_REPLACE_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,replaced,cmpfcn) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn); \ +} while (0) + +#define HASH_REPLACE_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add,replaced) \ +do { \ + (replaced) = NULL; \ + HASH_FIND_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, replaced); \ + if (replaced) { \ + HASH_DELETE(hh, head, replaced); \ + } \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add); \ +} while (0) + +#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced); \ +} while (0) + +#define HASH_REPLACE_INORDER(hh,head,fieldname,keylen_in,add,replaced,cmpfcn) \ +do { \ + unsigned _hr_hashv; \ + HASH_VALUE(&((add)->fieldname), keylen_in, _hr_hashv); \ + HASH_REPLACE_BYHASHVALUE_INORDER(hh, head, fieldname, keylen_in, _hr_hashv, add, replaced, cmpfcn); \ +} while (0) + +#define HASH_APPEND_LIST(hh, head, add) \ +do { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \ + (head)->hh.tbl->tail->next = (add); \ + (head)->hh.tbl->tail = &((add)->hh); \ +} while (0) + +#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 { \ + if (!(oomed)) { \ + 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.key = (char*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( } ) \ + } else { \ + void *_hs_iter = (head); \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_AKBI_INNER_LOOP(hh, head, add, cmpfcn); \ + if (_hs_iter) { \ + (add)->hh.next = _hs_iter; \ + if (((add)->hh.prev = HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev)) { \ + HH_FROM_ELMT((head)->hh.tbl, (add)->hh.prev)->next = (add); \ + } else { \ + (head) = (add); \ + } \ + HH_FROM_ELMT((head)->hh.tbl, _hs_iter)->prev = (add); \ + } else { \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE_INORDER"); \ +} while (0) + +#define HASH_ADD_KEYPTR_INORDER(hh,head,keyptr,keylen_in,add,cmpfcn) \ +do { \ + unsigned _hs_hashv; \ + HASH_VALUE(keyptr, keylen_in, _hs_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, keyptr, keylen_in, _hs_hashv, add, cmpfcn); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE_INORDER(hh,head,fieldname,keylen_in,hashval,add,cmpfcn) \ + HASH_ADD_KEYPTR_BYHASHVALUE_INORDER(hh, head, &((add)->fieldname), keylen_in, hashval, add, cmpfcn) + +#define HASH_ADD_INORDER(hh,head,fieldname,keylen_in,add,cmpfcn) \ + HASH_ADD_KEYPTR_INORDER(hh, head, &((add)->fieldname), keylen_in, add, cmpfcn) + +#define HASH_ADD_KEYPTR_BYHASHVALUE(hh,head,keyptr,keylen_in,hashval,add) \ +do { \ + IF_HASH_NONFATAL_OOM( int _ha_oomed = 0; ) \ + (add)->hh.hashv = (hashval); \ + (add)->hh.key = (char*) (keyptr); \ + (add)->hh.keylen = (unsigned) (keylen_in); \ + if (!(head)) { \ + (add)->hh.next = NULL; \ + (add)->hh.prev = NULL; \ + HASH_MAKE_TABLE(hh, add, _ha_oomed); \ + IF_HASH_NONFATAL_OOM( if (!_ha_oomed) { ) \ + (head) = (add); \ + IF_HASH_NONFATAL_OOM( } ) \ + } else { \ + (add)->hh.tbl = (head)->hh.tbl; \ + HASH_APPEND_LIST(hh, head, add); \ + } \ + HASH_ADD_TO_TABLE(hh, head, keyptr, keylen_in, hashval, add, _ha_oomed); \ + HASH_FSCK(hh, head, "HASH_ADD_KEYPTR_BYHASHVALUE"); \ +} while (0) + +#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ +do { \ + unsigned _ha_hashv; \ + HASH_VALUE(keyptr, keylen_in, _ha_hashv); \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, keyptr, keylen_in, _ha_hashv, add); \ +} while (0) + +#define HASH_ADD_BYHASHVALUE(hh,head,fieldname,keylen_in,hashval,add) \ + HASH_ADD_KEYPTR_BYHASHVALUE(hh, head, &((add)->fieldname), keylen_in, hashval, add) + +#define HASH_ADD(hh,head,fieldname,keylen_in,add) \ + HASH_ADD_KEYPTR(hh, head, &((add)->fieldname), keylen_in, add) + +#define HASH_TO_BKT(hashv,num_bkts,bkt) \ +do { \ + bkt = ((hashv) & ((num_bkts) - 1U)); \ +} while (0) + +/* delete "delptr" from the hash table. + * "the usual" patch-up process for the app-order doubly-linked-list. + * The use of _hd_hh_del below deserves special explanation. + * These used to be expressed using (delptr) but that led to a bug + * if someone used the same symbol for the head and deletee, like + * HASH_DELETE(hh,users,users); + * We want that to work, but by changing the head (users) below + * we were forfeiting our ability to further refer to the deletee (users) + * in the patch-up process. Solution: use scratch space to + * copy the deletee pointer, then the latter references are via that + * scratch pointer rather than through the repointed (users) symbol. + */ +#define HASH_DELETE(hh,head,delptr) \ + HASH_DELETE_HH(hh, head, &(delptr)->hh) + +#define HASH_DELETE_HH(hh,head,delptrhh) \ +do { \ + struct UT_hash_handle *_hd_hh_del = (delptrhh); \ + if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \ + 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)); \ + (head) = NULL; \ + } else { \ + unsigned _hd_bkt; \ + if (_hd_hh_del == (head)->hh.tbl->tail) { \ + (head)->hh.tbl->tail = HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev); \ + } \ + if (_hd_hh_del->prev != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->prev)->next = _hd_hh_del->next; \ + } else { \ + DECLTYPE_ASSIGN(head, _hd_hh_del->next); \ + } \ + if (_hd_hh_del->next != NULL) { \ + HH_FROM_ELMT((head)->hh.tbl, _hd_hh_del->next)->prev = _hd_hh_del->prev; \ + } \ + HASH_TO_BKT(_hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \ + HASH_DEL_IN_BKT((head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \ + (head)->hh.tbl->num_items--; \ + } \ + HASH_FSCK(hh, head, "HASH_DELETE_HH"); \ +} while (0) + +/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */ +#define HASH_FIND_STR(head,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) \ +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) \ +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) \ + HASH_FIND(hh,head,findint,sizeof(int),out) +#define HASH_ADD_INT(head,intfield,add) \ + HASH_ADD(hh,head,intfield,sizeof(int),add) +#define HASH_REPLACE_INT(head,intfield,add,replaced) \ + HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced) +#define HASH_FIND_PTR(head,findptr,out) \ + HASH_FIND(hh,head,findptr,sizeof(void *),out) +#define HASH_ADD_PTR(head,ptrfield,add) \ + HASH_ADD(hh,head,ptrfield,sizeof(void *),add) +#define HASH_REPLACE_PTR(head,ptrfield,add,replaced) \ + HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced) +#define HASH_DEL(head,delptr) \ + HASH_DELETE(hh,head,delptr) + +/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined. + * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. + */ +#ifdef HASH_DEBUG +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_FSCK(hh,head,where) \ +do { \ + struct UT_hash_handle *_thh; \ + if (head) { \ + unsigned _bkt_i; \ + unsigned _count = 0; \ + char *_prev; \ + for (_bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; ++_bkt_i) { \ + unsigned _bkt_count = 0; \ + _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \ + _prev = NULL; \ + while (_thh) { \ + if (_prev != (char*)(_thh->hh_prev)) { \ + HASH_OOPS("%s: invalid hh_prev %p, actual %p\n", \ + (where), (void*)_thh->hh_prev, (void*)_prev); \ + } \ + _bkt_count++; \ + _prev = (char*)(_thh); \ + _thh = _thh->hh_next; \ + } \ + _count += _bkt_count; \ + if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \ + HASH_OOPS("%s: invalid bucket count %u, actual %u\n", \ + (where), (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \ + } \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid hh item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + _count = 0; \ + _prev = NULL; \ + _thh = &(head)->hh; \ + while (_thh) { \ + _count++; \ + if (_prev != (char*)_thh->prev) { \ + HASH_OOPS("%s: invalid prev %p, actual %p\n", \ + (where), (void*)_thh->prev, (void*)_prev); \ + } \ + _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \ + _thh = (_thh->next ? HH_FROM_ELMT((head)->hh.tbl, _thh->next) : NULL); \ + } \ + if (_count != (head)->hh.tbl->num_items) { \ + HASH_OOPS("%s: invalid app item count %u, actual %u\n", \ + (where), (head)->hh.tbl->num_items, _count); \ + } \ + } \ +} while (0) +#else +#define HASH_FSCK(hh,head,where) +#endif + +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to + * the descriptor to which this macro is defined for tuning the hash function. + * The app can #include to get the prototype for write(2). */ +#ifdef HASH_EMIT_KEYS +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \ +do { \ + unsigned _klen = fieldlen; \ + write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ + write(HASH_EMIT_KEYS, keyptr, (unsigned long)fieldlen); \ +} while (0) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#endif + +/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ +#ifdef HASH_FUNCTION +#define HASH_FCN HASH_FUNCTION +#else +#define HASH_FCN HASH_JEN +#endif + +/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */ +#define HASH_BER(key,keylen,hashv) \ +do { \ + unsigned _hb_keylen = (unsigned)keylen; \ + const unsigned char *_hb_key = (const unsigned char*)(key); \ + (hashv) = 0; \ + while (_hb_keylen-- != 0U) { \ + (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; \ + } \ +} while (0) + + +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at + * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ +#define HASH_SAX(key,keylen,hashv) \ +do { \ + unsigned _sx_i; \ + const unsigned char *_hs_key = (const unsigned char*)(key); \ + hashv = 0; \ + for (_sx_i=0; _sx_i < keylen; _sx_i++) { \ + hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \ + } \ +} while (0) +/* FNV-1a variation */ +#define HASH_FNV(key,keylen,hashv) \ +do { \ + unsigned _fn_i; \ + const unsigned char *_hf_key = (const unsigned char*)(key); \ + (hashv) = 2166136261U; \ + for (_fn_i=0; _fn_i < keylen; _fn_i++) { \ + hashv = hashv ^ _hf_key[_fn_i]; \ + hashv = hashv * 16777619U; \ + } \ +} while (0) + +#define HASH_OAT(key,keylen,hashv) \ +do { \ + unsigned _ho_i; \ + const unsigned char *_ho_key=(const unsigned char*)(key); \ + hashv = 0; \ + for(_ho_i=0; _ho_i < keylen; _ho_i++) { \ + hashv += _ho_key[_ho_i]; \ + hashv += (hashv << 10); \ + hashv ^= (hashv >> 6); \ + } \ + hashv += (hashv << 3); \ + hashv ^= (hashv >> 11); \ + hashv += (hashv << 15); \ +} while (0) + +#define HASH_JEN_MIX(a,b,c) \ +do { \ + a -= b; a -= c; a ^= ( c >> 13 ); \ + b -= c; b -= a; b ^= ( a << 8 ); \ + c -= a; c -= b; c ^= ( b >> 13 ); \ + a -= b; a -= c; a ^= ( c >> 12 ); \ + b -= c; b -= a; b ^= ( a << 16 ); \ + c -= a; c -= b; c ^= ( b >> 5 ); \ + a -= b; a -= c; a ^= ( c >> 3 ); \ + b -= c; b -= a; b ^= ( a << 10 ); \ + c -= a; c -= b; c ^= ( b >> 15 ); \ +} while (0) + +#define HASH_JEN(key,keylen,hashv) \ +do { \ + unsigned _hj_i,_hj_j,_hj_k; \ + unsigned const char *_hj_key=(unsigned const char*)(key); \ + hashv = 0xfeedbeefu; \ + _hj_i = _hj_j = 0x9e3779b9u; \ + _hj_k = (unsigned)(keylen); \ + while (_hj_k >= 12U) { \ + _hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \ + + ( (unsigned)_hj_key[2] << 16 ) \ + + ( (unsigned)_hj_key[3] << 24 ) ); \ + _hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \ + + ( (unsigned)_hj_key[6] << 16 ) \ + + ( (unsigned)_hj_key[7] << 24 ) ); \ + hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \ + + ( (unsigned)_hj_key[10] << 16 ) \ + + ( (unsigned)_hj_key[11] << 24 ) ); \ + \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ + \ + _hj_key += 12; \ + _hj_k -= 12U; \ + } \ + hashv += (unsigned)(keylen); \ + switch ( _hj_k ) { \ + case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */ \ + case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); /* FALLTHROUGH */ \ + case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); /* FALLTHROUGH */ \ + case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); /* FALLTHROUGH */ \ + case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); /* FALLTHROUGH */ \ + case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); /* FALLTHROUGH */ \ + case 5: _hj_j += _hj_key[4]; /* FALLTHROUGH */ \ + case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); /* FALLTHROUGH */ \ + case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); /* FALLTHROUGH */ \ + case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); /* FALLTHROUGH */ \ + case 1: _hj_i += _hj_key[0]; \ + } \ + HASH_JEN_MIX(_hj_i, _hj_j, hashv); \ +} while (0) + +/* The Paul Hsieh hash function */ +#undef get16bits +#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ + || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) +#define get16bits(d) (*((const uint16_t *) (d))) +#endif + +#if !defined (get16bits) +#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \ + +(uint32_t)(((const uint8_t *)(d))[0]) ) +#endif +#define HASH_SFH(key,keylen,hashv) \ +do { \ + unsigned const char *_sfh_key=(unsigned const char*)(key); \ + uint32_t _sfh_tmp, _sfh_len = (uint32_t)keylen; \ + \ + unsigned _sfh_rem = _sfh_len & 3U; \ + _sfh_len >>= 2; \ + hashv = 0xcafebabeu; \ + \ + /* Main loop */ \ + for (;_sfh_len > 0U; _sfh_len--) { \ + hashv += get16bits (_sfh_key); \ + _sfh_tmp = ((uint32_t)(get16bits (_sfh_key+2)) << 11) ^ hashv; \ + hashv = (hashv << 16) ^ _sfh_tmp; \ + _sfh_key += 2U*sizeof (uint16_t); \ + hashv += hashv >> 11; \ + } \ + \ + /* Handle end cases */ \ + switch (_sfh_rem) { \ + case 3: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 16; \ + hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)]) << 18; \ + hashv += hashv >> 11; \ + break; \ + case 2: hashv += get16bits (_sfh_key); \ + hashv ^= hashv << 11; \ + hashv += hashv >> 17; \ + break; \ + case 1: hashv += *_sfh_key; \ + hashv ^= hashv << 10; \ + hashv += hashv >> 1; \ + } \ + \ + /* Force "avalanching" of final 127 bits */ \ + hashv ^= hashv << 3; \ + hashv += hashv >> 5; \ + hashv ^= hashv << 4; \ + hashv += hashv >> 17; \ + hashv ^= hashv << 25; \ + hashv += hashv >> 6; \ +} while (0) + +#ifdef HASH_USING_NO_STRICT_ALIASING +/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads. + * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. + * MurmurHash uses the faster approach only on CPU's where we know it's safe. + * + * Note the preprocessor built-in defines can be emitted using: + * + * gcc -m64 -dM -E - < /dev/null (on gcc) + * cc -## a.c (where a.c is a simple test file) (Sun Studio) + */ +#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86)) +#define MUR_GETBLOCK(p,i) p[i] +#else /* non intel */ +#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 3UL) == 0UL) +#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 3UL) == 1UL) +#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 3UL) == 2UL) +#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 3UL) == 3UL) +#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL)) +#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__)) +#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8)) +#else /* assume little endian non-intel */ +#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24)) +#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16)) +#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8)) +#endif +#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \ + (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \ + (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \ + MUR_ONE_THREE(p)))) +#endif +#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) +#define MUR_FMIX(_h) \ +do { \ + _h ^= _h >> 16; \ + _h *= 0x85ebca6bu; \ + _h ^= _h >> 13; \ + _h *= 0xc2b2ae35u; \ + _h ^= _h >> 16; \ +} while (0) + +#define HASH_MUR(key,keylen,hashv) \ +do { \ + const uint8_t *_mur_data = (const uint8_t*)(key); \ + const int _mur_nblocks = (int)(keylen) / 4; \ + uint32_t _mur_h1 = 0xf88D5353u; \ + uint32_t _mur_c1 = 0xcc9e2d51u; \ + uint32_t _mur_c2 = 0x1b873593u; \ + uint32_t _mur_k1 = 0; \ + const uint8_t *_mur_tail; \ + const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+(_mur_nblocks*4)); \ + int _mur_i; \ + for (_mur_i = -_mur_nblocks; _mur_i != 0; _mur_i++) { \ + _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + \ + _mur_h1 ^= _mur_k1; \ + _mur_h1 = MUR_ROTL32(_mur_h1,13); \ + _mur_h1 = (_mur_h1*5U) + 0xe6546b64u; \ + } \ + _mur_tail = (const uint8_t*)(_mur_data + (_mur_nblocks*4)); \ + _mur_k1=0; \ + switch ((keylen) & 3U) { \ + case 0: break; \ + case 3: _mur_k1 ^= (uint32_t)_mur_tail[2] << 16; /* FALLTHROUGH */ \ + case 2: _mur_k1 ^= (uint32_t)_mur_tail[1] << 8; /* FALLTHROUGH */ \ + case 1: _mur_k1 ^= (uint32_t)_mur_tail[0]; \ + _mur_k1 *= _mur_c1; \ + _mur_k1 = MUR_ROTL32(_mur_k1,15); \ + _mur_k1 *= _mur_c2; \ + _mur_h1 ^= _mur_k1; \ + } \ + _mur_h1 ^= (uint32_t)(keylen); \ + MUR_FMIX(_mur_h1); \ + hashv = _mur_h1; \ +} while (0) +#endif /* HASH_USING_NO_STRICT_ALIASING */ + +/* iterate over items in a known bucket to find desired item */ +#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,hashval,out) \ +do { \ + if ((head).hh_head != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (head).hh_head)); \ + } else { \ + (out) = NULL; \ + } \ + while ((out) != NULL) { \ + if ((out)->hh.hashv == (hashval) && (out)->hh.keylen == (keylen_in)) { \ + if (uthash_memcmp((out)->hh.key, keyptr, keylen_in) == 0) { \ + break; \ + } \ + } \ + if ((out)->hh.hh_next != NULL) { \ + DECLTYPE_ASSIGN(out, ELMT_FROM_HH(tbl, (out)->hh.hh_next)); \ + } else { \ + (out) = NULL; \ + } \ + } \ +} while (0) + +/* add an item to a bucket */ +#define HASH_ADD_TO_BKT(head,hh,addhh,oomed) \ +do { \ + UT_hash_bucket *_ha_head = &(head); \ + _ha_head->count++; \ + (addhh)->hh_next = _ha_head->hh_head; \ + (addhh)->hh_prev = NULL; \ + if (_ha_head->hh_head != NULL) { \ + _ha_head->hh_head->hh_prev = (addhh); \ + } \ + _ha_head->hh_head = (addhh); \ + 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) + +/* remove an item from a given bucket */ +#define HASH_DEL_IN_BKT(head,delhh) \ +do { \ + UT_hash_bucket *_hd_head = &(head); \ + _hd_head->count--; \ + if (_hd_head->hh_head == (delhh)) { \ + _hd_head->hh_head = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_prev) { \ + (delhh)->hh_prev->hh_next = (delhh)->hh_next; \ + } \ + if ((delhh)->hh_next) { \ + (delhh)->hh_next->hh_prev = (delhh)->hh_prev; \ + } \ +} while (0) + +/* Bucket expansion has the effect of doubling the number of buckets + * and redistributing the items into the new buckets. Ideally the + * items will distribute more or less evenly into the new buckets + * (the extent to which this is true is a measure of the quality of + * the hash function as it applies to the key domain). + * + * With the items distributed into more buckets, the chain length + * (item count) in each bucket is reduced. Thus by expanding buckets + * the hash keeps a bound on the chain length. This bounded chain + * length is the essence of how a hash provides constant time lookup. + * + * The calculation of tbl->ideal_chain_maxlen below deserves some + * explanation. First, keep in mind that we're calculating the ideal + * maximum chain length based on the *new* (doubled) bucket count. + * In fractions this is just n/b (n=number of items,b=new num buckets). + * Since the ideal chain length is an integer, we want to calculate + * ceil(n/b). We don't depend on floating point arithmetic in this + * hash, so to calculate ceil(n/b) with integers we could write + * + * ceil(n/b) = (n/b) + ((n%b)?1:0) + * + * and in fact a previous version of this hash did just that. + * But now we have improved things a bit by recognizing that b is + * always a power of two. We keep its base 2 log handy (call it lb), + * so now we can write this with a bit shift and logical AND: + * + * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) + * + */ +#define HASH_EXPAND_BUCKETS(hh,tbl,oomed) \ +do { \ + unsigned _he_bkt; \ + unsigned _he_bkt_i; \ + struct UT_hash_handle *_he_thh, *_he_hh_nxt; \ + UT_hash_bucket *_he_new_buckets, *_he_newbkt; \ + _he_new_buckets = (UT_hash_bucket*)uthash_malloc( \ + 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + if (!_he_new_buckets) { \ + HASH_RECORD_OOM(oomed); \ + } else { \ + uthash_bzero(_he_new_buckets, \ + 2UL * (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->ideal_chain_maxlen = \ + ((tbl)->num_items >> ((tbl)->log2_num_buckets+1U)) + \ + ((((tbl)->num_items & (((tbl)->num_buckets*2U)-1U)) != 0U) ? 1U : 0U); \ + (tbl)->nonideal_items = 0; \ + 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) { \ + _he_hh_nxt = _he_thh->hh_next; \ + HASH_TO_BKT(_he_thh->hashv, (tbl)->num_buckets * 2U, _he_bkt); \ + _he_newbkt = &(_he_new_buckets[_he_bkt]); \ + if (++(_he_newbkt->count) > (tbl)->ideal_chain_maxlen) { \ + (tbl)->nonideal_items++; \ + _he_newbkt->expand_mult = _he_newbkt->count / (tbl)->ideal_chain_maxlen; \ + } \ + _he_thh->hh_prev = NULL; \ + _he_thh->hh_next = _he_newbkt->hh_head; \ + if (_he_newbkt->hh_head != NULL) { \ + _he_newbkt->hh_head->hh_prev = _he_thh; \ + } \ + _he_newbkt->hh_head = _he_thh; \ + _he_thh = _he_hh_nxt; \ + } \ + } \ + uthash_free((tbl)->buckets, (tbl)->num_buckets * sizeof(struct UT_hash_bucket)); \ + (tbl)->num_buckets *= 2U; \ + (tbl)->log2_num_buckets++; \ + (tbl)->buckets = _he_new_buckets; \ + (tbl)->ineff_expands = ((tbl)->nonideal_items > ((tbl)->num_items >> 1)) ? \ + ((tbl)->ineff_expands+1U) : 0U; \ + if ((tbl)->ineff_expands > 1U) { \ + (tbl)->noexpand = 1; \ + uthash_noexpand_fyi(tbl); \ + } \ + uthash_expand_fyi(tbl); \ + } \ +} while (0) + + +/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ +/* Note that HASH_SORT assumes the hash handle name to be hh. + * HASH_SRT was added to allow the hash handle name to be passed in. */ +#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) +#define HASH_SRT(hh,head,cmpfcn) \ +do { \ + unsigned _hs_i; \ + unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \ + struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \ + if (head != NULL) { \ + _hs_insize = 1; \ + _hs_looping = 1; \ + _hs_list = &((head)->hh); \ + while (_hs_looping != 0U) { \ + _hs_p = _hs_list; \ + _hs_list = NULL; \ + _hs_tail = NULL; \ + _hs_nmerges = 0; \ + while (_hs_p != NULL) { \ + _hs_nmerges++; \ + _hs_q = _hs_p; \ + _hs_psize = 0; \ + for (_hs_i = 0; _hs_i < _hs_insize; ++_hs_i) { \ + _hs_psize++; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + if (_hs_q == NULL) { \ + break; \ + } \ + } \ + _hs_qsize = _hs_insize; \ + while ((_hs_psize != 0U) || ((_hs_qsize != 0U) && (_hs_q != NULL))) { \ + if (_hs_psize == 0U) { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } else if ((_hs_qsize == 0U) || (_hs_q == NULL)) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } else if ((cmpfcn( \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_p)), \ + DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl, _hs_q)) \ + )) <= 0) { \ + _hs_e = _hs_p; \ + if (_hs_p != NULL) { \ + _hs_p = ((_hs_p->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_p->next) : NULL); \ + } \ + _hs_psize--; \ + } else { \ + _hs_e = _hs_q; \ + _hs_q = ((_hs_q->next != NULL) ? \ + HH_FROM_ELMT((head)->hh.tbl, _hs_q->next) : NULL); \ + _hs_qsize--; \ + } \ + if ( _hs_tail != NULL ) { \ + _hs_tail->next = ((_hs_e != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl, _hs_e) : NULL); \ + } else { \ + _hs_list = _hs_e; \ + } \ + if (_hs_e != NULL) { \ + _hs_e->prev = ((_hs_tail != NULL) ? \ + ELMT_FROM_HH((head)->hh.tbl, _hs_tail) : NULL); \ + } \ + _hs_tail = _hs_e; \ + } \ + _hs_p = _hs_q; \ + } \ + if (_hs_tail != NULL) { \ + _hs_tail->next = NULL; \ + } \ + if (_hs_nmerges <= 1U) { \ + _hs_looping = 0; \ + (head)->hh.tbl->tail = _hs_tail; \ + DECLTYPE_ASSIGN(head, ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \ + } \ + _hs_insize *= 2U; \ + } \ + HASH_FSCK(hh, head, "HASH_SRT"); \ + } \ +} while (0) + +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash + * hash handle that must be present in the structure. */ +#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ +do { \ + unsigned _src_bkt, _dst_bkt; \ + void *_last_elt = NULL, *_elt; \ + UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \ + ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \ + if ((src) != NULL) { \ + 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; \ + _src_hh != NULL; \ + _src_hh = _src_hh->hh_next) { \ + _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \ + if (cond(_elt)) { \ + IF_HASH_NONFATAL_OOM( int _hs_oomed = 0; ) \ + _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \ + _dst_hh->key = _src_hh->key; \ + _dst_hh->keylen = _src_hh->keylen; \ + _dst_hh->hashv = _src_hh->hashv; \ + _dst_hh->prev = _last_elt; \ + _dst_hh->next = NULL; \ + if (_last_elt_hh != NULL) { \ + _last_elt_hh->next = _elt; \ + } \ + 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 { \ + _dst_hh->tbl = (dst)->hh_dst.tbl; \ + } \ + HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \ + HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt], hh_dst, _dst_hh, _hs_oomed); \ + (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_hh = _dst_hh; \ + } \ + } \ + } \ + } \ + HASH_FSCK(hh_dst, dst, "HASH_SELECT"); \ +} while (0) + +#define HASH_CLEAR(hh,head) \ +do { \ + if ((head) != NULL) { \ + 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)); \ + (head) = NULL; \ + } \ +} while (0) + +#define HASH_OVERHEAD(hh,head) \ + (((head) != NULL) ? ( \ + (size_t)(((head)->hh.tbl->num_items * sizeof(UT_hash_handle)) + \ + ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket)) + \ + sizeof(UT_hash_table) + \ + (HASH_BLOOM_BYTELEN))) : 0U) + +#ifdef NO_DECLTYPE +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((*(char**)(&(tmp)))=(char*)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((*(char**)(&(tmp)))=(char*)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#else +#define HASH_ITER(hh,head,el,tmp) \ +for(((el)=(head)), ((tmp)=DECLTYPE(el)((head!=NULL)?(head)->hh.next:NULL)); \ + (el) != NULL; ((el)=(tmp)), ((tmp)=DECLTYPE(el)((tmp!=NULL)?(tmp)->hh.next:NULL))) +#endif + +/* obtain a count of items in the hash */ +#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_CNT(hh,head) ((head != NULL)?((head)->hh.tbl->num_items):0U) + +typedef struct UT_hash_bucket { + struct UT_hash_handle *hh_head; + unsigned count; + + /* expand_mult is normally set to 0. In this situation, the max chain length + * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If + * the bucket's chain exceeds this length, bucket expansion is triggered). + * However, setting expand_mult to a non-zero value delays bucket expansion + * (that would be triggered by additions to this particular bucket) + * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. + * (The multiplier is simply expand_mult+1). The whole idea of this + * multiplier is to reduce bucket expansions, since they are expensive, in + * situations where we know that a particular bucket tends to be overused. + * It is better to let its chain length grow to a longer yet-still-bounded + * value, than to do an O(n) bucket expansion too often. + */ + unsigned expand_mult; + +} UT_hash_bucket; + +/* random signature used only to find hash tables in external analysis */ +#define HASH_SIGNATURE 0xa0111fe1u +#define HASH_BLOOM_SIGNATURE 0xb12220f2u + +typedef struct UT_hash_table { + UT_hash_bucket *buckets; + unsigned num_buckets, log2_num_buckets; + unsigned num_items; + struct UT_hash_handle *tail; /* tail hh in app order, for fast append */ + ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */ + + /* in an ideal situation (all buckets used equally), no bucket would have + * more than ceil(#items/#buckets) items. that's the ideal chain length. */ + unsigned ideal_chain_maxlen; + + /* nonideal_items is the number of items in the hash whose chain position + * exceeds the ideal chain maxlen. these items pay the penalty for an uneven + * hash distribution; reaching them in a chain traversal takes >ideal steps */ + unsigned nonideal_items; + + /* ineffective expands occur when a bucket doubling was performed, but + * afterward, more than half the items in the hash had nonideal chain + * positions. If this happens on two consecutive expansions we inhibit any + * further expansion, as it's not helping; this happens when the hash + * function isn't a good fit for the key domain. When expansion is inhibited + * the hash will still work, albeit no longer in constant time. */ + unsigned ineff_expands, noexpand; + + uint32_t signature; /* used only to find hash tables in external analysis */ +#ifdef HASH_BLOOM + uint32_t bloom_sig; /* used only to test bloom exists in external analysis */ + uint8_t *bloom_bv; + uint8_t bloom_nbits; +#endif + +} UT_hash_table; + +typedef struct UT_hash_handle { + struct UT_hash_table *tbl; + void *prev; /* prev element in app order */ + void *next; /* next element in app order */ + struct UT_hash_handle *hh_prev; /* previous hh in bucket order */ + struct UT_hash_handle *hh_next; /* next hh in bucket order */ + void *key; /* ptr to enclosing struct's key */ + unsigned keylen; /* enclosing struct's key len */ + unsigned hashv; /* result of hash-fcn(key) */ +} UT_hash_handle; + +#endif /* UTHASH_H */