X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=stat.c;h=24a3466a16e9c7f4f83b3354b157bb5bbb778aeb;hp=e46102da51d3ec8e337cfb49217615be63af7f56;hb=1bf9ebabcce7731b83c302e8416bba41c3cdf5da;hpb=f8949e17c86f1561ab2a9568288fb4911b4878be diff --git a/stat.c b/stat.c index e46102d..24a3466 100644 --- a/stat.c +++ b/stat.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 + * Copyright (C) 2012, 2013, 2014 * Dale Weiler * Wolfgang Bumiller * @@ -353,139 +353,11 @@ typedef struct hash_node_t { struct hash_node_t *next; /* next node (linked list) */ } hash_node_t; -/* - * This is a patched version of the Murmur2 hashing function to use - * a proper pre-mix and post-mix setup. Infact this is Murmur3 for - * the most part just reinvented. - * - * Murmur 2 contains an inner loop such as: - * while (l >= 4) { - * u32 k = *(u32*)d; - * k *= m; - * k ^= k >> r; - * k *= m; - * - * h *= m; - * h ^= k; - * d += 4; - * l -= 4; - * } - * - * The two u32s that form the key are the same value x (pulled from data) - * this premix stage will perform the same results for both values. Unrolled - * this produces just: - * x *= m; - * x ^= x >> r; - * x *= m; - * - * h *= m; - * h ^= x; - * h *= m; - * h ^= x; - * - * This appears to be fine, except what happens when m == 1? well x - * cancels out entierly, leaving just: - * x ^= x >> r; - * h ^= x; - * h ^= x; - * - * So all keys hash to the same value, but how often does m == 1? - * well, it turns out testing x for all possible values yeilds only - * 172,013,942 unique results instead of 2^32. So nearly ~4.6 bits - * are cancelled out on average! - * - * This means we have a 14.5% (rounded) chance of colliding more, which - * results in another bucket/chain for the hashtable. - * - * We fix it buy upgrading the pre and post mix ssystems to align with murmur - * hash 3. - */ -#if 1 -#define GMQCC_ROTL32(X, R) (((X) << (R)) | ((X) >> (32 - (R)))) -GMQCC_INLINE size_t util_hthash(hash_table_t *ht, const char *key) { - const unsigned char *data = (const unsigned char *)key; - const size_t len = strlen(key); - const size_t block = len / 4; - const uint32_t mask1 = 0xCC9E2D51; - const uint32_t mask2 = 0x1B873593; - const uint32_t *blocks = (const uint32_t*)(data + block * 4); - const unsigned char *tail = (const unsigned char *)(data + block * 4); - - size_t i; - uint32_t k; - uint32_t h = 0x1EF0 ^ len; - - for (i = -((int)block); i; i++) { - k = blocks[i]; - k *= mask1; - k = GMQCC_ROTL32(k, 15); - k *= mask2; - h ^= k; - h = GMQCC_ROTL32(h, 13); - h = h * 5 + 0xE6546B64; - } - k = 0; - switch (len & 3) { - case 3: - k ^= tail[2] << 16; - case 2: - k ^= tail[1] << 8; - case 1: - k ^= tail[0]; - k *= mask1; - k = GMQCC_ROTL32(k, 15); - k *= mask2; - h ^= k; - } - - h ^= len; - h ^= h >> 16; - h *= 0x85EBCA6B; - h ^= h >> 13; - h *= 0xC2B2AE35; - h ^= h >> 16; - - return (size_t) (h % ht->size); +size_t hash(const char *key); +size_t util_hthash(hash_table_t *ht, const char *key) { + return hash(key) % ht->size; } -#undef GMQCC_ROTL32 -#else -/* We keep the old for reference */ -GMQCC_INLINE size_t util_hthash(hash_table_t *ht, const char *key) { - const uint32_t mix = 0x5BD1E995; - const uint32_t rot = 24; - size_t size = strlen(key); - uint32_t hash = 0x1EF0 /* LICRC TAB */ ^ size; - uint32_t alias = 0; - const unsigned char *data = (const unsigned char*)key; - - while (size >= 4) { - alias = (data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24)); - alias *= mix; - alias ^= alias >> rot; - alias *= mix; - - hash *= mix; - hash ^= alias; - - data += 4; - size -= 4; - } - - switch (size) { - case 3: hash ^= data[2] << 16; - case 2: hash ^= data[1] << 8; - case 1: hash ^= data[0]; - hash *= mix; - } - - hash ^= hash >> 13; - hash *= mix; - hash ^= hash >> 15; - - return (size_t) (hash % ht->size); -} -#endif static hash_node_t *_util_htnewpair(const char *key, void *value) { hash_node_t *node; @@ -685,7 +557,7 @@ void util_htdel(hash_table_t *ht) { * information. */ static void stat_dump_mem_contents(stat_mem_block_t *block, uint16_t cols) { - unsigned char *buffer = mem_a(cols); + unsigned char *buffer = (unsigned char *)mem_a(cols); unsigned char *memory = (unsigned char *)(block + 1); size_t i;