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; return current != NULL ? 1 : 0;
} }
// TODO change to linkedList buckets up to this point
int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity) int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
{ {
if(hm->size > newCapacity) if(hm->size > newCapacity)
@ -180,100 +179,112 @@ int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
return 0; return 0;
} }
UDPC_Deque **newBuckets = malloc(sizeof(UDPC_Deque*) * newCapacity); // allocate newBuckets
UDPC_Deque *newOverflow = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE int fail = 0;
* (4 + hm->unitSize)); UDPC_HashMap_Node **newBuckets = malloc(sizeof(UDPC_HashMap_Node*) * newCapacity);
if(!newBuckets) { return 0; }
for(int x = 0; x < newCapacity; ++x) for(int x = 0; x < newCapacity; ++x)
{ {
newBuckets[x] = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE if(fail != 0) { newBuckets[x] = NULL; continue; }
* (4 + hm->unitSize)); 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; uint32_t hash;
char *data; UDPC_HashMap_Node *current;
int fail = 0; UDPC_HashMap_Node *next;
UDPC_HashMap_Node *newCurrent;
for(int x = 0; x < hm->capacity; ++x) 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); next = current->next;
hash = UDPC_HASHMAP_MOD(*((uint32_t*)data), newCapacity); hash = UDPC_HASHMAP_MOD(current->key, newCapacity);
if(newBuckets[hash]->size < newBuckets[hash]->alloc_size) newCurrent = newBuckets[hash];
while(newCurrent->next)
{ {
if(UDPC_Deque_push_back(newBuckets[hash], data, 4 + hm->unitSize) == 0) newCurrent = newCurrent->next;
{
fail = 1;
break;
}
} }
else if(UDPC_Deque_push_back(newOverflow, data, 4 + hm->unitSize) == 0) newCurrent->next = malloc(sizeof(UDPC_HashMap_Node));
if(!newCurrent->next)
{ {
fail = 1; fail = 1;
break; break;
} }
newCurrent->next->key = current->key;
newCurrent->next->data = current->data;
newCurrent->next->next = NULL;
newCurrent->next->prev = newCurrent;
current = next;
} }
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_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) if(fail != 0)
{ {
for(int x = 0; x < newCapacity; ++x) 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); free(newBuckets);
UDPC_Deque_destroy(newOverflow);
return 0; 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) void UDPC_HashMap_clear(UDPC_HashMap *hm)
{ {
UDPC_HashMap_Node *current;
UDPC_HashMap_Node *next;
for(int x = 0; x < hm->capacity; ++x) 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; hm->size = 0;
} }
@ -287,64 +298,16 @@ uint32_t UDPC_HashMap_get_capacity(UDPC_HashMap *hm)
return hm->capacity; 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 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( fn(userData, current->key, current->data);
hm->buckets[x], 4 + hm->unitSize, y); current = current->next;
if(hm->unitSize > 0) { fn(userData, data + 4); }
else { fn(userData, data); }
} }
} }
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 * \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); void UDPC_HashMap_itercall(UDPC_HashMap *hm, void (*fn)(void*, uint32_t, 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);
#endif #endif