add single instance mode
[uwplayer.git] / ucx / hash_map.c
index 48e7d3e..8b8cd20 100644 (file)
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <string.h>
 #include "cx/hash_map.h"
 #include "cx/utils.h"
 
+#include <string.h>
+#include <assert.h>
+
 struct cx_hash_map_element_s {
     /** A pointer to the next element in the current bucket. */
     struct cx_hash_map_element_s *next;
@@ -48,8 +50,10 @@ static void cx_hash_map_clear(struct cx_map_s *map) {
         if (elem != NULL) {
             do {
                 struct cx_hash_map_element_s *next = elem->next;
+                // invoke the destructor
+                cx_invoke_destructor(map, elem->data);
                 // free the key data
-                cxFree(map->allocator, elem->key.data.obj);
+                cxFree(map->allocator, (void *) elem->key.data);
                 // free the node
                 cxFree(map->allocator, elem);
                 // proceed
@@ -80,7 +84,7 @@ static int cx_hash_map_put(
         void *value
 ) {
     struct cx_hash_map_s *hash_map = (struct cx_hash_map_s *) map;
-    CxAllocator *allocator = map->allocator;
+    CxAllocator const *allocator = map->allocator;
 
     unsigned hash = key.hash;
     if (hash == 0) {
@@ -98,28 +102,28 @@ static int cx_hash_map_put(
     }
 
     if (elm != NULL && elm->key.hash == hash && elm->key.len == key.len &&
-        memcmp(elm->key.data.obj, key.data.obj, key.len) == 0) {
+        memcmp(elm->key.data, key.data, key.len) == 0) {
         // overwrite existing element
-        if (map->store_pointers) {
+        if (map->store_pointer) {
             memcpy(elm->data, &value, sizeof(void *));
         } else {
-            memcpy(elm->data, value, map->itemsize);
+            memcpy(elm->data, value, map->item_size);
         }
     } else {
         // allocate new element
         struct cx_hash_map_element_s *e = cxMalloc(
                 allocator,
-                sizeof(struct cx_hash_map_element_s) + map->itemsize
+                sizeof(struct cx_hash_map_element_s) + map->item_size
         );
         if (e == NULL) {
             return -1;
         }
 
         // write the value
-        if (map->store_pointers) {
+        if (map->store_pointer) {
             memcpy(e->data, &value, sizeof(void *));
         } else {
-            memcpy(e->data, value, map->itemsize);
+            memcpy(e->data, value, map->item_size);
         }
 
         // copy the key
@@ -127,8 +131,8 @@ static int cx_hash_map_put(
         if (kd == NULL) {
             return -1;
         }
-        memcpy(kd, key.data.obj, key.len);
-        e->key.data.obj = kd;
+        memcpy(kd, key.data, key.len);
+        e->key.data = kd;
         e->key.len = key.len;
         e->key.hash = hash;
 
@@ -160,7 +164,7 @@ static void cx_hash_map_unlink(
         prev->next = elm->next;
     }
     // free element
-    cxFree(hash_map->base.allocator, elm->key.data.obj);
+    cxFree(hash_map->base.allocator, (void *) elm->key.data);
     cxFree(hash_map->base.allocator, elm);
     // decrease size
     hash_map->base.size--;
@@ -172,12 +176,14 @@ static void cx_hash_map_unlink(
  * @param map the map
  * @param key the key to look up
  * @param remove flag indicating whether the looked up entry shall be removed
+ * @param destroy flag indicating whether the destructor shall be invoked
  * @return a pointer to the value corresponding to the key or \c NULL
  */
 static void *cx_hash_map_get_remove(
         CxMap *map,
         CxHashKey key,
-        bool remove
+        bool remove,
+        bool destroy
 ) {
     struct cx_hash_map_s *hash_map = (struct cx_hash_map_s *) map;
 
@@ -192,12 +198,16 @@ static void *cx_hash_map_get_remove(
     struct cx_hash_map_element_s *prev = NULL;
     while (elm && elm->key.hash <= hash) {
         if (elm->key.hash == hash && elm->key.len == key.len) {
-            if (memcmp(elm->key.data.obj, key.data.obj, key.len) == 0) {
+            if (memcmp(elm->key.data, key.data, key.len) == 0) {
                 void *data = NULL;
-                if (map->store_pointers) {
-                    data = *(void **) elm->data;
-                } else if (!remove) {
-                    data = elm->data;
+                if (destroy) {
+                    cx_invoke_destructor(map, elm->data);
+                } else {
+                    if (map->store_pointer) {
+                        data = *(void **) elm->data;
+                    } else {
+                        data = elm->data;
+                    }
                 }
                 if (remove) {
                     cx_hash_map_unlink(hash_map, slot, prev, elm);
@@ -216,15 +226,16 @@ static void *cx_hash_map_get(
         CxMap const *map,
         CxHashKey key
 ) {
-    // we can safely cast, because we know when remove=false, the map stays untouched
-    return cx_hash_map_get_remove((CxMap *) map, key, false);
+    // we can safely cast, because we know the map stays untouched
+    return cx_hash_map_get_remove((CxMap *) map, key, false, false);
 }
 
 static void *cx_hash_map_remove(
         CxMap *map,
-        CxHashKey key
+        CxHashKey key,
+        bool destroy
 ) {
-    return cx_hash_map_get_remove(map, key, true);
+    return cx_hash_map_get_remove(map, key, true, destroy);
 }
 
 static void *cx_hash_map_iter_current_entry(void const *it) {
@@ -243,7 +254,7 @@ static void *cx_hash_map_iter_current_value(void const *it) {
     struct cx_iterator_s const *iter = it;
     struct cx_hash_map_s const *map = iter->src_handle;
     struct cx_hash_map_element_s *elm = iter->elem_handle;
-    if (map->base.store_pointers) {
+    if (map->base.store_pointer) {
         return *(void **) elm->data;
     } else {
         return elm->data;
@@ -280,6 +291,9 @@ static void cx_hash_map_iter_next(void *it) {
             }
         }
 
+        // destroy
+        cx_invoke_destructor((struct cx_map_s *) map, elm->data);
+
         // unlink
         cx_hash_map_unlink(map, iter->slot, prev, elm);
 
@@ -304,7 +318,7 @@ static void cx_hash_map_iter_next(void *it) {
         iter->kv_data.value = NULL;
     } else {
         iter->kv_data.key = &elm->key;
-        if (map->base.store_pointers) {
+        if (map->base.store_pointer) {
             iter->kv_data.value = *(void **) elm->data;
         } else {
             iter->kv_data.value = elm->data;
@@ -322,13 +336,30 @@ static bool cx_hash_map_iter_flag_rm(void *it) {
     }
 }
 
-static CxIterator cx_hash_map_iterator(CxMap const *map) {
+static CxIterator cx_hash_map_iterator(
+        CxMap const *map,
+        enum cx_map_iterator_type type
+) {
     CxIterator iter;
 
     iter.src_handle = map;
     iter.base.valid = cx_hash_map_iter_valid;
     iter.base.next = cx_hash_map_iter_next;
-    iter.base.current = cx_hash_map_iter_current_entry;
+
+    switch (type) {
+        case CX_MAP_ITERATOR_PAIRS:
+            iter.base.current = cx_hash_map_iter_current_entry;
+            break;
+        case CX_MAP_ITERATOR_KEYS:
+            iter.base.current = cx_hash_map_iter_current_key;
+            break;
+        case CX_MAP_ITERATOR_VALUES:
+            iter.base.current = cx_hash_map_iter_current_value;
+            break;
+        default:
+            assert(false);
+    }
+
     iter.base.flag_removal = cx_hash_map_iter_flag_rm;
     iter.base.remove = false;
     iter.base.mutating = false;
@@ -344,7 +375,7 @@ static CxIterator cx_hash_map_iterator(CxMap const *map) {
         }
         iter.elem_handle = elm;
         iter.kv_data.key = &elm->key;
-        if (map->store_pointers) {
+        if (map->store_pointer) {
             iter.kv_data.value = *(void **) elm->data;
         } else {
             iter.kv_data.value = elm->data;
@@ -358,40 +389,6 @@ static CxIterator cx_hash_map_iterator(CxMap const *map) {
     return iter;
 }
 
-static CxIterator cx_hash_map_iterator_keys(CxMap const *map) {
-    CxIterator iter = cx_hash_map_iterator(map);
-    iter.base.current = cx_hash_map_iter_current_key;
-    return iter;
-}
-
-static CxIterator cx_hash_map_iterator_values(CxMap const *map) {
-    CxIterator iter = cx_hash_map_iterator(map);
-    iter.base.current = cx_hash_map_iter_current_value;
-    return iter;
-}
-
-static CxMutIterator cx_hash_map_mut_iterator(CxMap *map) {
-    CxIterator it = cx_hash_map_iterator(map);
-    it.base.mutating = true;
-
-    // we know the iterators share the same memory layout
-    CxMutIterator iter;
-    memcpy(&iter, &it, sizeof(CxMutIterator));
-    return iter;
-}
-
-static CxMutIterator cx_hash_map_mut_iterator_keys(CxMap *map) {
-    CxMutIterator iter = cx_hash_map_mut_iterator(map);
-    iter.base.current = cx_hash_map_iter_current_key;
-    return iter;
-}
-
-static CxMutIterator cx_hash_map_mut_iterator_values(CxMap *map) {
-    CxMutIterator iter = cx_hash_map_mut_iterator(map);
-    iter.base.current = cx_hash_map_iter_current_value;
-    return iter;
-}
-
 static cx_map_class cx_hash_map_class = {
         cx_hash_map_destructor,
         cx_hash_map_clear,
@@ -399,15 +396,10 @@ static cx_map_class cx_hash_map_class = {
         cx_hash_map_get,
         cx_hash_map_remove,
         cx_hash_map_iterator,
-        cx_hash_map_iterator_keys,
-        cx_hash_map_iterator_values,
-        cx_hash_map_mut_iterator,
-        cx_hash_map_mut_iterator_keys,
-        cx_hash_map_mut_iterator_values,
 };
 
 CxMap *cxHashMapCreate(
-        CxAllocator *allocator,
+        CxAllocator const *allocator,
         size_t itemsize,
         size_t buckets
 ) {
@@ -416,12 +408,14 @@ CxMap *cxHashMapCreate(
         buckets = 16;
     }
 
-    struct cx_hash_map_s *map = cxMalloc(allocator, sizeof(struct cx_hash_map_s));
+    struct cx_hash_map_s *map = cxCalloc(allocator, 1,
+                                         sizeof(struct cx_hash_map_s));
     if (map == NULL) return NULL;
 
     // initialize hash map members
     map->bucket_count = buckets;
-    map->buckets = cxCalloc(allocator, buckets, sizeof(struct cx_hash_map_element_s *));
+    map->buckets = cxCalloc(allocator, buckets,
+                            sizeof(struct cx_hash_map_element_s *));
     if (map->buckets == NULL) {
         cxFree(allocator, map);
         return NULL;
@@ -430,14 +424,13 @@ CxMap *cxHashMapCreate(
     // initialize base members
     map->base.cl = &cx_hash_map_class;
     map->base.allocator = allocator;
-    map->base.size = 0;
 
     if (itemsize > 0) {
-        map->base.store_pointers = false;
-        map->base.itemsize = itemsize;
+        map->base.store_pointer = false;
+        map->base.item_size = itemsize;
     } else {
-        map->base.store_pointers = true;
-        map->base.itemsize = sizeof(void *);
+        map->base.store_pointer = true;
+        map->base.item_size = sizeof(void *);
     }
 
     return (CxMap *) map;
@@ -448,8 +441,10 @@ int cxMapRehash(CxMap *map) {
     if (map->size > ((hash_map->bucket_count * 3) >> 2)) {
 
         size_t new_bucket_count = (map->size * 5) >> 1;
-        struct cx_hash_map_element_s **new_buckets = cxCalloc(map->allocator,
-                                                              new_bucket_count, sizeof(struct cx_hash_map_element_s *));
+        struct cx_hash_map_element_s **new_buckets = cxCalloc(
+                map->allocator,
+                new_bucket_count, sizeof(struct cx_hash_map_element_s *)
+        );
 
         if (new_buckets == NULL) {
             return 1;
@@ -465,7 +460,8 @@ int cxMapRehash(CxMap *map) {
                 // find position where to insert
                 struct cx_hash_map_element_s *bucket_next = new_buckets[new_slot];
                 struct cx_hash_map_element_s *bucket_prev = NULL;
-                while (bucket_next != NULL && bucket_next->key.hash < elm->key.hash) {
+                while (bucket_next != NULL &&
+                       bucket_next->key.hash < elm->key.hash) {
                     bucket_prev = bucket_next;
                     bucket_next = bucket_next->next;
                 }