diff options
author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-11-27 03:24:24 +0100 |
---|---|---|
committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-11-29 23:57:56 +0100 |
commit | 4e2d5a81bb2834f7393e9847bfa091f8a0a07556 (patch) | |
tree | 87eb878db4a269948a39566f14be9315733f5919 | |
parent | 1842a9dcd1056dac886e96071e8c5dcd2859d471 (diff) |
libihash: provide a general purpose hash algorithm
* libdiskfs/name-cache.c: Move the Murmur3 algorithm...
* libihash/murmur3.c: ... here, and properly attribute the code.
* libihash/ihash.h (hurd_ihash_hash32): New prototype.
* libihash/Makefile (SRCS): Add new file.
-rw-r--r-- | libdiskfs/name-cache.c | 89 | ||||
-rw-r--r-- | libihash/Makefile | 2 | ||||
-rw-r--r-- | libihash/ihash.h | 5 | ||||
-rw-r--r-- | libihash/murmur3.c | 93 |
4 files changed, 102 insertions, 87 deletions
diff --git a/libdiskfs/name-cache.c b/libdiskfs/name-cache.c index e9fe27ea..53935ab3 100644 --- a/libdiskfs/name-cache.c +++ b/libdiskfs/name-cache.c @@ -21,6 +21,7 @@ #include "priv.h" #include <assert.h> +#include <hurd/ihash.h> #include <string.h> /* The name cache is implemented using a hash table. @@ -118,90 +119,6 @@ valid_entry (struct cache_bucket *b, int i) return b->name[i] != 0; } -/* This is the Murmur3 hash algorithm. */ - -#define FORCE_INLINE inline __attribute__((always_inline)) - -inline uint32_t rotl32 ( uint32_t x, int8_t r ) -{ - return (x << r) | (x >> (32 - r)); -} - -#define ROTL32(x,y) rotl32(x,y) - -/* Block read - if your platform needs to do endian-swapping or can - only handle aligned reads, do the conversion here. */ - -FORCE_INLINE uint32_t getblock32 ( const uint32_t * p, int i ) -{ - return p[i]; -} - -/* Finalization mix - force all bits of a hash block to avalanche. */ - -FORCE_INLINE uint32_t fmix32 ( uint32_t h ) -{ - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; - - return h; -} - -/* The Murmur3 hash function. */ -void MurmurHash3_x86_32 ( const void * key, int len, - uint32_t seed, void * out ) -{ - const uint8_t * data = (const uint8_t*)key; - const int nblocks = len / 4; - - uint32_t h1 = seed; - - const uint32_t c1 = 0xcc9e2d51; - const uint32_t c2 = 0x1b873593; - - /* body */ - - const uint32_t * blocks = (const uint32_t *)(data + nblocks*4); - - for(int i = -nblocks; i; i++) - { - uint32_t k1 = getblock32(blocks,i); - - k1 *= c1; - k1 = ROTL32(k1,15); - k1 *= c2; - - h1 ^= k1; - h1 = ROTL32(h1,13); - h1 = h1*5+0xe6546b64; - } - - /* tail */ - - const uint8_t * tail = (const uint8_t*)(data + nblocks*4); - - uint32_t k1 = 0; - - switch(len & 3) - { - case 3: k1 ^= tail[2] << 16; - case 2: k1 ^= tail[1] << 8; - case 1: k1 ^= tail[0]; - k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; - }; - - /* finalization */ - - h1 ^= len; - - h1 = fmix32(h1); - - *(uint32_t*)out = h1; -} - /* If there is no best candidate to replace, pick any. We approximate any by picking the slot depicted by REPLACE, and increment REPLACE then. */ @@ -259,8 +176,8 @@ static inline unsigned long hash (ino64_t dir_cache_id, const char *name) { unsigned long h; - MurmurHash3_x86_32 (&dir_cache_id, sizeof dir_cache_id, 0, &h); - MurmurHash3_x86_32 (name, strlen (name), h, &h); + h = hurd_ihash_hash32 (&dir_cache_id, sizeof dir_cache_id, 0); + h = hurd_ihash_hash32 (name, strlen (name), h); return h; } diff --git a/libihash/Makefile b/libihash/Makefile index 09bb1362..3377ef41 100644 --- a/libihash/Makefile +++ b/libihash/Makefile @@ -20,7 +20,7 @@ dir := libihash makemode := library libname := libihash -SRCS = ihash.c +SRCS = ihash.c murmur3.c installhdrs = ihash.h OBJS = $(SRCS:.c=.o) diff --git a/libihash/ihash.h b/libihash/ihash.h index 28fefe80..356f6473 100644 --- a/libihash/ihash.h +++ b/libihash/ihash.h @@ -349,5 +349,10 @@ int hurd_ihash_remove (hurd_ihash_t ht, hurd_ihash_key_t key); was provided to hurd_ihash_add(). This call is faster than hurd_ihash_remove(). */ void hurd_ihash_locp_remove (hurd_ihash_t ht, hurd_ihash_locp_t locp); + +/* We provide a general purpose hash function. This function can be + used with the generalized key interface to use arbitrary data as + keys using this library. */ +uint32_t hurd_ihash_hash32 (const void *buf, size_t len, uint32_t seed); #endif /* _HURD_IHASH_H */ diff --git a/libihash/murmur3.c b/libihash/murmur3.c new file mode 100644 index 00000000..e45180a4 --- /dev/null +++ b/libihash/murmur3.c @@ -0,0 +1,93 @@ +/* This is the Murmur3 hash algorithm. + * + * MurmurHash3 was written by Austin Appleby, and is placed in the public + * domain. The author hereby disclaims copyright to this source code. + */ + +#include <stdint.h> +#include <stdio.h> + +#define FORCE_INLINE static inline __attribute__((always_inline)) + +static inline uint32_t rotl32 ( uint32_t x, int8_t r ) +{ + return (x << r) | (x >> (32 - r)); +} + +#define ROTL32(x,y) rotl32(x,y) + +/* Block read - if your platform needs to do endian-swapping or can + only handle aligned reads, do the conversion here. */ + +FORCE_INLINE uint32_t getblock32 ( const uint32_t * p, int i ) +{ + return p[i]; +} + +/* Finalization mix - force all bits of a hash block to avalanche. */ + +FORCE_INLINE uint32_t fmix32 ( uint32_t h ) +{ + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; +} + +/* The Murmur3 hash function. */ +static uint32_t +MurmurHash3_x86_32 (const void *key, size_t len, uint32_t seed) +{ + const uint8_t * data = (const uint8_t*)key; + const int nblocks = (int) (len / 4); + + uint32_t h1 = seed; + + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; + + /* body */ + + const uint32_t * blocks = (const uint32_t *)(data + nblocks*4); + + for(int i = -nblocks; i; i++) + { + uint32_t k1 = getblock32(blocks,i); + + k1 *= c1; + k1 = ROTL32(k1,15); + k1 *= c2; + + h1 ^= k1; + h1 = ROTL32(h1,13); + h1 = h1*5+0xe6546b64; + } + + /* tail */ + + const uint8_t * tail = (const uint8_t*)(data + nblocks*4); + + uint32_t k1 = 0; + + switch(len & 3) + { + case 3: k1 ^= tail[2] << 16; + case 2: k1 ^= tail[1] << 8; + case 1: k1 ^= tail[0]; + k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1; + }; + + /* finalization */ + + h1 ^= len; + + h1 = fmix32(h1); + + return h1; +} + +uint32_t hurd_ihash_hash32 (const void *, size_t, uint32_t) + __attribute__ ((weak, alias ("MurmurHash3_x86_32"))); |