]> git.mdlowis.com Git - archive/carl.git/commitdiff
Added tests for new hashtable implementation. Fully tested insert and retrieval functions
authorMike D. Lowis <mike.lowis@gentex.com>
Thu, 1 Oct 2015 15:08:08 +0000 (11:08 -0400)
committerMike D. Lowis <mike.lowis@gentex.com>
Thu, 1 Oct 2015 15:08:08 +0000 (11:08 -0400)
build.ninja
source/carl.h
source/data/hash.c
source/data/hash.h
tests/data/hash.c [new file with mode: 0644]
tests/main.c

index dc8a265a140ae3ad2c080a5b5d38eb839cce7734..306242d4c8cf95d0a4610dd05546ee7050faa2ac 100644 (file)
@@ -1,9 +1,9 @@
 CC = gcc
 DEPSUFFIX = .d
 CPPFLAGS = -Isource/ -Imodules/atf/source
-CFLAGS = -g -O3 -Wall -Wextra --std=c99 --pedantic
+CFLAGS = -g -O3 -Wall -Wextra --std=c99 --pedantic --coverage
 LD = gcc
-LDFLAGS =
+LDFLAGS = --coverage
 AR = ar
 ARFLAGS = rcs
 
@@ -54,8 +54,9 @@ build tests/refcount.o: cc tests/refcount.c
 build tests/utf/test_unicodedata.o: cc tests/utf/test_unicodedata.c
 build tests/data/bstree.o: cc tests/data/bstree.c
 build tests/data/slist.o: cc tests/data/slist.c
+build tests/data/hash.o: cc tests/data/hash.c
 build tests/main.o: cc tests/main.c
 build modules/atf/source/atf.o: cc modules/atf/source/atf.c
-build test_libc: ld tests/refcount.o tests/utf/test_unicodedata.o tests/data/bstree.o tests/data/slist.o tests/main.o modules/atf/source/atf.o libcarl.a
-build Unit$ Tests: command test_libc
+build test_libc: ld tests/refcount.o tests/utf/test_unicodedata.o tests/data/bstree.o tests/data/slist.o tests/data/hash.o tests/main.o modules/atf/source/atf.o libcarl.a
+build Tests: command test_libc
     CMD = ./test_libc
index a11621cf8c379ad27a2bea85fbb7a8e6cd7b8e79..b5985d1f17e771daca8fcad44c0c46bf0c5bf500 100644 (file)
@@ -16,6 +16,8 @@
 #include <errno.h>
 #include <ctype.h>
 
+typedef unsigned int uint;
+
 #ifndef nil
 #define nil NULL
 #endif
index 451ea83531a088840c6997d32ff965adf983cd0c..7d613fb22c272a2ac76c7bb05979bad463b03e02 100644 (file)
@@ -34,8 +34,9 @@ static void find_entry(hash_t* hash, hash_entry_t** parent, hash_entry_t** curre
 static void rehash(hash_t* hash)
 {
     unsigned int oldcount = hash->bkt_count++;
-    hash_entry_t** oldbuckets = (hash_entry_t**)calloc(sizeof(hash_entry_t*), num_buckets(hash->bkt_count));
+    hash_entry_t** oldbuckets = hash->buckets;
     hash->buckets = (hash_entry_t**)calloc(sizeof(hash_entry_t*), num_buckets(hash->bkt_count));
+    hash->size = 0;
     /* Iterate over all of the old buckets */
     for (unsigned int i = 0; i < num_buckets(oldcount); i++) {
         hash_entry_t* node = oldbuckets[i];
@@ -66,28 +67,40 @@ void hash_deinit(hash_t* hash)
     free(hash->buckets);
 }
 
+size_t hash_size(hash_t* hash)
+{
+    return hash->size;
+}
+
 bool hash_set(hash_t* hash, hash_entry_t* entry)
 {
     if (hash->size >= num_buckets(hash->bkt_count))
         rehash(hash);
     entry->hash = hash->hashfn(entry);
-    unsigned int index   = (entry->hash % num_buckets(hash->bkt_count));
-    hash_entry_t* parent = NULL;
-    hash_entry_t* node   = hash->buckets[index];
+    unsigned int index    = (entry->hash % num_buckets(hash->bkt_count));
+    hash_entry_t* parent  = NULL;
+    hash_entry_t* node    = hash->buckets[index];
+    hash_entry_t* deadite = NULL;
     find_entry(hash, &parent, &node, entry);
-    if (node != NULL) {
-        hash_entry_t* deadite = node;
-        node = node->next;
-        entry->next  = node;
-        if (parent != NULL)
-            parent->next = entry;
-        else
-            hash->buckets[index] = entry;
-        hash->delfn(deadite);
-    } else {
+    if ((parent == NULL) && (node == NULL)) {
         hash->buckets[index] = entry;
         entry->next = NULL;
+        hash->size++;
+    } else if (node == NULL) {
+        parent->next = entry;
+        entry->next = NULL;
+        hash->size++;
+    } else if (parent == NULL) {
+        deadite = node;
+        entry->next = deadite->next;
+        hash->buckets[index] = entry;
+    } else {
+        deadite = node;
+        entry->next = deadite->next;
+        parent->next = entry;
     }
+    if (deadite != NULL)
+        hash->delfn(deadite);
     return true;
 }
 
index 147c0e0346a024f17c2a659cce3a3a29cd930d9e..3a22bab92de27fcb5ce29c41b5ffeb1d786b8843 100644 (file)
@@ -32,6 +32,8 @@ void hash_init(hash_t* hash, hash_hashfn_t hashfn, hash_cmpfn_t cmpfn, hash_free
 
 void hash_deinit(hash_t* hash);
 
+size_t hash_size(hash_t* hash);
+
 bool hash_set(hash_t* hash, hash_entry_t* entry);
 
 hash_entry_t* hash_get(hash_t* hash, hash_entry_t* entry);
diff --git a/tests/data/hash.c b/tests/data/hash.c
new file mode 100644 (file)
index 0000000..fb0883e
--- /dev/null
@@ -0,0 +1,109 @@
+
+// Unit Test Framework Includes
+#include "atf.h"
+
+// File To Test
+#include <data/hash.h>
+#include <carl.h>
+
+typedef struct {
+    hash_entry_t link;
+    uint val;
+} int_node_t;
+
+static unsigned int hash_func(const hash_entry_t* entry)
+{
+    int_node_t* node = container_of(entry, int_node_t, link);
+    return node->val;
+}
+
+static int compare_func(const hash_entry_t* entry1, const hash_entry_t* entry2)
+{
+    int_node_t* node1 = container_of(entry1, int_node_t, link);
+    int_node_t* node2 = container_of(entry2, int_node_t, link);
+    return node1->val - node2->val;
+}
+
+static void delete_func(hash_entry_t* entry)
+{
+    free(container_of(entry, int_node_t, link));
+}
+
+//-----------------------------------------------------------------------------
+// Begin Unit Tests
+//-----------------------------------------------------------------------------
+TEST_SUITE(Hash) {
+    TEST(Verify sequential hash inserts and lookups)
+    {
+        uint maxval = 1000000;
+        hash_t hash;
+        hash_init(&hash, hash_func, compare_func, delete_func);
+        for (uint i = 0; i < maxval; i++)
+        {
+            int_node_t* entry = (int_node_t*)malloc(sizeof(int_node_t));
+            entry->val = i;
+            hash_set(&hash, &(entry->link));
+            CHECK(i+1 == hash_size(&hash));
+            CHECK(&(entry->link) == hash_get(&hash, &(entry->link)));
+        }
+        for (uint i = 0; i < maxval; i++)
+        {
+            int_node_t search = { .val = i };
+            hash_entry_t* entry = hash_get(&hash, &(search.link));
+            int_node_t* ientry = container_of(entry, int_node_t, link);
+            CHECK(entry != NULL);
+            CHECK(ientry != NULL);
+            CHECK(search.val == ientry->val);
+        }
+        hash_deinit(&hash);
+    }
+
+    TEST(Verify ping pong hash inserts and lookups)
+    {
+        uint maxval = 1000000;
+        hash_t hash;
+        hash_init(&hash, hash_func, compare_func, delete_func);
+        for (uint i = 0; i < (maxval/2); i++) {
+            /* Insert the lower number */
+            int_node_t* entry = (int_node_t*)malloc(sizeof(int_node_t));
+            entry->val = i;
+            hash_set(&hash, &(entry->link));
+            CHECK(&(entry->link) == hash_get(&hash, &(entry->link)));
+            /* Insert the higher number */
+            entry = (int_node_t*)malloc(sizeof(int_node_t));
+            entry->val = maxval - i;
+            hash_set(&hash, &(entry->link));
+            CHECK(&(entry->link) == hash_get(&hash, &(entry->link)));
+        }
+        for (uint i = 0; i < (maxval/2); i++)
+        {
+            /* Find the lower number */
+            int_node_t search = { .val = i };
+            hash_entry_t* entry = hash_get(&hash, &(search.link));
+            int_node_t* ientry = container_of(entry, int_node_t, link);
+            CHECK(entry != NULL);
+            CHECK(search.val == ientry->val);
+            /* Find the higher number */
+            search.val = maxval-i;
+            entry = hash_get(&hash, &(search.link));
+            ientry = container_of(entry, int_node_t, link);
+            CHECK(entry != NULL);
+            CHECK(search.val == ientry->val);
+        }
+        hash_deinit(&hash);
+    }
+
+    TEST(Verify random hash inserts and lookups)
+    {
+        hash_t hash;
+        hash_init(&hash, hash_func, compare_func, delete_func);
+        for (uint i = 0; i < 1000000; i++)
+        {
+            int_node_t* entry = (int_node_t*)malloc(sizeof(int_node_t));
+            entry->val = (uint)rand();
+            hash_set(&hash, &(entry->link));
+            CHECK(&(entry->link) == hash_get(&hash, &(entry->link)));
+        }
+        hash_deinit(&hash);
+    }
+}
index 483ec68dcdad82e89e8548c5988e060a6fbc51d0..b600219b9e02600767abdab9a8fc0d47e8026472 100644 (file)
@@ -1,13 +1,18 @@
 #include "atf.h"
 #include <carl.h>
+#include <time.h>
 
 int main(int argc, char** argv)
 {
     (void)argc;
     (void)argv;
+    uint seed = (uint)time(NULL);
+    srand(seed);
+    printf("Random Number Generation Seed: %u\n", seed);
     RUN_EXTERN_TEST_SUITE(RefCount);
     RUN_EXTERN_TEST_SUITE(SList);
     RUN_EXTERN_TEST_SUITE(BSTree);
+    RUN_EXTERN_TEST_SUITE(Hash);
     RUN_EXTERN_TEST_SUITE(UnicodeData);
     return (PRINT_TEST_RESULTS());
 }