eina: add murmur3 hash
authorbilliob <billiob@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 10 Nov 2011 10:58:19 +0000 (10:58 +0000)
committerbilliob <billiob@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Thu, 10 Nov 2011 10:58:19 +0000 (10:58 +0000)
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eina@65017 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/include/eina_hash.h
src/include/eina_inline_hash.x
src/tests/eina_bench_hash.c

index 71de90b..c8eb048 100644 (file)
@@ -1020,7 +1020,9 @@ static inline int eina_hash_int32(const unsigned int *pkey,
                                   int                 len) EINA_ARG_NONNULL(1);
 static inline int eina_hash_int64(const unsigned long int *pkey,
                                   int                      len) EINA_ARG_NONNULL(1);
-
+/* http://sites.google.com/site/murmurhash/ */
+static inline int eina_hash_murmur3(const char *key,
+                           int         len) EINA_ARG_NONNULL(1);
 #include "eina_inline_hash.x"
 
 /**
index 0fb992b..f27060f 100644 (file)
@@ -85,4 +85,67 @@ eina_hash_int64(const unsigned long int *pkey, int len)
    return (int) key;
 }
 
+static inline unsigned int _rotl32(unsigned int x, char r)
+{
+   return (x << r) | (x >> (32 - r));
+}
+
+static inline unsigned int _fmix32(unsigned int h)
+{
+   h ^= h >> 16;
+   h *= 0x85ebca6b;
+   h ^= h >> 13;
+   h *= 0xc2b2ae35;
+   h ^= h >> 16;
+
+   return h;
+}
+
+int
+eina_hash_murmur3(const char *key, int len)
+{
+   const unsigned char * data = (const unsigned char*)key;
+   const int nblocks = len / 4;
+   unsigned int h1 = 0, k1;
+   unsigned int c1 = 0xcc9e2d51;
+   unsigned int c2 = 0x1b873593;
+   const unsigned int * blocks = (const unsigned int *)(data + nblocks*4);
+   int i;
+   const unsigned char *tail;
+
+   for(i = -nblocks; i; i++)
+     {
+        k1 = blocks[i];
+
+        k1 *= c1;
+        k1 = _rotl32(k1, 15);
+        k1 *= c2;
+
+        h1 ^= k1;
+        h1 = _rotl32(h1, 13);
+        h1 = h1*5+0xe6546b64;
+     }
+
+   tail = (const unsigned char*)(data + nblocks*4);
+
+   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, 16);
+         k1 *= c2;
+         h1 ^= k1;
+     }
+
+   h1 ^= len;
+
+   return _fmix32(h1);
+}
 #endif
index 46feedc..5b42318 100644 (file)
@@ -144,6 +144,49 @@ eina_bench_lookup_rbtree(int request)
    eina_rbtree_delete(root, EINA_RBTREE_FREE_CB(_eina_bench_rbtree_free), NULL);
 }
 
+static void
+eina_bench_lookup_murmur(int request)
+{
+   Eina_Hash *hash = NULL;
+   int *tmp_val;
+   unsigned int i;
+   unsigned int j;
+
+   hash = eina_hash_new(EINA_KEY_LENGTH(_eina_string_key_length),
+                        EINA_KEY_CMP(_eina_string_key_cmp),
+                        EINA_KEY_HASH(eina_hash_murmur3),
+                        free,
+                        8);
+
+   for (i = 0; i < (unsigned int)request; ++i)
+     {
+        char tmp_key[10];
+
+        tmp_val = malloc(sizeof (int));
+
+        if (!tmp_val)
+           continue;
+
+        eina_convert_itoa(i, tmp_key);
+        *tmp_val = i;
+
+        eina_hash_add(hash, tmp_key, tmp_val);
+     }
+
+   srand(time(NULL));
+
+   for (j = 0; j < 200; ++j)
+      for (i = 0; i < (unsigned int)request; ++i)
+        {
+           char tmp_key[10];
+
+           eina_convert_itoa(rand() % request, tmp_key);
+           tmp_val = eina_hash_find(hash, tmp_key);
+        }
+
+   eina_hash_free(hash);
+}
+
 #ifdef CITYHASH_BENCH
 static void
 eina_bench_lookup_cityhash(int request)
@@ -476,10 +519,13 @@ void eina_bench_hash(Eina_Benchmark *bench)
    eina_benchmark_register(bench, "djb2-lookup-inline",
                            EINA_BENCHMARK(
                               eina_bench_lookup_djb2_inline), 10, 10000, 10);
+   eina_benchmark_register(bench, "murmur",
+                           EINA_BENCHMARK(
+                              eina_bench_lookup_murmur),      10, 10000, 10);
 #ifdef CITYHASH_BENCH
    eina_benchmark_register(bench, "cityhash",
                            EINA_BENCHMARK(
-                              eina_bench_lookup_cityhash),      10, 10000, 10);
+                              eina_bench_lookup_cityhash),    10, 10000, 10);
 #endif
    eina_benchmark_register(bench, "rbtree",
                            EINA_BENCHMARK(
@@ -495,4 +541,5 @@ void eina_bench_hash(Eina_Benchmark *bench)
    eina_benchmark_register(bench, "ecore-lookup",
                            EINA_BENCHMARK(
                               eina_bench_lookup_ecore),       10, 10000, 10);
+
 }