Change HashMap to use llists, testing required
This commit is contained in:
parent
bb301d84e9
commit
2f794beede
2 changed files with 75 additions and 116 deletions
|
@ -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
|
|
||||||
* (4 + hm->unitSize));
|
|
||||||
for(int x = 0; x < newCapacity; ++x)
|
|
||||||
{
|
|
||||||
newBuckets[x] = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE
|
|
||||||
* (4 + hm->unitSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t hash;
|
|
||||||
char *data;
|
|
||||||
int fail = 0;
|
int fail = 0;
|
||||||
for(int x = 0; x < hm->capacity; ++x)
|
UDPC_HashMap_Node **newBuckets = malloc(sizeof(UDPC_HashMap_Node*) * newCapacity);
|
||||||
|
if(!newBuckets) { return 0; }
|
||||||
|
for(int x = 0; x < newCapacity; ++x)
|
||||||
{
|
{
|
||||||
for(int y = 0; y * (4 + hm->unitSize) < hm->buckets[x]->size; ++y)
|
if(fail != 0) { newBuckets[x] = NULL; continue; }
|
||||||
{
|
newBuckets[x] = calloc(1, sizeof(UDPC_HashMap_Node));
|
||||||
data = UDPC_Deque_index_ptr(hm->buckets[x], 4 + hm->unitSize, y);
|
if(!newBuckets[x]) { fail = 1; }
|
||||||
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)
|
|
||||||
{
|
|
||||||
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]);
|
if(newBuckets[x]) { free(newBuckets[x]); }
|
||||||
}
|
}
|
||||||
free(newBuckets);
|
free(newBuckets);
|
||||||
UDPC_Deque_destroy(newOverflow);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
// rehash entries from hm->buckets to newBuckets
|
||||||
|
uint32_t hash;
|
||||||
|
UDPC_HashMap_Node *current;
|
||||||
|
UDPC_HashMap_Node *next;
|
||||||
|
UDPC_HashMap_Node *newCurrent;
|
||||||
for(int x = 0; x < hm->capacity; ++x)
|
for(int x = 0; x < hm->capacity; ++x)
|
||||||
{
|
{
|
||||||
UDPC_Deque_destroy(hm->buckets[x]);
|
current = hm->buckets[x]->next;
|
||||||
|
while(current)
|
||||||
|
{
|
||||||
|
next = current->next;
|
||||||
|
hash = UDPC_HASHMAP_MOD(current->key, newCapacity);
|
||||||
|
newCurrent = newBuckets[hash];
|
||||||
|
while(newCurrent->next)
|
||||||
|
{
|
||||||
|
newCurrent = newCurrent->next;
|
||||||
|
}
|
||||||
|
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 < newCapacity; ++x)
|
||||||
|
{
|
||||||
|
current = newBuckets[x];
|
||||||
|
while(current)
|
||||||
|
{
|
||||||
|
next = current->next;
|
||||||
|
free(current);
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(newBuckets);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup hm->buckets to be replaced by newBuckets
|
||||||
|
for(int x = 0; x < hm->capacity; ++x)
|
||||||
|
{
|
||||||
|
current = hm->buckets[x];
|
||||||
|
while(current)
|
||||||
|
{
|
||||||
|
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);
|
free(hm->buckets);
|
||||||
UDPC_Deque_destroy(hm->overflow);
|
|
||||||
|
|
||||||
hm->buckets = newBuckets;
|
|
||||||
hm->overflow = newOverflow;
|
|
||||||
|
|
||||||
hm->capacity = newCapacity;
|
hm->capacity = newCapacity;
|
||||||
|
hm->buckets = newBuckets;
|
||||||
|
|
||||||
return 1;
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue