Add unit tests for HashMap, fix HashMap
This commit is contained in:
parent
e995c877c4
commit
1bab7694cf
2 changed files with 150 additions and 45 deletions
|
@ -30,7 +30,7 @@ UDPC_HashMap* UDPC_HashMap_init(uint32_t capacity, uint32_t unitSize)
|
||||||
m->buckets[x] = NULL;
|
m->buckets[x] = NULL;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
m->buckets[x] = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE * (sizeof(uint32_t) + unitSize));
|
m->buckets[x] = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE * (4 + unitSize));
|
||||||
if(!m->buckets[x])
|
if(!m->buckets[x])
|
||||||
{
|
{
|
||||||
fail = 1;
|
fail = 1;
|
||||||
|
@ -51,7 +51,7 @@ UDPC_HashMap* UDPC_HashMap_init(uint32_t capacity, uint32_t unitSize)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
m->overflow = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE * (sizeof(uint32_t) + unitSize));
|
m->overflow = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE * (4 + unitSize));
|
||||||
if(!m->overflow)
|
if(!m->overflow)
|
||||||
{
|
{
|
||||||
for(int x = 0; x < m->capacity; ++x)
|
for(int x = 0; x < m->capacity; ++x)
|
||||||
|
@ -76,7 +76,7 @@ void UDPC_HashMap_destroy(UDPC_HashMap *hashMap)
|
||||||
UDPC_Deque_destroy(hashMap->buckets[x]);
|
UDPC_Deque_destroy(hashMap->buckets[x]);
|
||||||
}
|
}
|
||||||
free(hashMap->buckets);
|
free(hashMap->buckets);
|
||||||
free(hashMap->overflow);
|
UDPC_Deque_destroy(hashMap->overflow);
|
||||||
free(hashMap);
|
free(hashMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,22 +92,22 @@ void* UDPC_HashMap_insert(UDPC_HashMap *hm, uint32_t key, void *data)
|
||||||
|
|
||||||
uint32_t hash = UDPC_HASH32(key) % hm->capacity;
|
uint32_t hash = UDPC_HASH32(key) % hm->capacity;
|
||||||
|
|
||||||
char *temp = malloc(sizeof(uint32_t) + hm->unitSize);
|
char *temp = malloc(4 + hm->unitSize);
|
||||||
memcpy(temp, &key, sizeof(uint32_t));
|
memcpy(temp, &key, 4);
|
||||||
if(hm->unitSize > 0)
|
if(hm->unitSize > 0)
|
||||||
{
|
{
|
||||||
memcpy(temp + sizeof(uint32_t), data, hm->unitSize);
|
memcpy(temp + 4, data, hm->unitSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(UDPC_Deque_get_available(hm->buckets[hash]) != 0)
|
if(UDPC_Deque_get_available(hm->buckets[hash]) == 0)
|
||||||
{
|
{
|
||||||
if(UDPC_Deque_push_back(hm->overflow, temp, sizeof(uint32_t) + hm->unitSize) == 0)
|
if(UDPC_Deque_push_back(hm->overflow, temp, 4 + hm->unitSize) == 0)
|
||||||
{
|
{
|
||||||
free(temp);
|
free(temp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(UDPC_Deque_push_back(hm->buckets[hash], temp, sizeof(uint32_t) + hm->unitSize) == 0)
|
else if(UDPC_Deque_push_back(hm->buckets[hash], temp, 4 + hm->unitSize) == 0)
|
||||||
{
|
{
|
||||||
free(temp);
|
free(temp);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -115,8 +115,8 @@ void* UDPC_HashMap_insert(UDPC_HashMap *hm, uint32_t key, void *data)
|
||||||
|
|
||||||
free(temp);
|
free(temp);
|
||||||
++hm->size;
|
++hm->size;
|
||||||
temp = UDPC_Deque_get_back_ptr(hm->buckets[hash], sizeof(uint32_t) + hm->unitSize);
|
temp = UDPC_Deque_get_back_ptr(hm->buckets[hash], 4 + hm->unitSize);
|
||||||
return temp + sizeof(uint32_t);
|
return temp + 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
int UDPC_HashMap_remove(UDPC_HashMap *hm, uint32_t key)
|
int UDPC_HashMap_remove(UDPC_HashMap *hm, uint32_t key)
|
||||||
|
@ -128,14 +128,14 @@ int UDPC_HashMap_remove(UDPC_HashMap *hm, uint32_t key)
|
||||||
|
|
||||||
uint32_t hash = UDPC_HASH32(key) % hm->capacity;
|
uint32_t hash = UDPC_HASH32(key) % hm->capacity;
|
||||||
|
|
||||||
for(int x = 0; x * (sizeof(uint32_t) + hm->unitSize) < hm->buckets[hash]->size; ++x)
|
for(int x = 0; x * (4 + hm->unitSize) < hm->buckets[hash]->size; ++x)
|
||||||
{
|
{
|
||||||
if(memcmp(
|
if(memcmp(
|
||||||
UDPC_Deque_index_ptr(hm->buckets[hash], sizeof(uint32_t) + hm->unitSize, x),
|
UDPC_Deque_index_ptr(hm->buckets[hash], 4 + hm->unitSize, x),
|
||||||
&key,
|
&key,
|
||||||
sizeof(uint32_t)) == 0)
|
4) == 0)
|
||||||
{
|
{
|
||||||
int result = UDPC_Deque_remove(hm->buckets[hash], sizeof(uint32_t) + hm->unitSize, x);
|
int result = UDPC_Deque_remove(hm->buckets[hash], 4 + hm->unitSize, x);
|
||||||
if(result != 0)
|
if(result != 0)
|
||||||
{
|
{
|
||||||
--hm->size;
|
--hm->size;
|
||||||
|
@ -148,14 +148,14 @@ int UDPC_HashMap_remove(UDPC_HashMap *hm, uint32_t key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int x = 0; x * (sizeof(uint32_t) + hm->unitSize) < hm->overflow->size; ++x)
|
for(int x = 0; x * (4 + hm->unitSize) < hm->overflow->size; ++x)
|
||||||
{
|
{
|
||||||
if(memcmp(
|
if(memcmp(
|
||||||
UDPC_Deque_index_ptr(hm->overflow, sizeof(uint32_t) + hm->unitSize, x),
|
UDPC_Deque_index_ptr(hm->overflow, 4 + hm->unitSize, x),
|
||||||
&key,
|
&key,
|
||||||
sizeof(uint32_t)) == 0)
|
4) == 0)
|
||||||
{
|
{
|
||||||
int result = UDPC_Deque_remove(hm->overflow, sizeof(uint32_t) + hm->unitSize, x);
|
int result = UDPC_Deque_remove(hm->overflow, 4 + hm->unitSize, x);
|
||||||
if(result != 0)
|
if(result != 0)
|
||||||
{
|
{
|
||||||
--hm->size;
|
--hm->size;
|
||||||
|
@ -180,17 +180,14 @@ void* UDPC_HashMap_get(UDPC_HashMap *hm, uint32_t key)
|
||||||
|
|
||||||
uint32_t hash = UDPC_HASH32(key) % hm->capacity;
|
uint32_t hash = UDPC_HASH32(key) % hm->capacity;
|
||||||
|
|
||||||
for(int x = 0; x * (sizeof(uint32_t) + hm->unitSize) < hm->buckets[hash]->size; ++x)
|
for(int x = 0; x * (4 + hm->unitSize) < hm->buckets[hash]->size; ++x)
|
||||||
{
|
{
|
||||||
char *ptr = UDPC_Deque_index_ptr(hm->buckets[hash], sizeof(uint32_t) + hm->unitSize, x);
|
char *ptr = UDPC_Deque_index_ptr(hm->buckets[hash], 4 + hm->unitSize, x);
|
||||||
if(memcmp(
|
if(memcmp(ptr, &key, 4) == 0)
|
||||||
ptr,
|
|
||||||
&key,
|
|
||||||
sizeof(uint32_t)) == 0)
|
|
||||||
{
|
{
|
||||||
if(hm->unitSize > 0)
|
if(hm->unitSize > 0)
|
||||||
{
|
{
|
||||||
return ptr + sizeof(uint32_t);
|
return ptr + 4;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -199,17 +196,14 @@ void* UDPC_HashMap_get(UDPC_HashMap *hm, uint32_t key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int x = 0; x * (sizeof(uint32_t) + hm->unitSize) < hm->overflow->size; ++x)
|
for(int x = 0; x * (4 + hm->unitSize) < hm->overflow->size; ++x)
|
||||||
{
|
{
|
||||||
char *ptr = UDPC_Deque_index_ptr(hm->overflow, sizeof(uint32_t) + hm->unitSize, x);
|
char *ptr = UDPC_Deque_index_ptr(hm->overflow, 4 + hm->unitSize, x);
|
||||||
if(memcmp(
|
if(memcmp(ptr, &key, 4) == 0)
|
||||||
ptr,
|
|
||||||
&key,
|
|
||||||
sizeof(uint32_t)) == 0)
|
|
||||||
{
|
{
|
||||||
if(hm->unitSize > 0)
|
if(hm->unitSize > 0)
|
||||||
{
|
{
|
||||||
return ptr + sizeof(uint32_t);
|
return ptr + 4;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -230,11 +224,11 @@ int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
|
||||||
|
|
||||||
UDPC_Deque **newBuckets = malloc(sizeof(UDPC_Deque*) * newCapacity);
|
UDPC_Deque **newBuckets = malloc(sizeof(UDPC_Deque*) * newCapacity);
|
||||||
UDPC_Deque *newOverflow = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE
|
UDPC_Deque *newOverflow = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE
|
||||||
* (sizeof(uint32_t) + hm->unitSize));
|
* (4 + hm->unitSize));
|
||||||
for(int x = 0; x < newCapacity; ++x)
|
for(int x = 0; x < newCapacity; ++x)
|
||||||
{
|
{
|
||||||
*newBuckets = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE
|
newBuckets[x] = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE
|
||||||
* (sizeof(uint32_t) + hm->unitSize));
|
* (4 + hm->unitSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
|
@ -242,33 +236,52 @@ int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
for(int x = 0; x < hm->capacity; ++x)
|
for(int x = 0; x < hm->capacity; ++x)
|
||||||
{
|
{
|
||||||
for(int y = 0; y * (sizeof(uint32_t) + hm->unitSize) < hm->buckets[x]->size; ++y)
|
for(int y = 0; y * (4 + hm->unitSize) < hm->buckets[x]->size; ++y)
|
||||||
{
|
{
|
||||||
data = UDPC_Deque_index_ptr(hm->buckets[x], sizeof(uint32_t) + hm->unitSize, y);
|
data = UDPC_Deque_index_ptr(hm->buckets[x], 4 + hm->unitSize, y);
|
||||||
hash = UDPC_HASH32(*((uint32_t*)data)) % newCapacity;
|
hash = UDPC_HASH32(*((uint32_t*)data)) % newCapacity;
|
||||||
if(newBuckets[hash]->size < newBuckets[hash]->alloc_size)
|
if(newBuckets[hash]->size < newBuckets[hash]->alloc_size)
|
||||||
{
|
{
|
||||||
if(UDPC_Deque_push_back(newBuckets[hash], data, sizeof(uint32_t) + hm->unitSize) == 0)
|
if(UDPC_Deque_push_back(newBuckets[hash], data, 4 + hm->unitSize) == 0)
|
||||||
{
|
{
|
||||||
fail = 1;
|
fail = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if(UDPC_Deque_push_back(newOverflow, data, 4 + hm->unitSize) == 0)
|
||||||
{
|
|
||||||
if(UDPC_Deque_push_back(newOverflow, data, sizeof(uint32_t) + hm->unitSize) == 0)
|
|
||||||
{
|
{
|
||||||
fail = 1;
|
fail = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(fail != 0)
|
if(fail != 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(fail == 0)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
if(newBuckets[hash]->size < newBuckets[hash]->alloc_size)
|
||||||
|
{
|
||||||
|
if(UDPC_Deque_push_back(newBuckets[hash], data, 4 + hm->unitSize) == 0)
|
||||||
|
{
|
||||||
|
fail = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(UDPC_Deque_push_back(newOverflow, data, 4 + hm->unitSize) == 0)
|
||||||
|
{
|
||||||
|
fail = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(fail != 0)
|
if(fail != 0)
|
||||||
{
|
{
|
||||||
for(int x = 0; x < newCapacity; ++x)
|
for(int x = 0; x < newCapacity; ++x)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <UDPC_Deque.h>
|
#include <UDPC_Deque.h>
|
||||||
|
#include <UDPC_HashMap.h>
|
||||||
#include <UDPConnection.h>
|
#include <UDPConnection.h>
|
||||||
|
|
||||||
static UnitTestState UDPC_uts = {0, 0};
|
static UnitTestState UDPC_uts = {0, 0};
|
||||||
|
@ -231,9 +232,100 @@ void TEST_ATOSTR()
|
||||||
UNITTEST_REPORT(ATOSTR);
|
UNITTEST_REPORT(ATOSTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TEST_HASHMAP()
|
||||||
|
{
|
||||||
|
UDPC_HashMap *hm = UDPC_HashMap_init(0, sizeof(int));
|
||||||
|
int temp;
|
||||||
|
|
||||||
|
temp = 1333;
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_insert(hm, 0, &temp), NULL);
|
||||||
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 0), &temp, sizeof(int));
|
||||||
|
|
||||||
|
temp = 9999;
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_insert(hm, 1, &temp), NULL);
|
||||||
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 1), &temp, sizeof(int));
|
||||||
|
|
||||||
|
temp = 1235987;
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_insert(hm, 2, &temp), NULL);
|
||||||
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 2), &temp, sizeof(int));
|
||||||
|
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_remove(hm, 1), 0);
|
||||||
|
temp = 1333;
|
||||||
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 0), &temp, sizeof(int));
|
||||||
|
temp = 1235987;
|
||||||
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 2), &temp, sizeof(int));
|
||||||
|
|
||||||
|
ASSERT_EQ(UDPC_HashMap_realloc(hm, 0), 0);
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_realloc(hm, 16), 0);
|
||||||
|
|
||||||
|
temp = 1333;
|
||||||
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 0), &temp, sizeof(int));
|
||||||
|
temp = 1235987;
|
||||||
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 2), &temp, sizeof(int));
|
||||||
|
|
||||||
|
UDPC_HashMap_clear(hm);
|
||||||
|
ASSERT_EQ(hm->size, 0);
|
||||||
|
ASSERT_EQ(hm->capacity, 16);
|
||||||
|
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_realloc(hm, 8), 0);
|
||||||
|
ASSERT_EQ(hm->size, 0);
|
||||||
|
ASSERT_EQ(hm->capacity, 8);
|
||||||
|
|
||||||
|
for(int x = 0; x < 8; ++x)
|
||||||
|
{
|
||||||
|
temp = x * 100;
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_insert(hm, x, &temp), NULL);
|
||||||
|
}
|
||||||
|
for(int x = 0; x < 8; ++x)
|
||||||
|
{
|
||||||
|
temp = x * 100;
|
||||||
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
|
||||||
|
}
|
||||||
|
ASSERT_EQ(hm->capacity, 8);
|
||||||
|
|
||||||
|
temp = 800;
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_insert(hm, 8, &temp), NULL);
|
||||||
|
for(int x = 0; x < 9; ++x)
|
||||||
|
{
|
||||||
|
temp = x * 100;
|
||||||
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
|
||||||
|
}
|
||||||
|
ASSERT_EQ(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);
|
||||||
|
|
||||||
|
// TODO DEBUG
|
||||||
|
/*
|
||||||
|
printf("Size = %d\n", hm->size);
|
||||||
|
printf("Capacity = %d\n", hm->capacity);
|
||||||
|
for(int x = 0; x < hm->capacity; ++x)
|
||||||
|
{
|
||||||
|
for(int y = 0; y * (4 + sizeof(int)) < hm->buckets[x]->size; ++y)
|
||||||
|
{
|
||||||
|
printf("Bucket%d[%d] = %d\n", x, y,
|
||||||
|
*((int*)&hm->buckets[x]->buf[y * (4 + sizeof(int)) + 4]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int x = 0; x < hm->overflow->size; ++x)
|
||||||
|
{
|
||||||
|
printf("Overflow[%d] = %d\n", x,
|
||||||
|
*((int*)&hm->overflow->buf[x * (4 + sizeof(int)) + 4]));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
UDPC_HashMap_destroy(hm);
|
||||||
|
UNITTEST_REPORT(HASHMAP);
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
TEST_DEQUE();
|
TEST_DEQUE();
|
||||||
TEST_ATOSTR();
|
TEST_ATOSTR();
|
||||||
|
TEST_HASHMAP();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue