Change HashMap to use llists, testing required

This commit is contained in:
Stephen Seo 2019-02-18 12:13:49 +09:00
parent bb301d84e9
commit 2f794beede
2 changed files with 75 additions and 116 deletions

View file

@ -172,7 +172,6 @@ int UDPC_HashMap_has(UDPC_HashMap *hm, uint32_t key)
return current != NULL ? 1 : 0;
}
// TODO change to linkedList buckets up to this point
int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
{
if(hm->size > newCapacity)
@ -180,100 +179,112 @@ int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
return 0;
}
UDPC_Deque **newBuckets = malloc(sizeof(UDPC_Deque*) * newCapacity);
UDPC_Deque *newOverflow = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE
* (4 + hm->unitSize));
// allocate newBuckets
int fail = 0;
UDPC_HashMap_Node **newBuckets = malloc(sizeof(UDPC_HashMap_Node*) * newCapacity);
if(!newBuckets) { return 0; }
for(int x = 0; x < newCapacity; ++x)
{
newBuckets[x] = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE
* (4 + hm->unitSize));
if(fail != 0) { newBuckets[x] = NULL; continue; }
newBuckets[x] = calloc(1, sizeof(UDPC_HashMap_Node));
if(!newBuckets[x]) { fail = 1; }
}
if(fail != 0)
{
for(int x = 0; x < newCapacity; ++x)
{
if(newBuckets[x]) { free(newBuckets[x]); }
}
free(newBuckets);
return 0;
}
// rehash entries from hm->buckets to newBuckets
uint32_t hash;
char *data;
int fail = 0;
UDPC_HashMap_Node *current;
UDPC_HashMap_Node *next;
UDPC_HashMap_Node *newCurrent;
for(int x = 0; x < hm->capacity; ++x)
{
for(int y = 0; y * (4 + hm->unitSize) < hm->buckets[x]->size; ++y)
current = hm->buckets[x]->next;
while(current)
{
data = UDPC_Deque_index_ptr(hm->buckets[x], 4 + hm->unitSize, y);
hash = UDPC_HASHMAP_MOD(*((uint32_t*)data), newCapacity);
if(newBuckets[hash]->size < newBuckets[hash]->alloc_size)
next = current->next;
hash = UDPC_HASHMAP_MOD(current->key, newCapacity);
newCurrent = newBuckets[hash];
while(newCurrent->next)
{
if(UDPC_Deque_push_back(newBuckets[hash], data, 4 + hm->unitSize) == 0)
{
fail = 1;
break;
}
newCurrent = newCurrent->next;
}
else if(UDPC_Deque_push_back(newOverflow, data, 4 + hm->unitSize) == 0)
newCurrent->next = malloc(sizeof(UDPC_HashMap_Node));
if(!newCurrent->next)
{
fail = 1;
break;
}
newCurrent->next->key = current->key;
newCurrent->next->data = current->data;
newCurrent->next->next = NULL;
newCurrent->next->prev = newCurrent;
current = next;
}
if(fail != 0)
{
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_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)
{
fail = 1;
break;
}
}
else if(UDPC_Deque_push_back(newOverflow, data, 4 + hm->unitSize) == 0)
{
fail = 1;
break;
}
}
}
if(fail != 0)
{
for(int x = 0; x < newCapacity; ++x)
{
UDPC_Deque_destroy(newBuckets[x]);
current = newBuckets[x];
while(current)
{
next = current->next;
free(current);
current = next;
}
}
free(newBuckets);
UDPC_Deque_destroy(newOverflow);
return 0;
}
else
// cleanup hm->buckets to be replaced by newBuckets
for(int x = 0; x < hm->capacity; ++x)
{
for(int x = 0; x < hm->capacity; ++x)
current = hm->buckets[x];
while(current)
{
UDPC_Deque_destroy(hm->buckets[x]);
next = current->next;
// do not free current->data as it is now being pointed to by entries in newBuckets
free(current);
current = next;
}
free(hm->buckets);
UDPC_Deque_destroy(hm->overflow);
hm->buckets = newBuckets;
hm->overflow = newOverflow;
hm->capacity = newCapacity;
return 1;
}
free(hm->buckets);
hm->capacity = newCapacity;
hm->buckets = newBuckets;
return 1;
}
void UDPC_HashMap_clear(UDPC_HashMap *hm)
{
UDPC_HashMap_Node *current;
UDPC_HashMap_Node *next;
for(int x = 0; x < hm->capacity; ++x)
{
UDPC_Deque_clear(hm->buckets[x]);
current = hm->buckets[x]->next;
while(current)
{
next = current->next;
if(current->data) { free(current->data); }
free(current);
current = next;
}
hm->buckets[x]->next = NULL;
}
UDPC_Deque_clear(hm->overflow);
hm->size = 0;
}
@ -287,64 +298,16 @@ uint32_t UDPC_HashMap_get_capacity(UDPC_HashMap *hm)
return hm->capacity;
}
void UDPC_HashMap_itercall(UDPC_HashMap *hm, void (*fn)(void*, char*), void *userData)
void UDPC_HashMap_itercall(UDPC_HashMap *hm, void (*fn)(void*, uint32_t, char*), void *userData)
{
UDPC_HashMap_Node *current;
for(int x = 0; x < hm->capacity; ++x)
{
for(int y = 0; y * (4 + hm->unitSize) < hm->buckets[x]->size; ++y)
current = hm->buckets[x]->next;
while(current)
{
char *data = UDPC_Deque_index_ptr(
hm->buckets[x], 4 + hm->unitSize, y);
if(hm->unitSize > 0) { fn(userData, data + 4); }
else { fn(userData, data); }
fn(userData, current->key, current->data);
current = current->next;
}
}
for(int x = 0; x * (4 + hm->unitSize) < hm->overflow->size; ++x)
{
char *data = UDPC_Deque_index_ptr(
hm->overflow, 4 + hm->unitSize, x);
if(hm->unitSize > 0) { fn(userData, data + 4); }
else { fn(userData, data); }
}
}
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;
}

View file

@ -104,12 +104,8 @@ uint32_t UDPC_HashMap_get_capacity(UDPC_HashMap *hm);
/*!
* \brief Calls a fn with a ptr to each entry in the hash map
* The fn is called with userData, entry key, and entry data.
*/
void UDPC_HashMap_itercall(UDPC_HashMap *hm, void (*fn)(void*, char*), void *userData);
/*!
* \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);
void UDPC_HashMap_itercall(UDPC_HashMap *hm, void (*fn)(void*, uint32_t, char*), void *userData);
#endif