Merge branch 'hm_linkedlist'
HashMap updated to use linked lists instead of Deques to store entries.
This commit is contained in:
commit
f691af58ab
5 changed files with 194 additions and 257 deletions
|
@ -16,7 +16,7 @@ UDPC_HashMap* UDPC_HashMap_init(uint32_t capacity, uint32_t unitSize)
|
||||||
m->capacity = (capacity > UDPC_HASHMAP_INIT_CAPACITY ? capacity : UDPC_HASHMAP_INIT_CAPACITY);
|
m->capacity = (capacity > UDPC_HASHMAP_INIT_CAPACITY ? capacity : UDPC_HASHMAP_INIT_CAPACITY);
|
||||||
m->unitSize = unitSize;
|
m->unitSize = unitSize;
|
||||||
|
|
||||||
m->buckets = malloc(sizeof(UDPC_Deque*) * m->capacity);
|
m->buckets = malloc(sizeof(UDPC_HashMap_Node*) * m->capacity);
|
||||||
if(!m->buckets)
|
if(!m->buckets)
|
||||||
{
|
{
|
||||||
free(m);
|
free(m);
|
||||||
|
@ -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 * (4 + unitSize));
|
m->buckets[x] = calloc(1, sizeof(UDPC_HashMap_Node));
|
||||||
if(!m->buckets[x])
|
if(!m->buckets[x])
|
||||||
{
|
{
|
||||||
fail = 1;
|
fail = 1;
|
||||||
|
@ -43,22 +43,7 @@ UDPC_HashMap* UDPC_HashMap_init(uint32_t capacity, uint32_t unitSize)
|
||||||
{
|
{
|
||||||
if(m->buckets[x])
|
if(m->buckets[x])
|
||||||
{
|
{
|
||||||
UDPC_Deque_destroy(m->buckets[x]);
|
free(m->buckets[x]);
|
||||||
}
|
|
||||||
}
|
|
||||||
free(m->buckets);
|
|
||||||
free(m);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
m->overflow = UDPC_Deque_init(UDPC_HASHMAP_BUCKET_SIZE * (4 + unitSize));
|
|
||||||
if(!m->overflow)
|
|
||||||
{
|
|
||||||
for(int x = 0; x < m->capacity; ++x)
|
|
||||||
{
|
|
||||||
if(m->buckets[x])
|
|
||||||
{
|
|
||||||
UDPC_Deque_destroy(m->buckets[x]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(m->buckets);
|
free(m->buckets);
|
||||||
|
@ -71,12 +56,20 @@ UDPC_HashMap* UDPC_HashMap_init(uint32_t capacity, uint32_t unitSize)
|
||||||
|
|
||||||
void UDPC_HashMap_destroy(UDPC_HashMap *hashMap)
|
void UDPC_HashMap_destroy(UDPC_HashMap *hashMap)
|
||||||
{
|
{
|
||||||
|
UDPC_HashMap_Node *current;
|
||||||
|
UDPC_HashMap_Node *next;
|
||||||
for(int x = 0; x < hashMap->capacity; ++x)
|
for(int x = 0; x < hashMap->capacity; ++x)
|
||||||
{
|
{
|
||||||
UDPC_Deque_destroy(hashMap->buckets[x]);
|
current = hashMap->buckets[x];
|
||||||
|
while(current)
|
||||||
|
{
|
||||||
|
next = current->next;
|
||||||
|
if(current->data) { free(current->data); }
|
||||||
|
free(current);
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(hashMap->buckets);
|
free(hashMap->buckets);
|
||||||
UDPC_Deque_destroy(hashMap->overflow);
|
|
||||||
free(hashMap);
|
free(hashMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,43 +85,27 @@ void* UDPC_HashMap_insert(UDPC_HashMap *hm, uint32_t key, void *data)
|
||||||
|
|
||||||
uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
|
uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
|
||||||
|
|
||||||
char *temp = malloc(4 + hm->unitSize);
|
UDPC_HashMap_Node *current = hm->buckets[hash];
|
||||||
memcpy(temp, &key, 4);
|
while(current->next)
|
||||||
if(hm->unitSize > 0)
|
|
||||||
{
|
{
|
||||||
memcpy(temp + 4, data, hm->unitSize);
|
current = current->next;
|
||||||
}
|
}
|
||||||
|
current->next = malloc(sizeof(UDPC_HashMap_Node));
|
||||||
|
current->next->key = key;
|
||||||
|
if(hm->unitSize != 0)
|
||||||
|
{
|
||||||
|
current->next->data = malloc(hm->unitSize);
|
||||||
|
memcpy(current->next->data, data, hm->unitSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current->next->data = NULL;
|
||||||
|
}
|
||||||
|
current->next->next = NULL;
|
||||||
|
current->next->prev = current;
|
||||||
|
|
||||||
if(UDPC_Deque_get_available(hm->buckets[hash]) == 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(UDPC_Deque_push_back(hm->buckets[hash], temp, 4 + hm->unitSize) == 0)
|
|
||||||
{
|
|
||||||
free(temp);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(temp);
|
|
||||||
++hm->size;
|
++hm->size;
|
||||||
temp = UDPC_Deque_get_back_ptr(hm->buckets[hash], 4 + hm->unitSize);
|
return current->next->data;
|
||||||
return temp + 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int UDPC_HashMap_remove(UDPC_HashMap *hm, uint32_t key)
|
int UDPC_HashMap_remove(UDPC_HashMap *hm, uint32_t key)
|
||||||
|
@ -140,47 +117,23 @@ int UDPC_HashMap_remove(UDPC_HashMap *hm, uint32_t key)
|
||||||
|
|
||||||
uint32_t hash = UDPC_HASHMAP_MOD(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)
|
UDPC_HashMap_Node *current = hm->buckets[hash]->next;
|
||||||
|
while(current && current->key != key)
|
||||||
{
|
{
|
||||||
if(memcmp(
|
current = current->next;
|
||||||
UDPC_Deque_index_ptr(hm->buckets[hash], 4 + hm->unitSize, x),
|
|
||||||
&key,
|
|
||||||
4) == 0)
|
|
||||||
{
|
|
||||||
int result = UDPC_Deque_remove(hm->buckets[hash], 4 + hm->unitSize, x);
|
|
||||||
if(result != 0)
|
|
||||||
{
|
|
||||||
--hm->size;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int x = 0; x * (4 + hm->unitSize) < hm->overflow->size; ++x)
|
if(!current) { return 0; }
|
||||||
{
|
|
||||||
if(memcmp(
|
|
||||||
UDPC_Deque_index_ptr(hm->overflow, 4 + hm->unitSize, x),
|
|
||||||
&key,
|
|
||||||
4) == 0)
|
|
||||||
{
|
|
||||||
int result = UDPC_Deque_remove(hm->overflow, 4 + hm->unitSize, x);
|
|
||||||
if(result != 0)
|
|
||||||
{
|
|
||||||
--hm->size;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
current->prev->next = current->next;
|
||||||
|
if(current->next) { current->next->prev = current->prev; }
|
||||||
|
|
||||||
|
if(current->data) { free(current->data); }
|
||||||
|
free(current);
|
||||||
|
|
||||||
|
--hm->size;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* UDPC_HashMap_get(UDPC_HashMap *hm, uint32_t key)
|
void* UDPC_HashMap_get(UDPC_HashMap *hm, uint32_t key)
|
||||||
|
@ -192,39 +145,33 @@ void* UDPC_HashMap_get(UDPC_HashMap *hm, uint32_t key)
|
||||||
|
|
||||||
uint32_t hash = UDPC_HASHMAP_MOD(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)
|
UDPC_HashMap_Node *current = hm->buckets[hash];
|
||||||
|
while(current && (current == hm->buckets[hash] || current->key != key))
|
||||||
{
|
{
|
||||||
char *ptr = UDPC_Deque_index_ptr(hm->buckets[hash], 4 + hm->unitSize, x);
|
current = current->next;
|
||||||
if(memcmp(ptr, &key, 4) == 0)
|
|
||||||
{
|
|
||||||
if(hm->unitSize > 0)
|
|
||||||
{
|
|
||||||
return ptr + 4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int x = 0; x * (4 + hm->unitSize) < hm->overflow->size; ++x)
|
if(!current) { return NULL; }
|
||||||
|
|
||||||
|
return current->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UDPC_HashMap_has(UDPC_HashMap *hm, uint32_t key)
|
||||||
|
{
|
||||||
|
if(hm->size == 0)
|
||||||
{
|
{
|
||||||
char *ptr = UDPC_Deque_index_ptr(hm->overflow, 4 + hm->unitSize, x);
|
return 0;
|
||||||
if(memcmp(ptr, &key, 4) == 0)
|
|
||||||
{
|
|
||||||
if(hm->unitSize > 0)
|
|
||||||
{
|
|
||||||
return ptr + 4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
uint32_t hash = UDPC_HASHMAP_MOD(key, hm->capacity);
|
||||||
|
|
||||||
|
UDPC_HashMap_Node *current = hm->buckets[hash];
|
||||||
|
while(current && (current == hm->buckets[hash] || current->key != key))
|
||||||
|
{
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current != NULL ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
|
int UDPC_HashMap_realloc(UDPC_HashMap *hm, uint32_t newCapacity)
|
||||||
|
@ -234,100 +181,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,64 +300,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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef UDPC_HASHMAP_H
|
#ifndef UDPC_HASHMAP_H
|
||||||
#define UDPC_HASHMAP_H
|
#define UDPC_HASHMAP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// 5 8 2 7 3 6 1
|
// 5 8 2 7 3 6 1
|
||||||
// 3 2 5 1 8 7 6
|
// 3 2 5 1 8 7 6
|
||||||
#define UDPC_HASH32(x) ( \
|
#define UDPC_HASH32(x) ( \
|
||||||
|
@ -16,18 +18,22 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
#define UDPC_HASHMAP_INIT_CAPACITY 13
|
#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)
|
#define UDPC_HASHMAP_MOD(k, m) ((UDPC_HASH32(k) % (m * 2 + 1)) % m)
|
||||||
|
|
||||||
#include "UDPC_Deque.h"
|
struct UDPC_HashMap_Node {
|
||||||
|
uint32_t key;
|
||||||
|
char *data;
|
||||||
|
struct UDPC_HashMap_Node *next;
|
||||||
|
struct UDPC_HashMap_Node *prev;
|
||||||
|
};
|
||||||
|
typedef struct UDPC_HashMap_Node UDPC_HashMap_Node;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t capacity;
|
uint32_t capacity;
|
||||||
uint32_t unitSize;
|
uint32_t unitSize;
|
||||||
UDPC_Deque **buckets;
|
UDPC_HashMap_Node **buckets;
|
||||||
UDPC_Deque *overflow;
|
|
||||||
} UDPC_HashMap;
|
} UDPC_HashMap;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -54,7 +60,7 @@ void UDPC_HashMap_destroy(UDPC_HashMap *hashMap);
|
||||||
* It is possible to insert items with duplicate keys. In that case, the first
|
* 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
|
* duplicate inserted will be the first returned with get() and first removed
|
||||||
* with remove().
|
* with remove().
|
||||||
* \return Internally managed pointer to inserted data, NULL on fail
|
* \return Pointer to inserted data, NULL on fail or unitSize = 0
|
||||||
*/
|
*/
|
||||||
void* UDPC_HashMap_insert(UDPC_HashMap *hm, uint32_t key, void *data);
|
void* UDPC_HashMap_insert(UDPC_HashMap *hm, uint32_t key, void *data);
|
||||||
|
|
||||||
|
@ -69,10 +75,15 @@ int UDPC_HashMap_remove(UDPC_HashMap *hm, uint32_t key);
|
||||||
* Note if unitSize == 0, then the returned pointer will point to a copy of
|
* Note if unitSize == 0, then the returned pointer will point to a copy of
|
||||||
* its integer key, which should not be changed manually (otherwise, the hash
|
* its integer key, which should not be changed manually (otherwise, the hash
|
||||||
* map would not be able to find it).
|
* map would not be able to find it).
|
||||||
* \return non-NULL if data was found
|
* \return non-NULL if data was found and unitSize != 0
|
||||||
*/
|
*/
|
||||||
void* UDPC_HashMap_get(UDPC_HashMap *hm, uint32_t key);
|
void* UDPC_HashMap_get(UDPC_HashMap *hm, uint32_t key);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \return non-zero if item with specified key is in the hash map
|
||||||
|
*/
|
||||||
|
int UDPC_HashMap_has(UDPC_HashMap *hm, uint32_t key);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Resizes the maximum capacity of a hash map
|
* \brief Resizes the maximum capacity of a hash map
|
||||||
* Note on fail, the hash map is unchanged.
|
* Note on fail, the hash map is unchanged.
|
||||||
|
@ -93,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
|
||||||
|
|
|
@ -152,7 +152,7 @@ void UDPC_destroy(UDPC_Context *ctx)
|
||||||
free(ctx);
|
free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDPC_INTERNAL_destroy_conMap(void *unused, char *data)
|
void UDPC_INTERNAL_destroy_conMap(void *unused, uint32_t addr, char *data)
|
||||||
{
|
{
|
||||||
UDPC_INTERNAL_ConnectionData *cd = (UDPC_INTERNAL_ConnectionData*)data;
|
UDPC_INTERNAL_ConnectionData *cd = (UDPC_INTERNAL_ConnectionData*)data;
|
||||||
for(int x = 0; x * sizeof(UDPC_INTERNAL_PacketInfo) < cd->sentPkts->size; ++x)
|
for(int x = 0; x * sizeof(UDPC_INTERNAL_PacketInfo) < cd->sentPkts->size; ++x)
|
||||||
|
@ -352,7 +352,7 @@ void UDPC_update(UDPC_Context *ctx)
|
||||||
// TODO rest of received packet actions
|
// TODO rest of received packet actions
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDPC_INTERNAL_update_to_rtt_si(void *userData, char *data)
|
void UDPC_INTERNAL_update_to_rtt_si(void *userData, uint32_t addr, char *data)
|
||||||
{
|
{
|
||||||
UDPC_INTERNAL_update_struct *us =
|
UDPC_INTERNAL_update_struct *us =
|
||||||
(UDPC_INTERNAL_update_struct*)userData;
|
(UDPC_INTERNAL_update_struct*)userData;
|
||||||
|
@ -361,9 +361,9 @@ void UDPC_INTERNAL_update_to_rtt_si(void *userData, char *data)
|
||||||
// check for timed out connection
|
// check for timed out connection
|
||||||
if(UDPC_ts_diff_to_seconds(&us->tsNow, &cd->received) >= UDPC_TIMEOUT_SECONDS)
|
if(UDPC_ts_diff_to_seconds(&us->tsNow, &cd->received) >= UDPC_TIMEOUT_SECONDS)
|
||||||
{
|
{
|
||||||
UDPC_Deque_push_back(us->removedQueue, &cd->addr, 4);
|
UDPC_Deque_push_back(us->removedQueue, &addr, 4);
|
||||||
UDPC_INTERNAL_log(us->ctx, 2, "Connection timed out with addr %s port %d",
|
UDPC_INTERNAL_log(us->ctx, 2, "Connection timed out with addr %s port %d",
|
||||||
UDPC_INTERNAL_atostr(us->ctx, cd->addr),
|
UDPC_INTERNAL_atostr(us->ctx, addr),
|
||||||
cd->port);
|
cd->port);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -375,7 +375,7 @@ void UDPC_INTERNAL_update_to_rtt_si(void *userData, char *data)
|
||||||
{
|
{
|
||||||
// good mode, bad rtt
|
// good mode, bad rtt
|
||||||
UDPC_INTERNAL_log(us->ctx, 2, "Connection with %s switching to bad mode",
|
UDPC_INTERNAL_log(us->ctx, 2, "Connection with %s switching to bad mode",
|
||||||
UDPC_INTERNAL_atostr(us->ctx, cd->addr));
|
UDPC_INTERNAL_atostr(us->ctx, addr));
|
||||||
|
|
||||||
cd->flags = cd->flags & 0xFFFFFFFD;
|
cd->flags = cd->flags & 0xFFFFFFFD;
|
||||||
if(cd->toggledTimer <= 10.0f)
|
if(cd->toggledTimer <= 10.0f)
|
||||||
|
@ -409,7 +409,7 @@ void UDPC_INTERNAL_update_to_rtt_si(void *userData, char *data)
|
||||||
cd->toggleTimer = 0.0f;
|
cd->toggleTimer = 0.0f;
|
||||||
cd->toggledTimer = 0.0f;
|
cd->toggledTimer = 0.0f;
|
||||||
UDPC_INTERNAL_log(us->ctx, 2, "Connection with %s switching to good mode",
|
UDPC_INTERNAL_log(us->ctx, 2, "Connection with %s switching to good mode",
|
||||||
UDPC_INTERNAL_atostr(us->ctx, cd->addr));
|
UDPC_INTERNAL_atostr(us->ctx, addr));
|
||||||
cd->flags |= 0x2;
|
cd->flags |= 0x2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -429,7 +429,7 @@ void UDPC_INTERNAL_update_to_rtt_si(void *userData, char *data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDPC_INTERNAL_update_send(void *userData, char *data)
|
void UDPC_INTERNAL_update_send(void *userData, uint32_t addr, char *data)
|
||||||
{
|
{
|
||||||
UDPC_INTERNAL_update_struct *us =
|
UDPC_INTERNAL_update_struct *us =
|
||||||
(UDPC_INTERNAL_update_struct*)userData;
|
(UDPC_INTERNAL_update_struct*)userData;
|
||||||
|
@ -454,7 +454,7 @@ void UDPC_INTERNAL_update_send(void *userData, char *data)
|
||||||
|
|
||||||
struct sockaddr_in destinationInfo;
|
struct sockaddr_in destinationInfo;
|
||||||
destinationInfo.sin_family = AF_INET;
|
destinationInfo.sin_family = AF_INET;
|
||||||
destinationInfo.sin_addr.s_addr = cd->addr;
|
destinationInfo.sin_addr.s_addr = addr;
|
||||||
destinationInfo.sin_port = htons(cd->port);
|
destinationInfo.sin_port = htons(cd->port);
|
||||||
long int sentBytes = sendto(
|
long int sentBytes = sendto(
|
||||||
us->ctx->socketHandle,
|
us->ctx->socketHandle,
|
||||||
|
@ -466,13 +466,13 @@ void UDPC_INTERNAL_update_send(void *userData, char *data)
|
||||||
if(sentBytes != 20)
|
if(sentBytes != 20)
|
||||||
{
|
{
|
||||||
UDPC_INTERNAL_log(us->ctx, 0, "Failed to send packet to %s port %d",
|
UDPC_INTERNAL_log(us->ctx, 0, "Failed to send packet to %s port %d",
|
||||||
UDPC_INTERNAL_atostr(us->ctx, cd->addr), cd->port);
|
UDPC_INTERNAL_atostr(us->ctx, addr), cd->port);
|
||||||
free(data);
|
free(data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UDPC_INTERNAL_PacketInfo sentInfo = {
|
UDPC_INTERNAL_PacketInfo sentInfo = {
|
||||||
cd->addr,
|
addr,
|
||||||
cd->lseq - 1,
|
cd->lseq - 1,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -510,7 +510,7 @@ void UDPC_INTERNAL_update_send(void *userData, char *data)
|
||||||
|
|
||||||
struct sockaddr_in destinationInfo;
|
struct sockaddr_in destinationInfo;
|
||||||
destinationInfo.sin_family = AF_INET;
|
destinationInfo.sin_family = AF_INET;
|
||||||
destinationInfo.sin_addr.s_addr = cd->addr;
|
destinationInfo.sin_addr.s_addr = addr;
|
||||||
destinationInfo.sin_port = htons(cd->port);
|
destinationInfo.sin_port = htons(cd->port);
|
||||||
long int sentBytes = sendto(
|
long int sentBytes = sendto(
|
||||||
us->ctx->socketHandle,
|
us->ctx->socketHandle,
|
||||||
|
@ -522,7 +522,7 @@ void UDPC_INTERNAL_update_send(void *userData, char *data)
|
||||||
if(sentBytes != 20 + pinfo->size)
|
if(sentBytes != 20 + pinfo->size)
|
||||||
{
|
{
|
||||||
UDPC_INTERNAL_log(us->ctx, 0, "Failed to send packet to %s port %d",
|
UDPC_INTERNAL_log(us->ctx, 0, "Failed to send packet to %s port %d",
|
||||||
UDPC_INTERNAL_atostr(us->ctx, cd->addr), cd->port);
|
UDPC_INTERNAL_atostr(us->ctx, addr), cd->port);
|
||||||
free(data);
|
free(data);
|
||||||
free(pinfo->data);
|
free(pinfo->data);
|
||||||
UDPC_Deque_pop_front(cd->sendPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
|
UDPC_Deque_pop_front(cd->sendPktQueue, sizeof(UDPC_INTERNAL_PacketInfo));
|
||||||
|
@ -532,7 +532,7 @@ void UDPC_INTERNAL_update_send(void *userData, char *data)
|
||||||
if((pinfo->flags & 0x2) != 0)
|
if((pinfo->flags & 0x2) != 0)
|
||||||
{
|
{
|
||||||
UDPC_INTERNAL_PacketInfo sentInfo = {
|
UDPC_INTERNAL_PacketInfo sentInfo = {
|
||||||
cd->addr,
|
addr,
|
||||||
cd->lseq - 1,
|
cd->lseq - 1,
|
||||||
0x2,
|
0x2,
|
||||||
data,
|
data,
|
||||||
|
@ -545,7 +545,7 @@ void UDPC_INTERNAL_update_send(void *userData, char *data)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UDPC_INTERNAL_PacketInfo sentInfo = {
|
UDPC_INTERNAL_PacketInfo sentInfo = {
|
||||||
cd->addr,
|
addr,
|
||||||
cd->lseq - 1,
|
cd->lseq - 1,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
|
|
|
@ -109,7 +109,7 @@ UDPC_Context* UDPC_init_threaded_update(uint16_t listenPort, int isClient);
|
||||||
|
|
||||||
void UDPC_destroy(UDPC_Context *ctx);
|
void UDPC_destroy(UDPC_Context *ctx);
|
||||||
|
|
||||||
void UDPC_INTERNAL_destroy_conMap(void *unused, char *data);
|
void UDPC_INTERNAL_destroy_conMap(void *unused, uint32_t addr, char *data);
|
||||||
|
|
||||||
uint32_t UDPC_get_error(UDPC_Context *ctx);
|
uint32_t UDPC_get_error(UDPC_Context *ctx);
|
||||||
|
|
||||||
|
@ -129,9 +129,9 @@ void UDPC_set_logging_type(UDPC_Context *ctx, uint32_t logType);
|
||||||
/// If threaded, this function is called automatically
|
/// If threaded, this function is called automatically
|
||||||
void UDPC_update(UDPC_Context *ctx);
|
void UDPC_update(UDPC_Context *ctx);
|
||||||
|
|
||||||
void UDPC_INTERNAL_update_to_rtt_si(void *userData, char *data);
|
void UDPC_INTERNAL_update_to_rtt_si(void *userData, uint32_t addr, char *data);
|
||||||
|
|
||||||
void UDPC_INTERNAL_update_send(void *userData, char *data);
|
void UDPC_INTERNAL_update_send(void *userData, uint32_t addr, char *data);
|
||||||
|
|
||||||
float UDPC_ts_diff_to_seconds(struct timespec *ts0, struct timespec *ts1);
|
float UDPC_ts_diff_to_seconds(struct timespec *ts0, struct timespec *ts1);
|
||||||
|
|
||||||
|
|
|
@ -232,11 +232,11 @@ void TEST_ATOSTR()
|
||||||
UNITTEST_REPORT(ATOSTR);
|
UNITTEST_REPORT(ATOSTR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TEST_HASHMAP_itercall_comp(void *userData, char *data)
|
void TEST_HASHMAP_itercall_comp(void *userData, uint32_t key, char *data)
|
||||||
{
|
{
|
||||||
*((int*)userData) += 1;
|
*((int*)userData) += 1;
|
||||||
int temp = *((int*)(data)) / 100;
|
int temp = *((int*)(data)) / 100;
|
||||||
ASSERT_EQ_MEM(&temp, data - 4, 4);
|
ASSERT_EQ(temp, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TEST_HASHMAP()
|
void TEST_HASHMAP()
|
||||||
|
@ -247,20 +247,32 @@ void TEST_HASHMAP()
|
||||||
temp = 1333;
|
temp = 1333;
|
||||||
ASSERT_NEQ(UDPC_HashMap_insert(hm, 0, &temp), NULL);
|
ASSERT_NEQ(UDPC_HashMap_insert(hm, 0, &temp), NULL);
|
||||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 0), &temp, sizeof(int));
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 0), &temp, sizeof(int));
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, 0), 0);
|
||||||
|
ASSERT_EQ(UDPC_HashMap_has(hm, 1), 0);
|
||||||
|
|
||||||
temp = 9999;
|
temp = 9999;
|
||||||
ASSERT_NEQ(UDPC_HashMap_insert(hm, 1, &temp), NULL);
|
ASSERT_NEQ(UDPC_HashMap_insert(hm, 1, &temp), NULL);
|
||||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 1), &temp, sizeof(int));
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 1), &temp, sizeof(int));
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, 0), 0);
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, 1), 0);
|
||||||
|
ASSERT_EQ(UDPC_HashMap_has(hm, 2), 0);
|
||||||
|
|
||||||
temp = 1235987;
|
temp = 1235987;
|
||||||
ASSERT_NEQ(UDPC_HashMap_insert(hm, 2, &temp), NULL);
|
ASSERT_NEQ(UDPC_HashMap_insert(hm, 2, &temp), NULL);
|
||||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 2), &temp, sizeof(int));
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 2), &temp, sizeof(int));
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, 0), 0);
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, 1), 0);
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, 2), 0);
|
||||||
|
ASSERT_EQ(UDPC_HashMap_has(hm, 3), 0);
|
||||||
|
|
||||||
ASSERT_NEQ(UDPC_HashMap_remove(hm, 1), 0);
|
ASSERT_NEQ(UDPC_HashMap_remove(hm, 1), 0);
|
||||||
temp = 1333;
|
temp = 1333;
|
||||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 0), &temp, sizeof(int));
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 0), &temp, sizeof(int));
|
||||||
temp = 1235987;
|
temp = 1235987;
|
||||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 2), &temp, sizeof(int));
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 2), &temp, sizeof(int));
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, 0), 0);
|
||||||
|
ASSERT_EQ(UDPC_HashMap_has(hm, 1), 0);
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, 2), 0);
|
||||||
|
|
||||||
ASSERT_EQ(UDPC_HashMap_realloc(hm, 0), 0);
|
ASSERT_EQ(UDPC_HashMap_realloc(hm, 0), 0);
|
||||||
ASSERT_NEQ(UDPC_HashMap_realloc(hm, 16), 0);
|
ASSERT_NEQ(UDPC_HashMap_realloc(hm, 16), 0);
|
||||||
|
@ -269,6 +281,9 @@ void TEST_HASHMAP()
|
||||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 0), &temp, sizeof(int));
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 0), &temp, sizeof(int));
|
||||||
temp = 1235987;
|
temp = 1235987;
|
||||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 2), &temp, sizeof(int));
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, 2), &temp, sizeof(int));
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, 0), 0);
|
||||||
|
ASSERT_EQ(UDPC_HashMap_has(hm, 1), 0);
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, 2), 0);
|
||||||
|
|
||||||
UDPC_HashMap_clear(hm);
|
UDPC_HashMap_clear(hm);
|
||||||
ASSERT_EQ(hm->size, 0);
|
ASSERT_EQ(hm->size, 0);
|
||||||
|
@ -287,6 +302,7 @@ void TEST_HASHMAP()
|
||||||
{
|
{
|
||||||
temp = x * 100;
|
temp = x * 100;
|
||||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, x), 0);
|
||||||
}
|
}
|
||||||
ASSERT_GTE(hm->capacity, 8);
|
ASSERT_GTE(hm->capacity, 8);
|
||||||
|
|
||||||
|
@ -296,12 +312,14 @@ void TEST_HASHMAP()
|
||||||
{
|
{
|
||||||
temp = x * 100;
|
temp = x * 100;
|
||||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, x), 0);
|
||||||
}
|
}
|
||||||
ASSERT_GTE(hm->capacity, 16);
|
ASSERT_GTE(hm->capacity, 16);
|
||||||
|
|
||||||
for(int x = 0; x < 9; ++x)
|
for(int x = 0; x < 9; ++x)
|
||||||
{
|
{
|
||||||
ASSERT_NEQ(UDPC_HashMap_remove(hm, x), 0);
|
ASSERT_NEQ(UDPC_HashMap_remove(hm, x), 0);
|
||||||
|
ASSERT_EQ(UDPC_HashMap_has(hm, x), 0);
|
||||||
}
|
}
|
||||||
ASSERT_EQ(hm->size, 0);
|
ASSERT_EQ(hm->size, 0);
|
||||||
ASSERT_GTE(hm->capacity, 16);
|
ASSERT_GTE(hm->capacity, 16);
|
||||||
|
@ -317,6 +335,7 @@ void TEST_HASHMAP()
|
||||||
{
|
{
|
||||||
temp = x * 100;
|
temp = x * 100;
|
||||||
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
|
ASSERT_EQ_MEM(UDPC_HashMap_get(hm, x), &temp, sizeof(int));
|
||||||
|
ASSERT_NEQ(UDPC_HashMap_has(hm, x), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
temp = 0;
|
temp = 0;
|
||||||
|
|
Loading…
Reference in a new issue