Fixes to Unit Test, attempt to improve hash use
This commit is contained in:
parent
1bab7694cf
commit
f1a13cde5c
4 changed files with 98 additions and 10 deletions
|
@ -90,7 +90,7 @@ void* UDPC_HashMap_insert(UDPC_HashMap *hm, uint32_t key, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t hash = UDPC_HASH32(key) % hm->capacity;
|
||||
uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
|
||||
|
||||
char *temp = malloc(4 + hm->unitSize);
|
||||
memcpy(temp, &key, 4);
|
||||
|
@ -101,7 +101,19 @@ void* UDPC_HashMap_insert(UDPC_HashMap *hm, uint32_t key, void *data)
|
|||
|
||||
if(UDPC_Deque_get_available(hm->buckets[hash]) == 0)
|
||||
{
|
||||
if(UDPC_Deque_push_back(hm->overflow, temp, 4 + hm->unitSize) == 0)
|
||||
if(UDPC_Deque_get_available(hm->overflow) == 0)
|
||||
{
|
||||
free(temp);
|
||||
if(UDPC_HashMap_realloc(hm, hm->capacity * 2) != 0)
|
||||
{
|
||||
return UDPC_HashMap_INTERNAL_reinsert(hm, key, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if(UDPC_Deque_push_back(hm->overflow, temp, 4 + hm->unitSize) == 0)
|
||||
{
|
||||
free(temp);
|
||||
return NULL;
|
||||
|
@ -126,7 +138,7 @@ int UDPC_HashMap_remove(UDPC_HashMap *hm, uint32_t key)
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint32_t hash = UDPC_HASH32(key) % hm->capacity;
|
||||
uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
|
||||
|
||||
for(int x = 0; x * (4 + hm->unitSize) < hm->buckets[hash]->size; ++x)
|
||||
{
|
||||
|
@ -178,7 +190,7 @@ void* UDPC_HashMap_get(UDPC_HashMap *hm, uint32_t key)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t hash = UDPC_HASH32(key) % hm->capacity;
|
||||
uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
|
||||
|
||||
for(int x = 0; x * (4 + hm->unitSize) < hm->buckets[hash]->size; ++x)
|
||||
{
|
||||
|
@ -239,7 +251,7 @@ int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
|
|||
for(int y = 0; y * (4 + hm->unitSize) < hm->buckets[x]->size; ++y)
|
||||
{
|
||||
data = UDPC_Deque_index_ptr(hm->buckets[x], 4 + hm->unitSize, y);
|
||||
hash = UDPC_HASH32(*((uint32_t*)data)) % newCapacity;
|
||||
hash = UDPC_HASHMAP_MOD(*((uint32_t*)data), newCapacity);
|
||||
if(newBuckets[hash]->size < newBuckets[hash]->alloc_size)
|
||||
{
|
||||
if(UDPC_Deque_push_back(newBuckets[hash], data, 4 + hm->unitSize) == 0)
|
||||
|
@ -265,7 +277,7 @@ int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
|
|||
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;
|
||||
hash = UDPC_HASHMAP_MOD(*((uint32_t*)data), newCapacity);
|
||||
if(newBuckets[hash]->size < newBuckets[hash]->alloc_size)
|
||||
{
|
||||
if(UDPC_Deque_push_back(newBuckets[hash], data, 4 + hm->unitSize) == 0)
|
||||
|
@ -328,3 +340,44 @@ uint32_t UDPC_HashMap_get_capacity(UDPC_HashMap *hm)
|
|||
{
|
||||
return hm->capacity;
|
||||
}
|
||||
|
||||
void* UDPC_HashMap_INTERNAL_reinsert(UDPC_HashMap *hm, uint32_t key, void *data)
|
||||
{
|
||||
if(hm->capacity <= hm->size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
|
||||
|
||||
char *temp = malloc(4 + hm->unitSize);
|
||||
memcpy(temp, &key, 4);
|
||||
if(hm->unitSize > 0)
|
||||
{
|
||||
memcpy(temp + 4, data, hm->unitSize);
|
||||
}
|
||||
|
||||
if(UDPC_Deque_get_available(hm->buckets[hash]) == 0)
|
||||
{
|
||||
if(UDPC_Deque_get_available(hm->overflow) == 0)
|
||||
{
|
||||
free(temp);
|
||||
return NULL;
|
||||
}
|
||||
else if(UDPC_Deque_push_back(hm->overflow, temp, 4 + hm->unitSize) == 0)
|
||||
{
|
||||
free(temp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if(UDPC_Deque_push_back(hm->buckets[hash], temp, 4 + hm->unitSize) == 0)
|
||||
{
|
||||
free(temp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
free(temp);
|
||||
++hm->size;
|
||||
temp = UDPC_Deque_get_back_ptr(hm->buckets[hash], 4 + hm->unitSize);
|
||||
return temp + 4;
|
||||
}
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
) ^ 0x96969696 \
|
||||
)
|
||||
|
||||
#define UDPC_HASHMAP_INIT_CAPACITY 8
|
||||
#define UDPC_HASHMAP_INIT_CAPACITY 13
|
||||
#define UDPC_HASHMAP_BUCKET_SIZE 4
|
||||
|
||||
#define UDPC_HASHMAP_MOD(k, m) ((UDPC_HASH32(k) % (m * 2 + 1)) % m)
|
||||
|
||||
#include "UDPC_Deque.h"
|
||||
|
||||
typedef struct {
|
||||
|
@ -46,6 +48,9 @@ void UDPC_HashMap_destroy(UDPC_HashMap *hashMap);
|
|||
* Note if size already equals capacity, the hash map's capacity is doubled
|
||||
* with UDPC_HashMap_realloc(). realloc requires rehashing of all items which
|
||||
* may be costly.
|
||||
* Also, if the hash map runs out of space for a specific key to insert, it will
|
||||
* also invoke realloc() with double the previous capacity and will attempt to
|
||||
* insert again afterwards.
|
||||
* It is possible to insert items with duplicate keys. In that case, the first
|
||||
* duplicate inserted will be the first returned with get() and first removed
|
||||
* with remove().
|
||||
|
@ -86,4 +91,9 @@ uint32_t UDPC_HashMap_get_size(UDPC_HashMap *hm);
|
|||
|
||||
uint32_t UDPC_HashMap_get_capacity(UDPC_HashMap *hm);
|
||||
|
||||
/*!
|
||||
* \brief A variant of insert that does not try to realloc() on no more space
|
||||
*/
|
||||
void* UDPC_HashMap_INTERNAL_reinsert(UDPC_HashMap *hm, uint32_t key, void *data);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -281,7 +281,7 @@ void TEST_HASHMAP()
|
|||
temp = x * 100;
|
||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
|
||||
}
|
||||
ASSERT_EQ(hm->capacity, 8);
|
||||
ASSERT_GTE(hm->capacity, 8);
|
||||
|
||||
temp = 800;
|
||||
ASSERT_NEQ(UDPC_HashMap_insert(hm, 8, &temp), NULL);
|
||||
|
@ -290,14 +290,27 @@ void TEST_HASHMAP()
|
|||
temp = x * 100;
|
||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
|
||||
}
|
||||
ASSERT_EQ(hm->capacity, 16);
|
||||
ASSERT_GTE(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);
|
||||
ASSERT_GTE(hm->capacity, 16);
|
||||
|
||||
for(int x = 0; x < 32; ++x)
|
||||
{
|
||||
temp = x * 100;
|
||||
ASSERT_NEQ(UDPC_HashMap_insert(hm, x, &temp), NULL);
|
||||
}
|
||||
ASSERT_EQ(hm->size, 32);
|
||||
|
||||
for(int x = 0; x < 32; ++x)
|
||||
{
|
||||
temp = x * 100;
|
||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
|
||||
}
|
||||
|
||||
// TODO DEBUG
|
||||
/*
|
||||
|
|
|
@ -26,6 +26,18 @@
|
|||
#define ASSERT_NEQ_MEM(x, y, size) \
|
||||
if(memcmp(x, y, size) == 0) { printf("%d: ASSERT_NEQ_MEM(%s, %s, %s) FAILED\n", \
|
||||
__LINE__, #x, #y, #size); ++UDPC_uts.failed; } ++UDPC_uts.total;
|
||||
#define ASSERT_GT(x, y) \
|
||||
if(x <= y) { printf("%d: ASSERT_GT(%s, %s) FAILED\n", __LINE__, #x, #y); \
|
||||
++UDPC_uts.failed; } ++UDPC_uts.total;
|
||||
#define ASSERT_GTE(x, y) \
|
||||
if(x < y) { printf("%d: ASSERT_GTE(%s, %s) FAILED\n", __LINE__, #x, #y); \
|
||||
++UDPC_uts.failed; } ++UDPC_uts.total;
|
||||
#define ASSERT_LT(x, y) \
|
||||
if(x >= y) { printf("%d: ASSERT_LT(%s, %s) FAILED\n", __LINE__, #x, #y); \
|
||||
++UDPC_uts.failed; } ++UDPC_uts.total;
|
||||
#define ASSERT_LTE(x, y) \
|
||||
if(x > y) { printf("%d: ASSERT_LTE(%s, %s) FAILED\n", __LINE__, #x, #y); \
|
||||
++UDPC_uts.failed; } ++UDPC_uts.total;
|
||||
|
||||
#define UNITTEST_REPORT(x) { \
|
||||
printf("%s: %d/%d tests failed\n", #x, UDPC_uts.failed, UDPC_uts.total); \
|
||||
|
|
Loading…
Reference in a new issue