diff --git a/src/std/hashtable.c b/src/std/hashtable.c index 2da63cc..f2e3d16 100644 --- a/src/std/hashtable.c +++ b/src/std/hashtable.c @@ -113,6 +113,7 @@ void ARC_HashtableNode_SetNearestNodeToArray(ARC_HashtableNode *nodes, uint32_t while(nodes[index].nextIndex != index){ index = nodes[index].nextIndex; } + index = nodes[index].nextIndex; //init variable for found node uint32_t nextIndex = index; @@ -195,6 +196,38 @@ void ARC_Hashtable_Add(ARC_Hashtable *hashtable, void *key, void *value){ hashtable->currentSize++; } +void ARC_Hashtable_MoveNextBack(ARC_HashtableNode *nodes, uint32_t capacity, uint32_t *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; + + //if the end has been reached, set index to the end + if(nodes->nextIndex == nextIndex){ + //if the next index is already in the right place return out + if(nodes->nextIndex == hashIndex){ + return; + } + + //set the index to the end + nodes[*index].nextIndex = *index; + *index = nextIndex; + return; + } + + //move the current node back one + nodes[*index] = nodes[nextIndex]; + + //moves the next index into the next used slot + nodes[*index].nextIndex = nextIndex; + + //get the next index to move back + *index = nextIndex; + + ARC_Hashtable_MoveNextBack(nodes, capacity, index); +} + void ARC_Hashtable_Remove(ARC_Hashtable *hashtable, void *key){ //get the index from a hashvalue uint32_t initialIndex = hashtable->hashFn(key) % hashtable->currentCapacity; @@ -231,27 +264,8 @@ void ARC_Hashtable_Remove(ARC_Hashtable *hashtable, void *key){ (*(hashtable->destroyKeyValueFn))(node.key, node.value); } - //while the current node needs to be moved back becuase it is offset to the initial index - while(hashtable->nodes[index].nextIndex != index){ - //get the currently used next index - uint32_t nextIndex = hashtable->nodes[index].nextIndex; - - //move the current node back one - hashtable->nodes[index] = hashtable->nodes[nextIndex]; - - //check if the next index is an end index and set this index to end - if(nextIndex == hashtable->nodes[nextIndex].nextIndex){ - hashtable->nodes[index].nextIndex = index; - index = nextIndex; - break; - } - - //moves the next index into the next used slot - hashtable->nodes[index].nextIndex = nextIndex; - - //get the next index to move back - index = nextIndex; - } + //move all next items back + ARC_Hashtable_MoveNextBack(hashtable->nodes, hashtable->currentCapacity, &index); //set the current value to an empty node hashtable->nodes[index] = (ARC_HashtableNode){ NULL, NULL, 0, index }; @@ -281,6 +295,11 @@ void ARC_Hashtable_Remove(ARC_Hashtable *hashtable, void *key){ //add the old nodes into the new array for(uint32_t index = 0; index < oldCapacity; index++){ + //null values do not need to be copied + if(oldNodes[index].key == NULL){ + continue; + } + ARC_HashtableNode_SetNearestNodeToArray(hashtable->nodes, hashtable->currentCapacity, oldNodes[index]); } diff --git a/tests/std/hashtable.c b/tests/std/hashtable.c index 2bd2873..f2542e7 100644 --- a/tests/std/hashtable.c +++ b/tests/std/hashtable.c @@ -14,11 +14,12 @@ void TEST_Hashtable_PrintIter(void *key, void *value){ } void TEST_Hashtable_Print(void *hashtable){ + printf("hashtable:\n"); ARC_Hashtable_RunIteration(hashtable, TEST_Hashtable_PrintIter); + printf("\n"); } ARC_Bool TEST_Hashtable_KeyCompareDataFn(void *dataA, void *dataB){ - printf("%s, %s\n", (char *)dataA, (char *)dataB); return (ARC_Bool)strcmp((const char *)dataA, (const char *)dataB) == 0; } @@ -103,6 +104,9 @@ ARC_TEST(Hashtable_Add_Get_Remove){ 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); } @@ -136,42 +140,42 @@ ARC_TEST(Hashtable_Add_Get_100){ ARC_Hashtable_Destroy(hashtable); } -//ARC_TEST(Hashtable_Add_Get_Remove_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); -// } -// -// for(uint32_t index = 0; index < 100; index++){ -// char *key = (char *)malloc(strlen(keyCStr)); -// sprintf(key, keyCStr, index); -// -// TEST_Hashtable_Print(hashtable); -// ARC_Hashtable_Remove(hashtable, key); -// -// free(key); -// } -// -// ARC_Hashtable_Destroy(hashtable); -//} +ARC_TEST(Hashtable_Add_Get_Remove_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"; + uint32_t maxVal = 1000; + + for(uint32_t index = 0; index < maxVal; 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 < maxVal; index++){ + char *key = (char *)malloc(strlen(keyCStr)); + sprintf(key, keyCStr, index); + + ARC_CHECK(index == *(int32_t *)ARC_Hashtable_Get(hashtable, key)); + + free(key); + } + + for(uint32_t index = 0; index < maxVal; index++){ + char *key = (char *)malloc(strlen(keyCStr)); + sprintf(key, keyCStr, index); + + ARC_Hashtable_Remove(hashtable, key); + + free(key); + } + + ARC_Hashtable_Destroy(hashtable); +}