Fixed value reassignment with sh_put_ptr() and reformatted the macro code.
authorStephan Soller <stephan.soller@helionweb.de>
Fri, 29 Apr 2016 18:41:30 +0000 (20:41 +0200)
committerStephan Soller <stephan.soller@helionweb.de>
Fri, 29 Apr 2016 18:41:30 +0000 (20:41 +0200)
slim_hash.h
tests/slim_hash_test.c

index df49d12..452c854 100644 (file)
@@ -11,9 +11,9 @@
 bool sh_del(hash, key);  // ture if value was found and deleted, false if not found
 
 for(sh_it_p it = sh_start(hash); it != NULL; it = sh_next(it)) {
-       int64_t key = sh_key(it);
-       int value = sh_value(it);
-       sh_remove(it);
+    int64_t key = sh_key(it);
+    int value = sh_value(it);
+    sh_remove(it);
 }
 
 int* sh_put_ptr(sh_hash_p hash, int64_t key);  // reserve new slot, returns ptr to value
@@ -28,18 +28,19 @@ void    sh_remove(sh_hash_p hash, sh_it_p it);  // removes current elem from has
 
 /*
 
-prefix        sh_                           dict_
-key_type      int64_t                       const char*
-value_type    int                           void*
-hash_expr     sh_murmur3_32(&k, sizeof(k))  sh_murmur3_32(k, strlen(k))
-key_cmp_expr  (a == b)                      strcmp(a, b) == 0
-key_add_expr  k                             strdup(k)
-key_del_expr  0                             (free(k), NULL)
+prefix      sh_                        dict_
+key_type      int64_t                      const char*
+value_type  int                        void*
+hash_expr    sh_murmur3_32(&k, sizeof(k))  sh_murmur3_32(k, strlen(k))
+key_cmp_expr  (a == b)                    strcmp(a, b) == 0
+key_put_expr  k                          strdup(k)
+key_del_expr  0                          (free(k), NULL)
+
+SH_GEN_DECL(dict, const char*, void*)
+SH_GEN_DEF(dict, const char*, void*, sh_murmur3_32(k, strlen(k)), strcmp(a, b) == 0, strdup(k), (free(k), NULL))
+SH_GEN_DICT_DEF(dict, void*)
+SH_GEN_HASH_DEF(con_list, int32_t, void*)
 
-SH_GEN_DECL("dict_", const char*, void*)
-SH_GEN_DEF("dict_", const char*, void*, sh_murmur3_32(k, strlen(k)), strcmp(a, b) == 0, strdup(k), (free(k), NULL))
-SH_GEN_DICT_DEF("dict_", void*)
-SH_GEN_HASH_DEF("con_list_", int32_t, void*)
 
 */
 
@@ -49,40 +50,39 @@ SH_GEN_HASH_DEF("con_list_", int32_t, void*)
 // Data
 //
 
-typedef struct {
-       uint32_t hash_and_flags;
-       int64_t key;
-       int value;
-} sh_slot_t, *sh_slot_p, *sh_it_p;
-
-typedef struct {
-       uint32_t length, capacity, deleted;
-       sh_slot_p slots;
-} sh_hash_t, *sh_hash_p;
-
 #define SH_SLOT_FREE     0x00000000
 #define SH_SLOT_DELETED  0x00000001
+#define SH_SLOT_FILLED   0x80000000
+
+#define SH_GEN_DECL(prefix, key_t, value_t)                                     \
+    typedef struct {                                                            \
+        uint32_t hash_and_flags;                                                \
+        key_t key;                                                              \
+        value_t value;                                                          \
+    } prefix##_slot_t, *prefix##_slot_p, *prefix##_it_p;                        \
+                                                                                \
+    typedef struct {                                                            \
+        uint32_t length, capacity, deleted;                                     \
+        prefix##_slot_p slots;                                                  \
+    } prefix##_t, *prefix##_p;                                                  \
+                                                                                \
+    void     prefix##_new(prefix##_p hash);                                     \
+    void     prefix##_destroy(prefix##_p hash);                                 \
+    void     prefix##_optimize(prefix##_p hash);                                \
+                                                                                \
+    void     prefix##_put(prefix##_p hash, key_t key, value_t value);           \
+    value_t  prefix##_get(prefix##_p hash, key_t key, value_t default_value);   \
+    bool     prefix##_del(prefix##_p hash, key_t key);                          \
+    bool     prefix##_contains(prefix##_p hash, key_t key);                     \
+                                                                                \
+    value_t* prefix##_put_ptr(prefix##_p hash, key_t key);                      \
+    value_t* prefix##_get_ptr(prefix##_p hash, key_t key);                      \
+                                                                                \
+    prefix##_it_p  prefix##_start(prefix##_p hash);                             \
+    prefix##_it_p  prefix##_next(prefix##_p hash, prefix##_it_p it);            \
+    void           prefix##_remove(prefix##_p hash, prefix##_it_p it);          \
 
 
-//
-// API
-//
-
-void sh_new(sh_hash_p hash);
-void sh_destroy(sh_hash_p hash);
-void sh_optimize(sh_hash_p hash);
-
-void sh_put(sh_hash_p hash, int64_t key, int value);
-int  sh_get(sh_hash_p hash, int64_t key, int default_value);
-bool sh_del(sh_hash_p hash, int64_t key);
-bool sh_contains(sh_hash_p hash, int64_t key);
-
-int* sh_put_ptr(sh_hash_p hash, int64_t key);
-int* sh_get_ptr(sh_hash_p hash, int64_t key);
-
-sh_it_p sh_start(sh_hash_p hash);
-sh_it_p sh_next(sh_hash_p hash, sh_it_p it);
-void    sh_remove(sh_hash_p hash, sh_it_p it);
 
 #endif // SLIM_HASH_HEADER
 
@@ -90,212 +90,233 @@ void    sh_remove(sh_hash_p hash, sh_it_p it);
 
 #ifdef SLIM_HASH_IMPLEMENTATION
 
+#define SH_GEN_DEF(prefix, key_t, value_t, hash_expr, key_cmp_expr, key_put_expr, key_del_expr)  \
+    /**                                                                          \
+     * Get 32-bit Murmur3 hash of a memory block. Taken from                     \
+     * https://github.com/wolkykim/qlibc/blob/master/src/utilities/qhash.c       \
+     *                                                                           \
+     * MurmurHash3 was created by Austin Appleby  in 2008. The initial           \
+     * implementation was published in C++ and placed in the public:             \
+     * https://sites.google.com/site/murmurhash/                                 \
+     *                                                                           \
+     * Seungyoung Kim has ported its implementation into C language in 2012 and  \
+     * published it as a part of qLibc component.                                \
+     **/                                                                         \
+    uint32_t prefix##_murmur3_32(const void *data, size_t size) {                \
+        if (data == NULL || size == 0)                                           \
+            return 0;                                                            \
+                                                                                 \
+        const uint32_t c1 = 0xcc9e2d51;                                          \
+        const uint32_t c2 = 0x1b873593;                                          \
+                                                                                 \
+        const int nblocks = size / 4;                                            \
+        const uint32_t *blocks = (const uint32_t *) (data);                      \
+        const uint8_t *tail = (const uint8_t *) (data + (nblocks * 4));          \
+                                                                                 \
+        uint32_t h = 0;                                                          \
+                                                                                 \
+        int i;                                                                   \
+        uint32_t k;                                                              \
+        for (i = 0; i < nblocks; i++) {                                          \
+            k = blocks[i];                                                       \
+                                                                                 \
+            k *= c1;                                                             \
+            k = (k << 15) | (k >> (32 - 15));                                    \
+            k *= c2;                                                             \
+                                                                                 \
+            h ^= k;                                                              \
+            h = (h << 13) | (h >> (32 - 13));                                    \
+            h = (h * 5) + 0xe6546b64;                                            \
+        }                                                                        \
+                                                                                 \
+        k = 0;                                                                   \
+        switch (size & 3) {                                                      \
+            case 3:                                                              \
+                k ^= tail[2] << 16;                                              \
+            case 2:                                                              \
+                k ^= tail[1] << 8;                                               \
+            case 1:                                                              \
+                k ^= tail[0];                                                    \
+                k *= c1;                                                         \
+                k = (k << 15) | (k >> (32 - 15));                                \
+                k *= c2;                                                         \
+                h ^= k;                                                          \
+        };                                                                       \
+                                                                                 \
+        h ^= size;                                                               \
+                                                                                 \
+        h ^= h >> 16;                                                            \
+        h *= 0x85ebca6b;                                                         \
+        h ^= h >> 13;                                                            \
+        h *= 0xc2b2ae35;                                                         \
+        h ^= h >> 16;                                                            \
+                                                                                 \
+        return h;                                                                \
+    }                                                                            \
+                                                                                 \
+    bool prefix##_resize(prefix##_p hashmap, uint32_t new_capacity) {                                   \
+        /* on filling empty slot: if exceeding load factor, double capacity                             \
+        // on deleting slot: if to empty, half capacity                                                 \
+                                                                                                        \
+        // Can't make hashmap smaller than it needs to be  */                                           \
+        if (new_capacity < hashmap->length)                                                             \
+            return false;                                                                               \
+                                                                                                        \
+        prefix##_t new_hashmap;                                                                         \
+        new_hashmap.length = 0;                                                                         \
+        new_hashmap.capacity = new_capacity;                                                            \
+        new_hashmap.deleted = 0;                                                                        \
+        new_hashmap.slots = calloc(new_hashmap.capacity, sizeof(new_hashmap.slots[0]));                 \
+                                                                                                        \
+        /* Failed to allocate memory for new hash map, leave the original untouched */                  \
+        if (new_hashmap.slots == NULL)                                                                  \
+            return false;                                                                               \
+                                                                                                        \
+        for(prefix##_it_p it = prefix##_start(hashmap); it != NULL; it = prefix##_next(hashmap, it)) {  \
+            prefix##_put(&new_hashmap, it->key, it->value);                                             \
+        }                                                                                               \
+                                                                                                        \
+        free(hashmap->slots);                                                                           \
+        *hashmap = new_hashmap;                                                                         \
+        return true;                                                                                    \
+    }                                                                                                   \
+                                                                                                        \
+    void prefix##_new(prefix##_p hashmap) {      \
+        hashmap->length = 0;                     \
+        hashmap->capacity = 0;                   \
+        hashmap->deleted = 0;                    \
+        hashmap->slots = NULL;                   \
+        prefix##_resize(hashmap, 8);             \
+    }                                            \
+                                                 \
+    void prefix##_destroy(prefix##_p hashmap) {  \
+        hashmap->length = 0;                     \
+        hashmap->capacity = 0;                   \
+        hashmap->deleted = 0;                    \
+        free(hashmap->slots);                    \
+        hashmap->slots = NULL;                   \
+    }                                            \
+                                                 \
+    value_t* prefix##_put_ptr(prefix##_p hashmap, key_t key) {                                                                                                                          \
+        /* add the +1 to the capacity doubling to avoid beeing stuck on a capacity of 0 */                                                                                              \
+        if (hashmap->length + hashmap->deleted + 1 > hashmap->capacity * 0.5)                                                                                                           \
+            prefix##_resize(hashmap, (hashmap->capacity + 1) * 2);                                                                                                                      \
+                                                                                                                                                                                        \
+        uint32_t hash = (hash_expr) | SH_SLOT_FILLED;                                                                                                                                   \
+        size_t index = hash % hashmap->capacity;                                                                                                                                        \
+        while ( !(hashmap->slots[index].hash_and_flags == hash || hashmap->slots[index].hash_and_flags == SH_SLOT_FREE || hashmap->slots[index].hash_and_flags == SH_SLOT_DELETED) ) {  \
+            index = (index + 1) % hashmap->capacity;                                                                                                                                    \
+        }                                                                                                                                                                               \
+                                                                                                                                                                                        \
+        if (hashmap->slots[index].hash_and_flags == SH_SLOT_DELETED)                                                                                                                    \
+            hashmap->deleted--;                                                                                                                                                         \
+        hashmap->length++;                                                                                                                                                              \
+        hashmap->slots[index].hash_and_flags = hash;                                                                                                                                    \
+        hashmap->slots[index].key = (key_put_expr);                                                                                                                                     \
+        return &hashmap->slots[index].value;                                                                                                                                            \
+    }                                                                                                                                                                                   \
+                                                                                                                                                                                        \
+    value_t* prefix##_get_ptr(prefix##_p hashmap, key_t key) {               \
+        uint32_t hash = (hash_expr) | SH_SLOT_FILLED;                        \
+        size_t index = hash % hashmap->capacity;                             \
+        while ( !(hashmap->slots[index].hash_and_flags == SH_SLOT_FREE) ) {  \
+            if (hashmap->slots[index].hash_and_flags == hash) {              \
+                key_t a = hashmap->slots[index].key;                         \
+                key_t b = key;                                               \
+                if (key_cmp_expr)                                            \
+                    return &hashmap->slots[index].value;                     \
+            }                                                                \
+                                                                             \
+            index = (index + 1) % hashmap->capacity;                         \
+        }                                                                    \
+                                                                             \
+        return NULL;                                                         \
+    }                                                                        \
+                                                                             \
+    bool prefix##_del(prefix##_p hashmap, key_t key) {                       \
+        uint32_t hash = (hash_expr) | SH_SLOT_FILLED;                        \
+        size_t index = hash % hashmap->capacity;                             \
+        while ( !(hashmap->slots[index].hash_and_flags == SH_SLOT_FREE) ) {  \
+            if (hashmap->slots[index].hash_and_flags == hash) {              \
+                key_t a = hashmap->slots[index].key;                         \
+                key_t b = key;                                               \
+                if (key_cmp_expr) {                                          \
+                    key_t key = hashmap->slots[index].key;                   \
+                    key = key; /* avoid unused variable warning */           \
+                    hashmap->slots[index].key = (key_del_expr);              \
+                    hashmap->slots[index].hash_and_flags = SH_SLOT_DELETED;  \
+                    hashmap->length--;                                       \
+                    hashmap->deleted++;                                      \
+                                                                             \
+                    if (hashmap->length < hashmap->capacity * 0.2)           \
+                        prefix##_resize(hashmap, hashmap->capacity / 2);     \
+                                                                             \
+                    return true;                                             \
+                }                                                            \
+            }                                                                \
+                                                                             \
+            index = (index + 1) % hashmap->capacity;                         \
+        }                                                                    \
+                                                                             \
+        return false;                                                        \
+    }                                                                        \
+                                                                             \
+    void prefix##_put(prefix##_p hashmap, key_t key, value_t value) {             \
+        *prefix##_put_ptr(hashmap, key) = value;                                  \
+    }                                                                             \
+                                                                                  \
+    value_t prefix##_get(prefix##_p hashmap, key_t key, value_t default_value) {  \
+        value_t* value_ptr = prefix##_get_ptr(hashmap, key);                      \
+        return (value_ptr) ? *value_ptr : default_value;                          \
+    }                                                                             \
+                                                                                  \
+    bool prefix##_contains(prefix##_p hashmap, key_t key) {                       \
+        return (prefix##_get_ptr(hashmap, key) != NULL);                          \
+    }                                                                             \
+                                                                                  \
+    /* Search for the first not-empty slot */                                                    \
+    prefix##_it_p prefix##_start(prefix##_p hashmap) {                                           \
+        /* We need to start at an invalid slot address since sh_next() increments it             \
+        // before it looks at it (so it's safe). */                                              \
+        return prefix##_next(hashmap, hashmap->slots - 1);                                       \
+    }                                                                                            \
+                                                                                                 \
+    prefix##_it_p prefix##_next(prefix##_p hashmap, prefix##_it_p it) {                          \
+        if (it == NULL)                                                                          \
+            return NULL;                                                                         \
+                                                                                                 \
+        do {                                                                                     \
+            it++;                                                                                \
+            /* Check if we're past the last slot */                                              \
+            if (it - hashmap->slots >= hashmap->capacity)                                        \
+                return NULL;                                                                     \
+        } while( it->hash_and_flags == SH_SLOT_FREE || it->hash_and_flags == SH_SLOT_DELETED );  \
+                                                                                                 \
+        return it;                                                                               \
+    }                                                                                            \
+                                                                                                 \
+    void prefix##_remove(prefix##_p hashmap, prefix##_it_p it) {                                 \
+        if (it != NULL && it >= hashmap->slots && it - hashmap->slots < hashmap->capacity) {     \
+            key_t key = it->key;                                                                 \
+            key = key; /* avoid unused variable warning */                                       \
+            key = key; /* avoid unused variable warning */                                       \
+            it->key = (key_del_expr);                                                            \
+            it->hash_and_flags = SH_SLOT_DELETED;                                                \
+                                                                                                 \
+            hashmap->length--;                                                                   \
+            hashmap->deleted++;                                                                  \
+        }                                                                                        \
+    }                                                                                            \
+                                                                                                 \
+    void prefix##_optimize(prefix##_p hashmap) {      \
+        prefix##_resize(hashmap, hashmap->capacity);  \
+    }                                                 \
+
+
+#define SH_GEN_HASH_DEF(prefix, key_t, value_t)  \
+             SH_GEN_DEF(prefix, key_t, value_t, prefix##_murmur3_32(&key, sizeof(key)), (a == b), key, 0)
+#define SH_GEN_DICT_DEF(prefix, key_t, value_t)  \
+             SH_GEN_DEF(prefix, key_t, value_t, prefix##_murmur3_32(key, strlen(key)), (strcmp(a, b) == 0), strdup(key), (free((void*)key), NULL))
 
-/**
- * Get 32-bit Murmur3 hash of a memory block. Taken from
- * https://github.com/wolkykim/qlibc/blob/master/src/utilities/qhash.c
- *
- * MurmurHash3 was created by Austin Appleby  in 2008. The initial implementation
- * was published in C++ and placed in the public: https://sites.google.com/site/murmurhash/
- * 
- * Seungyoung Kim has ported its implementation into C language in 2012 and
- * published it as a part of qLibc component.
- */
-uint32_t sh_murmur3_32(const void *data, size_t size) {
-    if (data == NULL || size == 0)
-        return 0;
-
-    const uint32_t c1 = 0xcc9e2d51;
-    const uint32_t c2 = 0x1b873593;
-
-    const int nblocks = size / 4;
-    const uint32_t *blocks = (const uint32_t *) (data);
-    const uint8_t *tail = (const uint8_t *) (data + (nblocks * 4));
-
-    uint32_t h = 0;
-
-    int i;
-    uint32_t k;
-    for (i = 0; i < nblocks; i++) {
-        k = blocks[i];
-
-        k *= c1;
-        k = (k << 15) | (k >> (32 - 15));
-        k *= c2;
-
-        h ^= k;
-        h = (h << 13) | (h >> (32 - 13));
-        h = (h * 5) + 0xe6546b64;
-    }
-
-    k = 0;
-    switch (size & 3) {
-        case 3:
-            k ^= tail[2] << 16;
-        case 2:
-            k ^= tail[1] << 8;
-        case 1:
-            k ^= tail[0];
-            k *= c1;
-            k = (k << 15) | (k >> (32 - 15));
-            k *= c2;
-            h ^= k;
-    };
-
-    h ^= size;
-
-    h ^= h >> 16;
-    h *= 0x85ebca6b;
-    h ^= h >> 13;
-    h *= 0xc2b2ae35;
-    h ^= h >> 16;
-
-    return h;
-}
-
-
-bool sh_resize(sh_hash_p hashmap, size_t new_capacity) {
-       // on filling empty slot: if exceeding load factor, double capacity
-       // on deleting slot: if to empty, half capacity
-       
-       // Can't make hashmap smaller than it needs to be
-       if (new_capacity < hashmap->length)
-               return false;
-       
-       sh_hash_t new_hashmap;
-       new_hashmap.length = 0;
-       new_hashmap.capacity = new_capacity;
-       new_hashmap.deleted = 0;
-       new_hashmap.slots = calloc(new_hashmap.capacity, sizeof(new_hashmap.slots[0]));
-       
-       // Failed to allocate memory for new hash map, leave the original untouched
-       if (new_hashmap.slots == NULL)
-               return false;
-       
-       for(sh_it_p it = sh_start(hashmap); it != NULL; it = sh_next(hashmap, it)) {
-               sh_put(&new_hashmap, it->key, it->value);
-       }
-       
-       free(hashmap->slots);
-       *hashmap = new_hashmap;
-       return true;
-}
-
-void sh_new(sh_hash_p hashmap) {
-       hashmap->length = 0;
-       hashmap->capacity = 0;
-       hashmap->deleted = 0;
-       hashmap->slots = NULL;
-       sh_resize(hashmap, 8);
-}
-
-void sh_destroy(sh_hash_p hashmap) {
-       hashmap->length = 0;
-       hashmap->capacity = 0;
-       hashmap->deleted = 0;
-       free(hashmap->slots);
-       hashmap->slots = NULL;
-}
-
-
-int* sh_put_ptr(sh_hash_p hashmap, int64_t key) {
-       // add the +1 to the capacity doubling to avoid beeing stuck on a capacity of 0
-       if (hashmap->length + hashmap->deleted + 1 > hashmap->capacity * 0.5)
-               sh_resize(hashmap, (hashmap->capacity + 1) * 2);
-       
-       uint32_t hash = sh_murmur3_32(&key, sizeof(key)) | 0x80000000;
-       size_t index = hash % hashmap->capacity;
-       while ( !(hashmap->slots[index].hash_and_flags == SH_SLOT_FREE || hashmap->slots[index].hash_and_flags == SH_SLOT_DELETED) ) {
-               index = (index + 1) % hashmap->capacity;
-       }
-       
-       if (hashmap->slots[index].hash_and_flags == SH_SLOT_DELETED)
-               hashmap->deleted--;
-       hashmap->length++;
-       hashmap->slots[index].hash_and_flags = hash;
-       hashmap->slots[index].key = key;
-       return &hashmap->slots[index].value;
-}
-
-int* sh_get_ptr(sh_hash_p hashmap, int64_t key) {
-       uint32_t hash = sh_murmur3_32(&key, sizeof(key)) | 0x80000000;
-       size_t index = hash % hashmap->capacity;
-       while ( !(hashmap->slots[index].hash_and_flags == SH_SLOT_FREE) ) {
-               if (hashmap->slots[index].hash_and_flags == hash && hashmap->slots[index].key == key)
-                       return &hashmap->slots[index].value;
-               
-               index = (index + 1) % hashmap->capacity;
-       }
-       
-       return NULL;
-}
-
-bool sh_del(sh_hash_p hashmap, int64_t key) {
-       uint32_t hash = sh_murmur3_32(&key, sizeof(key)) | 0x80000000;
-       size_t index = hash % hashmap->capacity;
-       while ( !(hashmap->slots[index].hash_and_flags == SH_SLOT_FREE) ) {
-               if (hashmap->slots[index].hash_and_flags == hash && hashmap->slots[index].key == key) {
-                       hashmap->slots[index].hash_and_flags = SH_SLOT_DELETED;
-                       hashmap->length--;
-                       hashmap->deleted++;
-                       
-                       if (hashmap->length < hashmap->capacity * 0.2)
-                               sh_resize(hashmap, hashmap->capacity / 2);
-                       
-                       return true;
-               }
-               
-               index = (index + 1) % hashmap->capacity;
-       }
-       
-       return false;
-}
-
-void sh_put(sh_hash_p hashmap, int64_t key, int value) {
-       *sh_put_ptr(hashmap, key) = value;
-}
-
-int sh_get(sh_hash_p hashmap, int64_t key, int default_value) {
-       int* value_ptr = sh_get_ptr(hashmap, key);
-       return (value_ptr) ? *value_ptr : default_value;
-}
-
-bool sh_contains(sh_hash_p hashmap, int64_t key) {
-       return (sh_get_ptr(hashmap, key) != NULL);
-}
-
-// Search for the first not-empty slot
-sh_it_p sh_start(sh_hash_p hashmap) {
-       // We need to start at an invalid slot address since sh_next() increments it
-       // before it looks at it (so it's safe).
-       return sh_next(hashmap, hashmap->slots - 1);
-}
-
-sh_it_p sh_next(sh_hash_p hashmap, sh_it_p it) {
-       if (it == NULL)
-               return NULL;
-       
-       do {
-               it++;
-               // Check if we're past the last slot
-               if (it - hashmap->slots >= hashmap->capacity)
-                       return NULL;
-       } while( it->hash_and_flags == SH_SLOT_FREE || it->hash_and_flags == SH_SLOT_DELETED );
-       
-       return it;
-}
-
-void sh_remove(sh_hash_p hashmap, sh_it_p it) {
-       if (it != NULL && it >= hashmap->slots && it - hashmap->slots < hashmap->capacity) {
-               it->hash_and_flags = SH_SLOT_DELETED;
-               
-               hashmap->length--;
-               hashmap->deleted++;
-       }
-}
-
-void sh_optimize(sh_hash_p hashmap) {
-       sh_resize(hashmap, hashmap->capacity);
-}
 
 #endif // SLIM_HASH_IMPLEMENTATION
\ No newline at end of file
index 45b21f4..fb08c32 100644 (file)
@@ -1,14 +1,22 @@
+// For strdup()
+#define _GNU_SOURCE
+#include <string.h>
+
 #define SLIM_HASH_IMPLEMENTATION
 #include "../slim_hash.h"
 #define SLIM_TEST_IMPLEMENTATION
 #include "../slim_test.h"
 
 
+SH_GEN_DECL(sh, int64_t, int);
+SH_GEN_HASH_DEF(sh, int64_t, int);
 
+SH_GEN_DECL(dict, const char*, int);
+SH_GEN_DICT_DEF(dict, const char*, int);
 
 
 void test_new_and_destroy() {
-       sh_hash_t hash;
+       sh_t hash;
        
        sh_new(&hash);
        st_check_int(hash.length, 0);
@@ -20,7 +28,7 @@ void test_new_and_destroy() {
 }
 
 void test_put_ptr() {
-       sh_hash_t hash;
+       sh_t hash;
        sh_new(&hash);
        
        int* ptr = sh_put_ptr(&hash, 174);
@@ -33,7 +41,7 @@ void test_put_ptr() {
 }
 
 void test_get_ptr() {
-       sh_hash_t hash;
+       sh_t hash;
        sh_new(&hash);
        
        int* put_ptr = sh_put_ptr(&hash, 174);
@@ -46,7 +54,7 @@ void test_get_ptr() {
 }
 
 void test_get_ptr_not_found() {
-       sh_hash_t hash;
+       sh_t hash;
        sh_new(&hash);
        
        int* get_ptr = sh_get_ptr(&hash, 12345);
@@ -64,7 +72,7 @@ void test_get_ptr_not_found() {
 }
 
 void test_del() {
-       sh_hash_t hash;
+       sh_t hash;
        sh_new(&hash);
        
        int* put_ptr = sh_put_ptr(&hash, 174);
@@ -83,7 +91,7 @@ void test_del() {
 }
 
 void test_get_and_put() {
-       sh_hash_t hash;
+       sh_t hash;
        sh_new(&hash);
        
        sh_put(&hash, 1, 10);
@@ -97,7 +105,7 @@ void test_get_and_put() {
 }
 
 void test_contains() {
-       sh_hash_t hash;
+       sh_t hash;
        sh_new(&hash);
        
        sh_put(&hash, 1, 10);
@@ -111,7 +119,7 @@ void test_contains() {
 }
 
 void test_iteration() {
-       sh_hash_t hash;
+       sh_t hash;
        sh_new(&hash);
        
        // empty hash
@@ -145,7 +153,7 @@ void test_iteration() {
 }
 
 void test_remove_during_iteration() {
-       sh_hash_t hash;
+       sh_t hash;
        sh_new(&hash);
        
        sh_put(&hash, 0, 10);
@@ -165,7 +173,7 @@ void test_remove_during_iteration() {
 }
 
 void test_growing() {
-       sh_hash_t hash;
+       sh_t hash;
        sh_new(&hash);
        st_check_int(hash.length, 0);
        st_check(hash.capacity < 100);
@@ -184,7 +192,7 @@ void test_growing() {
 }
 
 void test_shrinking() {
-       sh_hash_t hash;
+       sh_t hash;
        sh_new(&hash);
        st_check(hash.capacity < 100);
        
@@ -201,7 +209,7 @@ void test_shrinking() {
 }
 
 void test_optimize() {
-       sh_hash_t hash;
+       sh_t hash;
        sh_new(&hash);
        
        for(size_t i = 0; i < 100; i++)
@@ -220,6 +228,45 @@ void test_optimize() {
        sh_destroy(&hash);
 }
 
+void test_dict() {
+       dict_t dict;
+       dict_new(&dict);
+       
+       dict_put(&dict, "a", 1);
+       st_check_int(dict_contains(&dict, "a"), 1);
+       st_check_int(dict_contains(&dict, "b"), 0);
+       st_check_int(dict_get(&dict, "a", 0), 1);
+       
+       dict_put(&dict, "b", 2);
+       dict_put(&dict, "c", 3);
+       st_check_int(dict_get(&dict, "b", 0), 2);
+       st_check_int(dict_get(&dict, "c", 0), 3);
+       
+       dict_del(&dict, "b");
+       st_check_int(dict_get(&dict, "a", 0), 1);
+       st_check_int(dict_get(&dict, "b", 0), 0);
+       st_check_int(dict_get(&dict, "c", 0), 3);
+       
+       dict_destroy(&dict);
+}
+
+void test_dict_update() {
+       dict_t dict;
+       dict_new(&dict);
+       
+       dict_put(&dict, "x", 7);
+       st_check_int(dict_get(&dict, "x", 0), 7);
+       dict_put(&dict, "x", 1);
+       st_check_int(dict_get(&dict, "x", 0), 1);
+       
+       dict_del(&dict, "x");
+       st_check_int(dict_get(&dict, "x", 0), 0);
+       dict_put(&dict, "x", 3);
+       st_check_int(dict_get(&dict, "x", 0), 3);
+       
+       dict_destroy(&dict);
+}
+
 
 int main() {
        st_run(test_new_and_destroy);
@@ -234,5 +281,7 @@ int main() {
        st_run(test_growing);
        st_run(test_shrinking);
        st_run(test_optimize);
+       st_run(test_dict);
+       st_run(test_dict_update);
        return st_show_report();
 }
\ No newline at end of file