]> git.seodisparate.com - UDPConnection/commitdiff
Fixes to Unit Test, attempt to improve hash use
authorStephen Seo <seo.disparate@gmail.com>
Wed, 13 Feb 2019 08:49:24 +0000 (17:49 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Wed, 13 Feb 2019 08:49:24 +0000 (17:49 +0900)
src/UDPC_HashMap.c
src/UDPC_HashMap.h
src/test/UDPC_UnitTest.c
src/test/UDPC_UnitTest.h

index f81d2c348c69e8810a597816084f19d0a5e9d580..6b31f2ec2267fcdef03a5a60027a6229c0c71a5d 100644 (file)
@@ -90,7 +90,7 @@ void* UDPC_HashMap_insert(UDPC_HashMap *hm, uint32_t key, void *data)
         }
     }
 
-    uint32_t hash = UDPC_HASH32(key) % hm->capacity;
+    uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
 
     char *temp = malloc(4 + hm->unitSize);
     memcpy(temp, &key, 4);
@@ -101,7 +101,19 @@ void* UDPC_HashMap_insert(UDPC_HashMap *hm, uint32_t key, void *data)
 
     if(UDPC_Deque_get_available(hm->buckets[hash]) == 0)
     {
-        if(UDPC_Deque_push_back(hm->overflow, temp, 4 + hm->unitSize) == 0)
+        if(UDPC_Deque_get_available(hm->overflow) == 0)
+        {
+            free(temp);
+            if(UDPC_HashMap_realloc(hm, hm->capacity * 2) != 0)
+            {
+                return UDPC_HashMap_INTERNAL_reinsert(hm, key, data);
+            }
+            else
+            {
+                return NULL;
+            }
+        }
+        else if(UDPC_Deque_push_back(hm->overflow, temp, 4 + hm->unitSize) == 0)
         {
             free(temp);
             return NULL;
@@ -126,7 +138,7 @@ int UDPC_HashMap_remove(UDPC_HashMap *hm, uint32_t key)
         return 0;
     }
 
-    uint32_t hash = UDPC_HASH32(key) % hm->capacity;
+    uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
 
     for(int x = 0; x * (4 + hm->unitSize) < hm->buckets[hash]->size; ++x)
     {
@@ -178,7 +190,7 @@ void* UDPC_HashMap_get(UDPC_HashMap *hm, uint32_t key)
         return NULL;
     }
 
-    uint32_t hash = UDPC_HASH32(key) % hm->capacity;
+    uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
 
     for(int x = 0; x * (4 + hm->unitSize) < hm->buckets[hash]->size; ++x)
     {
@@ -239,7 +251,7 @@ int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
         for(int y = 0; y * (4 + hm->unitSize) < hm->buckets[x]->size; ++y)
         {
             data = UDPC_Deque_index_ptr(hm->buckets[x], 4 + hm->unitSize, y);
-            hash = UDPC_HASH32(*((uint32_t*)data)) % newCapacity;
+            hash = UDPC_HASHMAP_MOD(*((uint32_t*)data), newCapacity);
             if(newBuckets[hash]->size < newBuckets[hash]->alloc_size)
             {
                 if(UDPC_Deque_push_back(newBuckets[hash], data, 4 + hm->unitSize) == 0)
@@ -265,7 +277,7 @@ int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
         for(int x = 0; x * (4 + hm->unitSize) < hm->overflow->size; ++x)
         {
             data = UDPC_Deque_index_ptr(hm->overflow, 4 + hm->unitSize, x);
-            hash = UDPC_HASH32(*((uint32_t*)data)) % newCapacity;
+            hash = UDPC_HASHMAP_MOD(*((uint32_t*)data), newCapacity);
             if(newBuckets[hash]->size < newBuckets[hash]->alloc_size)
             {
                 if(UDPC_Deque_push_back(newBuckets[hash], data, 4 + hm->unitSize) == 0)
@@ -328,3 +340,44 @@ uint32_t UDPC_HashMap_get_capacity(UDPC_HashMap *hm)
 {
     return hm->capacity;
 }
+
+void* UDPC_HashMap_INTERNAL_reinsert(UDPC_HashMap *hm, uint32_t key, void *data)
+{
+    if(hm->capacity <= hm->size)
+    {
+        return NULL;
+    }
+
+    uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
+
+    char *temp = malloc(4 + hm->unitSize);
+    memcpy(temp, &key, 4);
+    if(hm->unitSize > 0)
+    {
+        memcpy(temp + 4, data, hm->unitSize);
+    }
+
+    if(UDPC_Deque_get_available(hm->buckets[hash]) == 0)
+    {
+        if(UDPC_Deque_get_available(hm->overflow) == 0)
+        {
+            free(temp);
+            return NULL;
+        }
+        else if(UDPC_Deque_push_back(hm->overflow, temp, 4 + hm->unitSize) == 0)
+        {
+            free(temp);
+            return NULL;
+        }
+    }
+    else if(UDPC_Deque_push_back(hm->buckets[hash], temp, 4 + hm->unitSize) == 0)
+    {
+        free(temp);
+        return NULL;
+    }
+
+    free(temp);
+    ++hm->size;
+    temp = UDPC_Deque_get_back_ptr(hm->buckets[hash], 4 + hm->unitSize);
+    return temp + 4;
+}
index e58712c10219a8632fe97110e87686d8d4bd35aa..bbe35b0dc7f77d8469870104842f0a8637053922 100644 (file)
     ) ^ 0x96969696 \
 )
 
-#define UDPC_HASHMAP_INIT_CAPACITY 8
+#define UDPC_HASHMAP_INIT_CAPACITY 13
 #define UDPC_HASHMAP_BUCKET_SIZE 4
 
+#define UDPC_HASHMAP_MOD(k, m) ((UDPC_HASH32(k) % (m * 2 + 1)) % m)
+
 #include "UDPC_Deque.h"
 
 typedef struct {
@@ -46,6 +48,9 @@ void UDPC_HashMap_destroy(UDPC_HashMap *hashMap);
  * Note if size already equals capacity, the hash map's capacity is doubled
  * with UDPC_HashMap_realloc(). realloc requires rehashing of all items which
  * may be costly.
+ * Also, if the hash map runs out of space for a specific key to insert, it will
+ * also invoke realloc() with double the previous capacity and will attempt to
+ * insert again afterwards.
  * It is possible to insert items with duplicate keys. In that case, the first
  * duplicate inserted will be the first returned with get() and first removed
  * with remove().
@@ -86,4 +91,9 @@ uint32_t UDPC_HashMap_get_size(UDPC_HashMap *hm);
 
 uint32_t UDPC_HashMap_get_capacity(UDPC_HashMap *hm);
 
+/*!
+ * \brief A variant of insert that does not try to realloc() on no more space
+ */
+void* UDPC_HashMap_INTERNAL_reinsert(UDPC_HashMap *hm, uint32_t key, void *data);
+
 #endif
index 0fd71a8cbf25ea0d0b685437af7af3bb5ca73d45..9da1f86ef388a8cabf35ed57ec66c60b2843ae75 100644 (file)
@@ -281,7 +281,7 @@ void TEST_HASHMAP()
         temp = x * 100;
         ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
     }
-    ASSERT_EQ(hm->capacity, 8);
+    ASSERT_GTE(hm->capacity, 8);
 
     temp = 800;
     ASSERT_NEQ(UDPC_HashMap_insert(hm, 8, &temp), NULL);
@@ -290,14 +290,27 @@ void TEST_HASHMAP()
         temp = x * 100;
         ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
     }
-    ASSERT_EQ(hm->capacity, 16);
+    ASSERT_GTE(hm->capacity, 16);
 
     for(int x = 0; x < 9; ++x)
     {
         ASSERT_NEQ(UDPC_HashMap_remove(hm, x), 0);
     }
     ASSERT_EQ(hm->size, 0);
-    ASSERT_EQ(hm->capacity, 16);
+    ASSERT_GTE(hm->capacity, 16);
+
+    for(int x = 0; x < 32; ++x)
+    {
+        temp = x * 100;
+        ASSERT_NEQ(UDPC_HashMap_insert(hm, x, &temp), NULL);
+    }
+    ASSERT_EQ(hm->size, 32);
+
+    for(int x = 0; x < 32; ++x)
+    {
+        temp = x * 100;
+        ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
+    }
 
     // TODO DEBUG
     /*
index b98950c1df0c780342e23341a8817c5002c0174c..19407615f33a48d4be772d624817e06136e49b1a 100644 (file)
 #define ASSERT_NEQ_MEM(x, y, size) \
     if(memcmp(x, y, size) == 0) { printf("%d: ASSERT_NEQ_MEM(%s, %s, %s) FAILED\n", \
             __LINE__, #x, #y, #size); ++UDPC_uts.failed; } ++UDPC_uts.total;
+#define ASSERT_GT(x, y) \
+    if(x <= y) { printf("%d: ASSERT_GT(%s, %s) FAILED\n", __LINE__, #x, #y); \
+        ++UDPC_uts.failed; } ++UDPC_uts.total;
+#define ASSERT_GTE(x, y) \
+    if(x < y) { printf("%d: ASSERT_GTE(%s, %s) FAILED\n", __LINE__, #x, #y); \
+        ++UDPC_uts.failed; } ++UDPC_uts.total;
+#define ASSERT_LT(x, y) \
+    if(x >= y) { printf("%d: ASSERT_LT(%s, %s) FAILED\n", __LINE__, #x, #y); \
+        ++UDPC_uts.failed; } ++UDPC_uts.total;
+#define ASSERT_LTE(x, y) \
+    if(x > y) { printf("%d: ASSERT_LTE(%s, %s) FAILED\n", __LINE__, #x, #y); \
+        ++UDPC_uts.failed; } ++UDPC_uts.total;
 
 #define UNITTEST_REPORT(x) { \
     printf("%s: %d/%d tests failed\n", #x, UDPC_uts.failed, UDPC_uts.total); \