v1.1.2 Optimized Hm__Bucket creation
This commit is contained in:
71
hm.h
71
hm.h
@@ -1,4 +1,4 @@
|
|||||||
// hm.h - v1.1.1 - MIT License
|
// hm.h - v1.1.2 - MIT License
|
||||||
// chained hash table implementation as a single header library.
|
// chained hash table implementation as a single header library.
|
||||||
//
|
//
|
||||||
// [License and changelog]
|
// [License and changelog]
|
||||||
@@ -77,6 +77,10 @@
|
|||||||
// key already exists, it's value will be overridden. Returns false on error
|
// key already exists, it's value will be overridden. Returns false on error
|
||||||
// only if HM_NO_ASSERT is defined.
|
// only if HM_NO_ASSERT is defined.
|
||||||
//
|
//
|
||||||
|
// WARNING: Passing a 'value' pointer that references memory currently stored
|
||||||
|
// within the HashMap (self-referencing update) results in undefined
|
||||||
|
// behavior. Always pass a pointer to an external memory buffer.
|
||||||
|
//
|
||||||
// void *hm_get(const HashMap *hm, const void *key)
|
// void *hm_get(const HashMap *hm, const void *key)
|
||||||
//
|
//
|
||||||
// This function returns the value associated with the specified key. Returns
|
// This function returns the value associated with the specified key. Returns
|
||||||
@@ -254,8 +258,6 @@ void hm_free(HashMap *hm)
|
|||||||
|
|
||||||
while (cur != NULL) {
|
while (cur != NULL) {
|
||||||
Hm__Bucket *next = cur->next;
|
Hm__Bucket *next = cur->next;
|
||||||
HM_FREE(cur->key);
|
|
||||||
HM_FREE(cur->value);
|
|
||||||
HM_FREE(cur);
|
HM_FREE(cur);
|
||||||
cur = next;
|
cur = next;
|
||||||
}
|
}
|
||||||
@@ -310,25 +312,31 @@ bool hm_put(HashMap *hm, const void *key, const void *value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temporary buffer in case of overlapping pointers
|
// Reallocate the entire bucket
|
||||||
uint8_t *tmp = (uint8_t*)HM_REALLOC(NULL, value_size);
|
size_t size = sizeof(Hm__Bucket) + key_size + value_size;
|
||||||
if (tmp == NULL) {
|
Hm__Bucket *new_bucket = (Hm__Bucket*)HM_REALLOC(cur, size);
|
||||||
|
if (new_bucket == NULL) {
|
||||||
HM_ASSERT(false && "Reallocation failed");
|
HM_ASSERT(false && "Reallocation failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
memcpy(tmp, value, value_size);
|
|
||||||
|
|
||||||
// Realloc and copy
|
// Recalculate key-value pointers
|
||||||
uint8_t *new_value = (uint8_t*)HM_REALLOC(cur->value, value_size);
|
new_bucket->key = (uint8_t*)new_bucket + sizeof(*new_bucket);
|
||||||
if (new_value == NULL) {
|
new_bucket->value = (uint8_t*)new_bucket->key + key_size;
|
||||||
HM_ASSERT(false && "Reallocation failed");
|
new_bucket->value_size = value_size;
|
||||||
HM_FREE(tmp);
|
|
||||||
return false;
|
// Update linked list pointers of neighbors
|
||||||
|
if (new_bucket != cur) {
|
||||||
|
if (new_bucket->prev != NULL) {
|
||||||
|
new_bucket->prev->next = new_bucket;
|
||||||
|
} else {
|
||||||
|
size_t idx = hm__fnv1a(key, key_size) % hm->capacity;
|
||||||
|
hm->map[idx] = new_bucket;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cur->value = new_value;
|
|
||||||
memcpy(cur->value, tmp, value_size);
|
|
||||||
|
|
||||||
HM_FREE(tmp);
|
// Copy the new value
|
||||||
|
memcpy(new_bucket->value, value, value_size);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -406,8 +414,6 @@ bool hm_remove(HashMap *hm, const void *key)
|
|||||||
cur->next->prev = cur->prev;
|
cur->next->prev = cur->prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
HM_FREE(cur->key);
|
|
||||||
HM_FREE(cur->value);
|
|
||||||
HM_FREE(cur);
|
HM_FREE(cur);
|
||||||
--hm->count;
|
--hm->count;
|
||||||
return true;
|
return true;
|
||||||
@@ -631,34 +637,23 @@ Hm__Bucket *hm__bucket_create(const void *key, size_t key_size, const void *valu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allocate bucket
|
// Allocate bucket
|
||||||
Hm__Bucket *bucket = (Hm__Bucket*)HM_REALLOC(NULL, sizeof(*bucket));
|
// [ Hm__Bucket ][ key ][ value ]
|
||||||
|
size_t size = sizeof(Hm__Bucket) + key_size + value_size;
|
||||||
|
Hm__Bucket *bucket = (Hm__Bucket*)HM_REALLOC(NULL, size);
|
||||||
if (bucket == NULL) {
|
if (bucket == NULL) {
|
||||||
HM_ASSERT(false && "Reallocation failed");
|
HM_ASSERT(false && "Reallocation failed");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset(bucket, 0, sizeof(*bucket));
|
memset(bucket, 0, sizeof(*bucket));
|
||||||
|
|
||||||
// Allocate key
|
// Prepare key-value pointers offset
|
||||||
bucket->key = HM_REALLOC(NULL, key_size);
|
bucket->key = (uint8_t*)bucket + sizeof(*bucket);
|
||||||
if (bucket->key == NULL) {
|
bucket->value = (uint8_t*)bucket->key + key_size;
|
||||||
HM_ASSERT(false && "Reallocation failed");
|
bucket->value_size = value_size;
|
||||||
HM_FREE(bucket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate value
|
// Copy key-value data
|
||||||
bucket->value = HM_REALLOC(NULL, value_size);
|
|
||||||
if (bucket->value == NULL) {
|
|
||||||
HM_ASSERT(false && "Reallocation failed");
|
|
||||||
HM_FREE(bucket->key);
|
|
||||||
HM_FREE(bucket);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy Key-value data
|
|
||||||
memcpy(bucket->key, key, key_size);
|
memcpy(bucket->key, key, key_size);
|
||||||
memcpy(bucket->value, value, value_size);
|
memcpy(bucket->value, value, value_size);
|
||||||
bucket->value_size = value_size;
|
|
||||||
|
|
||||||
return bucket;
|
return bucket;
|
||||||
}
|
}
|
||||||
@@ -672,6 +667,8 @@ Hm__Bucket *hm__bucket_create(const void *key, size_t key_size, const void *valu
|
|||||||
/*
|
/*
|
||||||
* Revision history:
|
* Revision history:
|
||||||
*
|
*
|
||||||
|
* 1.1.2 (2026-04-08) Optimized Hm__Bucket creation by only allocating one
|
||||||
|
* buffer instead of three per bucket
|
||||||
* 1.1.1 (2026-02-13) Added new hm_of() helper macro
|
* 1.1.1 (2026-02-13) Added new hm_of() helper macro
|
||||||
* 1.1.0 (2026-01-10) Added new hm_count() function;
|
* 1.1.0 (2026-01-10) Added new hm_count() function;
|
||||||
* Fix value_size comparison in hm_put();
|
* Fix value_size comparison in hm_put();
|
||||||
|
|||||||
Reference in New Issue
Block a user