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
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
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];
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;
}
--- /dev/null
+
+// 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);
+ }
+}