diff --git a/src/std/hashtable.c b/src/std/hashtable.c index ff61f1b..acd4c21 100644 --- a/src/std/hashtable.c +++ b/src/std/hashtable.c @@ -1,5 +1,4 @@ #include "arc/std/hashtable.h" - #include "arc/std/errno.h" #include #include @@ -51,6 +50,7 @@ uint32_t CRC32Fn(void *key){ return hashvalue; } +//private function that will just check compare void pointers directly used as default key compare ARC_Bool ARC_Hashtable_DefaultKeyCompareFn(void *key1, void *key2){ return (ARC_Bool)(key1 == key2); } @@ -105,6 +105,7 @@ void ARC_Hashtable_Destroy(ARC_Hashtable *hashtable){ free(hashtable); } +//private function to add a node as close to its hashed index as possible void ARC_HashtableNode_SetNearestNodeToArray(ARC_HashtableNode *nodes, uint32_t capacity, ARC_HashtableNode node){ //get the first possible index based on the node's hashvalue uint32_t index = node.hashvalue % capacity; @@ -196,10 +197,7 @@ void ARC_Hashtable_Add(ARC_Hashtable *hashtable, void *key, void *value){ hashtable->currentSize++; } -void ARC_Hashtable_VectorDestroyHashtableNodeFn(void *data){ - free((ARC_HashtableNode *)data); -} - +//private function used to remove a node at an index (moving next node values back) void ARC_Hashtable_UnsetNodeAtIndexFromArray(ARC_HashtableNode *nodes, uint32_t capacity, uint32_t index, uint32_t previousIndex){ //if the first index is the end index just set it to null and return if(nodes[index].nextIndex == index && nodes[previousIndex].nextIndex == index){ @@ -218,7 +216,7 @@ void ARC_Hashtable_UnsetNodeAtIndexFromArray(ARC_HashtableNode *nodes, uint32_t //if the next index will be moved into the correct spot if(index == nodes[nextIndex].hashvalue % capacity){ - //NOTE: I couldn't figure out an elegant way of handling this, so for now we remove then readd clashing nodes + //NOTE: I couldn't figure out an elegant way of handling this, so for now we remove then re-add clashing nodes //reset the previous index's next index nodes[previousIndex].nextIndex = previousIndex; @@ -233,14 +231,12 @@ void ARC_Hashtable_UnsetNodeAtIndexFromArray(ARC_HashtableNode *nodes, uint32_t //clear the last moved node nodes[index] = (ARC_HashtableNode){ NULL, NULL, 0, index }; - printf("move: %u -> %u\t%u\t%s\n", index, nodeCopy.nextIndex, nodeCopy.hashvalue % capacity, (char *)nodeCopy.key); //loop through remaining next nodes adding them to a temporary vector and clearing them from the nodes while(nodeCopy.nextIndex != index){ //move to the next node index = nodeCopy.nextIndex; nodeCopy = nodes[index]; - printf("next: %u -> %u\t%u\t%s\n", index, nodeCopy.nextIndex, nodeCopy.hashvalue % capacity, (char *)nodeCopy.key); //copy and clear node nodes[index] = (ARC_HashtableNode){ NULL, NULL, 0, index }; @@ -262,62 +258,13 @@ void ARC_Hashtable_UnsetNodeAtIndexFromArray(ARC_HashtableNode *nodes, uint32_t index = nextIndex; } + //the previous index will be the last moved node, so set its next index to itself + nodes[previousIndex].nextIndex = previousIndex; + //set the current value to an empty node nodes[index] = (ARC_HashtableNode){ NULL, NULL, 0, index }; } -//void ARC_Hashtable_UnsetNodeAtIndexFromArray(ARC_HashtableNode *nodes, uint32_t capacity, uint32_t index, uint32_t previousIndex){ -// while(nodes[index].nextIndex != index){ -// //get the currently used next index -// uint32_t nextIndex = nodes[index].nextIndex; -// -// //if the next index is an end, but it is in the right place this should break -// uint32_t hashIndex = nodes[nextIndex].hashvalue % capacity; -// -// printf("%02u -> %2u\t%2u\n", index, nextIndex, hashIndex); -// -// //move the current node back one -// nodes[index] = nodes[nextIndex]; -// -// //if the end has been reached, set index to the end -// if(nodes[nextIndex].nextIndex == hashIndex){ -// //fix if moved back but next index not updated -// nodes[nextIndex].nextIndex = hashIndex; -// break; -// } -// -// //move set the current index to the end -// if(nodes[index].nextIndex == nextIndex){ -// nodes[index].nextIndex = index; -// -// //check to see if the previous index is pointing to something it shouldn't be -// if(nodes[index].nextIndex == hashIndex){ -// nodes[previousIndex].nextIndex = previousIndex; -// } -// -// index = nextIndex; -// continue; -// } -// -// //moves the next index into the next used slot -// nodes[index].nextIndex = nextIndex; -// -// //set the previous index -// previousIndex = index; -// -// //get the next index to move back -// index = nextIndex; -// } -// -// //fix pointing at a nonexistant node if the index was the first node found -// if(previousIndex != index && nodes[previousIndex].nextIndex == index){ -// nodes[previousIndex].nextIndex = previousIndex; -// } -// -// //set the current value to an empty node -// nodes[index] = (ARC_HashtableNode){ NULL, NULL, 0, index }; -//} - void ARC_Hashtable_Remove(ARC_Hashtable *hashtable, void *key){ //get the index from a hashvalue uint32_t initialIndex = hashtable->hashFn(key) % hashtable->currentCapacity; @@ -356,7 +303,6 @@ void ARC_Hashtable_Remove(ARC_Hashtable *hashtable, void *key){ (*(hashtable->destroyKeyValueFn))(node.key, node.value); } - printf("MOVE:\n"); //move all next items back ARC_Hashtable_UnsetNodeAtIndexFromArray(hashtable->nodes, hashtable->currentCapacity, index, previousIndex); @@ -368,7 +314,6 @@ void ARC_Hashtable_Remove(ARC_Hashtable *hashtable, void *key){ return; } - printf("RESIZE:\n"); //move the current nodes into a temporary variable to move into a resized array uint64_t oldCapacity = hashtable->currentCapacity; ARC_HashtableNode *oldNodes = hashtable->nodes; @@ -465,8 +410,6 @@ void ARC_Hashtable_RunIteration(ARC_Hashtable *hashtable, ARC_Hashtable_Iterator continue; } - printf("%02u -> %02u\t%02u\t%s\n", index, node.nextIndex, node.hashvalue % hashtable->currentCapacity, (char *)node.key); - //passes current iteration into the callback function iteratorFn(node.key, node.value); } diff --git a/tests/std/hashtable.c b/tests/std/hashtable.c index fbbab78..9d4878a 100644 --- a/tests/std/hashtable.c +++ b/tests/std/hashtable.c @@ -20,7 +20,7 @@ void TEST_Hashtable_Print(void *hashtable){ } ARC_Bool TEST_Hashtable_KeyCompareDataFn(void *dataA, void *dataB){ - printf("%s : %s\n", (char *)dataA, (char *)dataB); + //printf("%s : %s\n", (char *)dataA, (char *)dataB); return (ARC_Bool)strcmp((const char *)dataA, (const char *)dataB) == 0; } @@ -39,108 +39,108 @@ ARC_TEST(Hashtable_Init){ ARC_Hashtable_Destroy(hashtable); } -//ARC_TEST(Hashtable_Add_Get_Remove){ -// ARC_Hashtable *hashtable; -// ARC_Hashtable_KeyCompareFn keyCompareFn = TEST_Hashtable_KeyCompareDataFn; -// ARC_Hashtable_Create(&hashtable, NULL, &keyCompareFn, NULL); -// -// char *key0 = (char *)"key0"; -// char *key1 = (char *)"key1"; -// char *key2 = (char *)"key2"; -// char *key3 = (char *)"key3"; -// char *key4 = (char *)"key4"; -// char *key5 = (char *)"key5"; -// char *key6 = (char *)"key6"; -// char *key7 = (char *)"key7"; -// char *key8 = (char *)"key8"; -// -// int32_t val0 = 2; -// int32_t val1 = 7; -// int32_t val2 = 4; -// int32_t val3 = 9; -// int32_t val4 = 0; -// int32_t val5 = 1; -// int32_t val6 = 3; -// int32_t val7 = 5; -// int32_t val8 = 6; -// -// ARC_Hashtable_Add(hashtable, key0, &val0); -// ARC_Hashtable_Add(hashtable, key1, &val1); -// ARC_Hashtable_Add(hashtable, key2, &val2); -// ARC_Hashtable_Add(hashtable, key3, &val3); -// ARC_Hashtable_Add(hashtable, key4, &val4); -// ARC_Hashtable_Add(hashtable, key5, &val5); -// ARC_Hashtable_Add(hashtable, key6, &val6); -// ARC_Hashtable_Add(hashtable, key7, &val7); -// ARC_Hashtable_Add(hashtable, key8, &val8); -// -// ARC_CHECK(2 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key0")); -// ARC_CHECK(7 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key1")); -// ARC_CHECK(4 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key2")); -// ARC_CHECK(9 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key3")); -// ARC_CHECK(0 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key4")); -// ARC_CHECK(1 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key5")); -// ARC_CHECK(3 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key6")); -// ARC_CHECK(5 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key7")); -// ARC_CHECK(6 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key8")); -// -// TEST_Hashtable_Print(hashtable); -// ARC_Hashtable_Remove(hashtable, (void *)"key2"); -// -// ARC_CHECK(2 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key0")); -// ARC_CHECK(7 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key1")); -// ARC_CHECK(9 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key3")); -// ARC_CHECK(0 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key4")); -// ARC_CHECK(1 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key5")); -// ARC_CHECK(3 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key6")); -// ARC_CHECK(5 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key7")); -// ARC_CHECK(6 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key8")); -// -// ARC_Hashtable_Remove(hashtable, (void *)"key0"); -// ARC_Hashtable_Remove(hashtable, (void *)"key4"); -// ARC_Hashtable_Remove(hashtable, (void *)"key3"); -// ARC_Hashtable_Remove(hashtable, (void *)"key8"); -// ARC_Hashtable_Remove(hashtable, (void *)"key6"); -// ARC_Hashtable_Remove(hashtable, (void *)"key7"); -// -// ARC_CHECK(7 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key1")); -// ARC_CHECK(1 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key5")); -// -// ARC_Hashtable_Remove(hashtable, (void *)"key1"); -// ARC_Hashtable_Remove(hashtable, (void *)"key5"); -// -// ARC_Hashtable_Destroy(hashtable); -//} -// -//ARC_TEST(Hashtable_Add_Get_100){ -// ARC_Hashtable *hashtable; -// ARC_Hashtable_KeyCompareFn keyCompareFn = TEST_Hashtable_KeyCompareDataFn; -// ARC_Hashtable_DestroyKeyValueFn destroyKeyValueFn = TEST_Hashtable_DestroyKeyValueFn; -// ARC_Hashtable_Create(&hashtable, NULL, &keyCompareFn, &destroyKeyValueFn); -// -// const char *keyCStr = "key%03u"; -// -// for(uint32_t index = 0; index < 100; index++){ -// char *key = (char *)malloc(strlen(keyCStr)); -// sprintf(key, keyCStr, index); -// -// int32_t *val = (int32_t *)malloc(sizeof(int32_t)); -// *val = index; -// -// ARC_Hashtable_Add(hashtable, key, val); -// } -// -// for(uint32_t index = 0; index < 100; index++){ -// char *key = (char *)malloc(strlen(keyCStr)); -// sprintf(key, keyCStr, index); -// -// ARC_CHECK(index == *(int32_t *)ARC_Hashtable_Get(hashtable, key)); -// -// free(key); -// } -// -// ARC_Hashtable_Destroy(hashtable); -//} +ARC_TEST(Hashtable_Add_Get_Remove){ + ARC_Hashtable *hashtable; + ARC_Hashtable_KeyCompareFn keyCompareFn = TEST_Hashtable_KeyCompareDataFn; + ARC_Hashtable_Create(&hashtable, NULL, &keyCompareFn, NULL); + + char *key0 = (char *)"key0"; + char *key1 = (char *)"key1"; + char *key2 = (char *)"key2"; + char *key3 = (char *)"key3"; + char *key4 = (char *)"key4"; + char *key5 = (char *)"key5"; + char *key6 = (char *)"key6"; + char *key7 = (char *)"key7"; + char *key8 = (char *)"key8"; + + int32_t val0 = 2; + int32_t val1 = 7; + int32_t val2 = 4; + int32_t val3 = 9; + int32_t val4 = 0; + int32_t val5 = 1; + int32_t val6 = 3; + int32_t val7 = 5; + int32_t val8 = 6; + + ARC_Hashtable_Add(hashtable, key0, &val0); + ARC_Hashtable_Add(hashtable, key1, &val1); + ARC_Hashtable_Add(hashtable, key2, &val2); + ARC_Hashtable_Add(hashtable, key3, &val3); + ARC_Hashtable_Add(hashtable, key4, &val4); + ARC_Hashtable_Add(hashtable, key5, &val5); + ARC_Hashtable_Add(hashtable, key6, &val6); + ARC_Hashtable_Add(hashtable, key7, &val7); + ARC_Hashtable_Add(hashtable, key8, &val8); + + ARC_CHECK(2 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key0")); + ARC_CHECK(7 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key1")); + ARC_CHECK(4 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key2")); + ARC_CHECK(9 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key3")); + ARC_CHECK(0 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key4")); + ARC_CHECK(1 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key5")); + ARC_CHECK(3 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key6")); + ARC_CHECK(5 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key7")); + ARC_CHECK(6 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key8")); + + TEST_Hashtable_Print(hashtable); + ARC_Hashtable_Remove(hashtable, (void *)"key2"); + + ARC_CHECK(2 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key0")); + ARC_CHECK(7 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key1")); + ARC_CHECK(9 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key3")); + ARC_CHECK(0 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key4")); + ARC_CHECK(1 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key5")); + ARC_CHECK(3 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key6")); + ARC_CHECK(5 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key7")); + ARC_CHECK(6 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key8")); + + ARC_Hashtable_Remove(hashtable, (void *)"key0"); + ARC_Hashtable_Remove(hashtable, (void *)"key4"); + ARC_Hashtable_Remove(hashtable, (void *)"key3"); + ARC_Hashtable_Remove(hashtable, (void *)"key8"); + ARC_Hashtable_Remove(hashtable, (void *)"key6"); + ARC_Hashtable_Remove(hashtable, (void *)"key7"); + + ARC_CHECK(7 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key1")); + ARC_CHECK(1 == *(int32_t *)ARC_Hashtable_Get(hashtable, (void *)"key5")); + + ARC_Hashtable_Remove(hashtable, (void *)"key1"); + ARC_Hashtable_Remove(hashtable, (void *)"key5"); + + ARC_Hashtable_Destroy(hashtable); +} + +ARC_TEST(Hashtable_Add_Get_100){ + ARC_Hashtable *hashtable; + ARC_Hashtable_KeyCompareFn keyCompareFn = TEST_Hashtable_KeyCompareDataFn; + ARC_Hashtable_DestroyKeyValueFn destroyKeyValueFn = TEST_Hashtable_DestroyKeyValueFn; + ARC_Hashtable_Create(&hashtable, NULL, &keyCompareFn, &destroyKeyValueFn); + + const char *keyCStr = "key%03u"; + + for(uint32_t index = 0; index < 100; index++){ + char *key = (char *)malloc(strlen(keyCStr)); + sprintf(key, keyCStr, index); + + int32_t *val = (int32_t *)malloc(sizeof(int32_t)); + *val = index; + + ARC_Hashtable_Add(hashtable, key, val); + } + + for(uint32_t index = 0; index < 100; index++){ + char *key = (char *)malloc(strlen(keyCStr)); + sprintf(key, keyCStr, index); + + ARC_CHECK(index == *(int32_t *)ARC_Hashtable_Get(hashtable, key)); + + free(key); + } + + ARC_Hashtable_Destroy(hashtable); +} ARC_TEST(Hashtable_Add_Get_Remove_100){ ARC_Hashtable *hashtable; @@ -148,41 +148,36 @@ ARC_TEST(Hashtable_Add_Get_Remove_100){ ARC_Hashtable_DestroyKeyValueFn destroyKeyValueFn = TEST_Hashtable_DestroyKeyValueFn; ARC_Hashtable_Create(&hashtable, NULL, &keyCompareFn, &destroyKeyValueFn); - const char *keyCStr = "key%09u"; - uint32_t tempMaxVal = 10000; + const char *keyCStr = "key%03u"; + uint32_t maxVal = 100; - for(uint32_t maxVal = 0; maxVal < tempMaxVal; maxVal++){ - for(uint32_t index = 0; index < maxVal; index++){ - char *key = (char *)malloc(strlen(keyCStr) + 12); - sprintf(key, keyCStr, index); + for(uint32_t index = 0; index < maxVal; index++){ + char *key = (char *)malloc(strlen(keyCStr) + 12); + sprintf(key, keyCStr, index); - int32_t *val = (int32_t *)malloc(sizeof(int32_t)); - *val = index; + int32_t *val = (int32_t *)malloc(sizeof(int32_t)); + *val = index; - ARC_Hashtable_Add(hashtable, key, val); - } + ARC_Hashtable_Add(hashtable, key, val); + } - for(uint32_t index = 0; index < maxVal; index++){ - char *key = (char *)malloc(strlen(keyCStr) + 12); - sprintf(key, keyCStr, index); + for(uint32_t index = 0; index < maxVal; index++){ + char *key = (char *)malloc(strlen(keyCStr) + 12); + sprintf(key, keyCStr, index); - ARC_CHECK(index == *(int32_t *)ARC_Hashtable_Get(hashtable, key)); + ARC_CHECK(index == *(int32_t *)ARC_Hashtable_Get(hashtable, key)); - free(key); - } + free(key); + } - for(uint32_t index = 0; index < maxVal; index++){ - char *key = (char *)malloc(strlen(keyCStr) + 12); - sprintf(key, keyCStr, index); + for(uint32_t index = 0; index < maxVal; index++){ + char *key = (char *)malloc(strlen(keyCStr) + 12); + sprintf(key, keyCStr, index); - TEST_Hashtable_Print(hashtable); - ARC_CHECK(index == *(int32_t *)ARC_Hashtable_Get(hashtable, key)); - ARC_Hashtable_Remove(hashtable, key); + ARC_CHECK(index == *(int32_t *)ARC_Hashtable_Get(hashtable, key)); + ARC_Hashtable_Remove(hashtable, key); - free(key); - } - - printf("%u\n", maxVal); + free(key); } ARC_Hashtable_Destroy(hashtable);