aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmdsserver/hash-table.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmdsserver/hash-table.c')
-rw-r--r--src/libmdsserver/hash-table.c581
1 files changed, 282 insertions, 299 deletions
diff --git a/src/libmdsserver/hash-table.c b/src/libmdsserver/hash-table.c
index 000bd20..2a7bc3c 100644
--- a/src/libmdsserver/hash-table.c
+++ b/src/libmdsserver/hash-table.c
@@ -31,8 +31,8 @@
* @param K The key
* @param H The hash of the key
*/
-#define TEST_KEY(T, B, K, H) \
- ((B->key == K) || (T->key_comparator && (B->hash == H) && T->key_comparator(B->key, K)))
+#define TEST_KEY(T, B, K, H)\
+ ((B)->key == (K) || ((T)->key_comparator && (B)->hash == (H) && (T)->key_comparator((B)->key, (K))))
/**
@@ -42,10 +42,10 @@
* @param key The key to hash
* @return The hash of the key
*/
-__attribute__((pure, nonnull))
-static inline size_t hash(const hash_table_t* restrict this, size_t key)
+static inline size_t __attribute__((pure, nonnull))
+hash(const hash_table_t *restrict this, size_t key)
{
- return this->hasher ? this->hasher(key) : key;
+ return this->hasher ? this->hasher(key) : key;
}
@@ -56,10 +56,10 @@ static inline size_t hash(const hash_table_t* restrict this, size_t key)
* @param key The key to hash
* @return A non-negative value less the the table's capacity
*/
-__attribute__((pure, nonnull))
-static inline size_t truncate_hash(const hash_table_t* restrict this, size_t hash)
+static inline size_t __attribute__((pure, nonnull))
+truncate_hash(const hash_table_t *restrict this, size_t hash)
{
- return hash % this->capacity;
+ return hash % this->capacity;
}
@@ -69,49 +69,42 @@ static inline size_t truncate_hash(const hash_table_t* restrict this, size_t has
* @param this The hash table
* @return Non-zero on error, `errno` will be set accordingly
*/
-__attribute__((nonnull))
-static int rehash(hash_table_t* restrict this)
+static int __attribute__((nonnull))
+rehash(hash_table_t *restrict this)
{
- hash_entry_t** old_buckets = this->buckets;
- size_t old_capacity = this->capacity;
- size_t i = old_capacity, index;
- hash_entry_t* bucket;
- hash_entry_t* destination;
- hash_entry_t* next;
-
- fail_if (xcalloc(this->buckets, old_capacity * 2 + 1, hash_entry_t*));
- this->capacity = old_capacity * 2 + 1;
- this->threshold = (size_t)((float)(this->capacity) * this->load_factor);
-
- while (i)
- {
- bucket = this->buckets[--i];
- while (bucket)
- {
- index = truncate_hash(this, bucket->hash);
- if ((destination = this->buckets[index]))
- {
- next = destination->next;
- while (next)
- {
- destination = next;
- next = destination->next;
+ hash_entry_t **old_buckets = this->buckets;
+ size_t old_capacity = this->capacity;
+ size_t i = old_capacity, index;
+ hash_entry_t *bucket;
+ hash_entry_t *destination;
+ hash_entry_t *next;
+
+ fail_if (xcalloc(this->buckets, old_capacity * 2 + 1, hash_entry_t*));
+ this->capacity = old_capacity * 2 + 1;
+ this->threshold = (size_t)((float)(this->capacity) * this->load_factor);
+
+ while (i--) {
+ bucket = this->buckets[i];
+ while (bucket) {
+ index = truncate_hash(this, bucket->hash);
+ if ((destination = this->buckets[index])) {
+ while ((next = destination->next))
+ destination = next;
+ destination->next = bucket;
+ } else {
+ this->buckets[index] = bucket;
+ }
+
+ next = bucket->next;
+ bucket->next = NULL;
+ bucket = next;
}
- destination->next = bucket;
- }
- else
- this->buckets[index] = bucket;
-
- next = bucket->next;
- bucket->next = NULL;
- bucket = next;
}
- }
-
- free(old_buckets);
- return 0;
- fail:
- return -1;
+
+ free(old_buckets);
+ return 0;
+fail:
+ return -1;
}
@@ -123,22 +116,23 @@ static int rehash(hash_table_t* restrict this)
* @param load_factor The load factor of the table, i.e. when to grow the table
* @return Non-zero on error, `errno` will have been set accordingly
*/
-int hash_table_create_fine_tuned(hash_table_t* restrict this, size_t initial_capacity, float load_factor)
+int
+hash_table_create_fine_tuned(hash_table_t *restrict this, size_t initial_capacity, float load_factor)
{
- this->buckets = NULL;
-
- this->capacity = initial_capacity ? initial_capacity : 1;
- fail_if (xcalloc(this->buckets, this->capacity, hash_entry_t*));
- this->load_factor = load_factor;
- this->threshold = (size_t)((float)(this->capacity) * load_factor);
- this->size = 0;
- this->value_comparator = NULL;
- this->key_comparator = NULL;
- this->hasher = NULL;
-
- return 0;
- fail:
- return -1;
+ this->buckets = NULL;
+
+ this->capacity = initial_capacity ? initial_capacity : 1;
+ fail_if (xcalloc(this->buckets, this->capacity, hash_entry_t*));
+ this->load_factor = load_factor;
+ this->threshold = (size_t)((float)(this->capacity) * load_factor);
+ this->size = 0;
+ this->value_comparator = NULL;
+ this->key_comparator = NULL;
+ this->hasher = NULL;
+
+ return 0;
+fail:
+ return -1;
}
@@ -150,27 +144,24 @@ int hash_table_create_fine_tuned(hash_table_t* restrict this, size_t initial_cap
* @param keys_freer Function that frees a key, `NULL` if keys should not be freed
* @param values_freer Function that frees a value, `NULL` if value should not be freed
*/
-void hash_table_destroy(hash_table_t* restrict this, free_func* key_freer, free_func* value_freer)
+void
+hash_table_destroy(hash_table_t *restrict this, free_func *key_freer, free_func *value_freer)
{
- size_t i = this->capacity;
- hash_entry_t* bucket;
- hash_entry_t* last;
-
- if (this->buckets != NULL)
- {
- while (i)
- {
- bucket = this->buckets[--i];
- while (bucket)
- {
- if (key_freer != NULL) key_freer(bucket->key);
- if (value_freer != NULL) value_freer(bucket->value);
- bucket = (last = bucket)->next;
- free(last);
- }
+ size_t i = this->capacity;
+ hash_entry_t *bucket, *last;
+
+ if (this->buckets) {
+ while (i) {
+ bucket = this->buckets[--i];
+ while (bucket) {
+ if (key_freer) key_freer(bucket->key);
+ if (value_freer) value_freer(bucket->value);
+ bucket = (last = bucket)->next;
+ free(last);
+ }
+ }
+ free(this->buckets);
}
- free(this->buckets);
- }
}
@@ -181,25 +172,24 @@ void hash_table_destroy(hash_table_t* restrict this, free_func* key_freer, free_
* @param value The value
* @return Whether the value is stored in the table
*/
-int hash_table_contains_value(const hash_table_t* restrict this, size_t value)
+int
+hash_table_contains_value(const hash_table_t *restrict this, size_t value)
{
- size_t i = this->capacity;
- hash_entry_t* restrict bucket;
-
- while (i)
- {
- bucket = this->buckets[--i];
- while (bucket != NULL)
- {
- if (bucket->value == value)
- return 1;
- if (this->value_comparator && this->value_comparator(bucket->value, value))
- return 1;
- bucket = bucket->next;
+ size_t i = this->capacity;
+ hash_entry_t *restrict bucket;
+
+ while (i--) {
+ bucket = this->buckets[i];
+ while (bucket) {
+ if (bucket->value == value)
+ return 1;
+ if (this->value_comparator && this->value_comparator(bucket->value, value))
+ return 1;
+ bucket = bucket->next;
+ }
}
- }
-
- return 0;
+
+ return 0;
}
@@ -210,20 +200,20 @@ int hash_table_contains_value(const hash_table_t* restrict this, size_t value)
* @param key The key
* @return Whether the key is used
*/
-int hash_table_contains_key(const hash_table_t* restrict this, size_t key)
+int
+hash_table_contains_key(const hash_table_t *restrict this, size_t key)
{
- size_t key_hash = hash(this, key);
- size_t index = truncate_hash(this, key_hash);
- hash_entry_t* restrict bucket = this->buckets[index];
-
- while (bucket)
- {
- if (TEST_KEY(this, bucket, key, key_hash))
- return 1;
- bucket = bucket->next;
- }
-
- return 0;
+ size_t key_hash = hash(this, key);
+ size_t index = truncate_hash(this, key_hash);
+ hash_entry_t *restrict bucket = this->buckets[index];
+
+ while (bucket) {
+ if (TEST_KEY(this, bucket, key, key_hash))
+ return 1;
+ bucket = bucket->next;
+ }
+
+ return 0;
}
@@ -234,20 +224,20 @@ int hash_table_contains_key(const hash_table_t* restrict this, size_t key)
* @param key The key associated with the value
* @return The value associated with the key, 0 if the key was not used
*/
-size_t hash_table_get(const hash_table_t* restrict this, size_t key)
+size_t
+hash_table_get(const hash_table_t *restrict this, size_t key)
{
- size_t key_hash = hash(this, key);
- size_t index = truncate_hash(this, key_hash);
- hash_entry_t* restrict bucket = this->buckets[index];
-
- while (bucket)
- {
- if (TEST_KEY(this, bucket, key, key_hash))
- return bucket->value;
- bucket = bucket->next;
- }
-
- return 0;
+ size_t key_hash = hash(this, key);
+ size_t index = truncate_hash(this, key_hash);
+ hash_entry_t *restrict bucket = this->buckets[index];
+
+ while (bucket) {
+ if (TEST_KEY(this, bucket, key, key_hash))
+ return bucket->value;
+ bucket = bucket->next;
+ }
+
+ return 0;
}
@@ -258,20 +248,20 @@ size_t hash_table_get(const hash_table_t* restrict this, size_t key)
* @param key The key associated with the value
* @return The entry associated with the key, `NULL` if the key was not used
*/
-hash_entry_t* hash_table_get_entry(const hash_table_t* restrict this, size_t key)
+hash_entry_t *
+hash_table_get_entry(const hash_table_t *restrict this, size_t key)
{
- size_t key_hash = hash(this, key);
- size_t index = truncate_hash(this, key_hash);
- hash_entry_t* restrict bucket = this->buckets[index];
-
- while (bucket)
- {
- if (TEST_KEY(this, bucket, key, key_hash))
- return bucket;
- bucket = bucket->next;
- }
-
- return NULL;
+ size_t key_hash = hash(this, key);
+ size_t index = truncate_hash(this, key_hash);
+ hash_entry_t *restrict bucket = this->buckets[index];
+
+ while (bucket) {
+ if (TEST_KEY(this, bucket, key, key_hash))
+ return bucket;
+ bucket = bucket->next;
+ }
+
+ return NULL;
}
@@ -284,41 +274,41 @@ hash_entry_t* hash_table_get_entry(const hash_table_t* restrict this, size_t key
* @return The previous value associated with the key, 0 if the key was not used.
* 0 will also be returned on error, check the `errno` variable.
*/
-size_t hash_table_put(hash_table_t* restrict this, size_t key, size_t value)
+size_t
+hash_table_put(hash_table_t *restrict this, size_t key, size_t value)
{
- size_t key_hash = hash(this, key);
- size_t index = truncate_hash(this, key_hash);
- hash_entry_t* restrict bucket = this->buckets[index];
- size_t rc;
-
- while (bucket)
- if (TEST_KEY(this, bucket, key, key_hash))
- {
- rc = bucket->value;
+ size_t key_hash = hash(this, key);
+ size_t index = truncate_hash(this, key_hash);
+ hash_entry_t *restrict bucket = this->buckets[index];
+ size_t rc;
+
+ while (bucket) {
+ if (TEST_KEY(this, bucket, key, key_hash)) {
+ rc = bucket->value;
+ bucket->value = value;
+ return rc;
+ } else {
+ bucket = bucket->next;
+ }
+ }
+
+ if (++(this->size) > this->threshold) {
+ errno = 0;
+ fail_if (rehash(this));
+ index = truncate_hash(this, key_hash);
+ }
+
+ errno = 0;
+ fail_if (xmalloc(bucket, 1, hash_entry_t));
bucket->value = value;
- return rc;
- }
- else
- bucket = bucket->next;
-
- if (++(this->size) > this->threshold)
- {
- errno = 0;
- fail_if (rehash(this));
- index = truncate_hash(this, key_hash);
- }
-
- errno = 0;
- fail_if (xmalloc(bucket, 1, hash_entry_t));
- bucket->value = value;
- bucket->key = key;
- bucket->hash = key_hash;
- bucket->next = this->buckets[index];
- this->buckets[index] = bucket;
-
- return 0;
- fail:
- return 0;
+ bucket->key = key;
+ bucket->hash = key_hash;
+ bucket->next = this->buckets[index];
+ this->buckets[index] = bucket;
+
+ return 0;
+fail:
+ return 0;
}
@@ -329,32 +319,31 @@ size_t hash_table_put(hash_table_t* restrict this, size_t key, size_t value)
* @param key The key of the entry to remove
* @return The previous value associated with the key, 0 if the key was not used
*/
-size_t hash_table_remove(hash_table_t* restrict this, size_t key)
+size_t
+hash_table_remove(hash_table_t *restrict this, size_t key)
{
- size_t key_hash = hash(this, key);
- size_t index = truncate_hash(this, key_hash);
- hash_entry_t* bucket = this->buckets[index];
- hash_entry_t* last = NULL;
- size_t rc;
-
- while (bucket)
- {
- if (TEST_KEY(this, bucket, key, key_hash))
- {
- if (last == NULL)
- this->buckets[index] = bucket->next;
- else
- last->next = bucket->next;
- this->size--;
- rc = bucket->value;
- free(bucket);
- return rc;
+ size_t key_hash = hash(this, key);
+ size_t index = truncate_hash(this, key_hash);
+ hash_entry_t *bucket = this->buckets[index];
+ hash_entry_t *last = NULL;
+ size_t rc;
+
+ while (bucket) {
+ if (TEST_KEY(this, bucket, key, key_hash)) {
+ if (!last)
+ this->buckets[index] = bucket->next;
+ else
+ last->next = bucket->next;
+ this->size--;
+ rc = bucket->value;
+ free(bucket);
+ return rc;
+ }
+ last = bucket;
+ bucket = bucket->next;
}
- last = bucket;
- bucket = bucket->next;
- }
-
- return 0;
+
+ return 0;
}
@@ -363,32 +352,29 @@ size_t hash_table_remove(hash_table_t* restrict this, size_t key)
*
* @param this The hash table
*/
-void hash_table_clear(hash_table_t* restrict this)
+void
+hash_table_clear(hash_table_t *restrict this)
{
- hash_entry_t** buf;
- hash_entry_t* bucket;
- size_t i, ptr;
-
- if (this->size)
- {
- buf = alloca((this->size + 1) * sizeof(hash_entry_t*));
- i = this->capacity;
- while (i)
- {
- bucket = this->buckets[--i];
- ptr = 0;
- buf[ptr++] = bucket;
- while (bucket)
- {
- bucket = bucket->next;
- buf[ptr++] = bucket;
- }
- while (ptr)
- free(buf[--ptr]);
- this->buckets[i] = NULL;
+ hash_entry_t **buf, *bucket;
+ size_t i, ptr;
+
+ if (this->size) {
+ buf = alloca((this->size + 1) * sizeof(hash_entry_t*));
+ i = this->capacity;
+ while (i--) {
+ bucket = this->buckets[i];
+ ptr = 0;
+ buf[ptr++] = bucket;
+ while (bucket) {
+ bucket = bucket->next;
+ buf[ptr++] = bucket;
+ }
+ while (ptr)
+ free(buf[--ptr]);
+ this->buckets[i] = NULL;
+ }
+ this->size = 0;
}
- this->size = 0;
- }
}
@@ -398,23 +384,23 @@ void hash_table_clear(hash_table_t* restrict this)
* @param this The hash table
* @return The number of bytes to allocate to the output buffer
*/
-size_t hash_table_marshal_size(const hash_table_t* restrict this)
+size_t
+hash_table_marshal_size(const hash_table_t *restrict this)
{
- size_t n = this->capacity;
- size_t rc = 3 * sizeof(size_t) + sizeof(float) + n * sizeof(size_t);
- size_t i, m = 0;
-
- for (i = 0; i < n; i++)
- {
- hash_entry_t* restrict bucket = this->buckets[i];
- while (bucket != NULL)
- {
- bucket = bucket->next;
- m++;
+ size_t n = this->capacity;
+ size_t rc = 3 * sizeof(size_t) + sizeof(float) + n * sizeof(size_t);
+ size_t i, m = 0;
+ hash_entry_t *restrict bucket;
+
+ for (i = 0; i < n; i++) {
+ bucket = this->buckets[i];
+ while (bucket) {
+ bucket = bucket->next;
+ m++;
+ }
}
- }
-
- return rc + m * 3 * sizeof(size_t) + sizeof(int);
+
+ return rc + m * 3 * sizeof(size_t) + sizeof(int);
}
@@ -424,31 +410,31 @@ size_t hash_table_marshal_size(const hash_table_t* restrict this)
* @param this The hash table
* @param data Output buffer for the marshalled data
*/
-void hash_table_marshal(const hash_table_t* restrict this, char* restrict data)
+void
+hash_table_marshal(const hash_table_t *restrict this, char *restrict data)
{
- size_t i, n = this->capacity;
-
- buf_set_next(data, int, HASH_TABLE_T_VERSION);
- buf_set_next(data, size_t, this->capacity);
- buf_set_next(data, float, this->load_factor);
- buf_set_next(data, size_t, this->threshold);
- buf_set_next(data, size_t, this->size);
-
- for (i = 0; i < n; i++)
- {
- hash_entry_t* restrict bucket = this->buckets[i];
- size_t m = 0;
- while (bucket != NULL)
- {
- buf_set(data, size_t, 1 + m * 3 + 0, bucket->key);
- buf_set(data, size_t, 1 + m * 3 + 1, bucket->value);
- buf_set(data, size_t, 1 + m * 3 + 2, bucket->hash);
- bucket = bucket->next;
- m++;
+ size_t i, n = this->capacity, m;
+ hash_entry_t *restrict bucket;
+
+ buf_set_next(data, int, HASH_TABLE_T_VERSION);
+ buf_set_next(data, size_t, this->capacity);
+ buf_set_next(data, float, this->load_factor);
+ buf_set_next(data, size_t, this->threshold);
+ buf_set_next(data, size_t, this->size);
+
+ for (i = 0; i < n; i++) {
+ bucket = this->buckets[i];
+ m = 0;
+ while (bucket) {
+ buf_set(data, size_t, 1 + m * 3 + 0, bucket->key);
+ buf_set(data, size_t, 1 + m * 3 + 1, bucket->value);
+ buf_set(data, size_t, 1 + m * 3 + 2, bucket->hash);
+ bucket = bucket->next;
+ m++;
+ }
+ buf_set(data, size_t, 0, m);
+ buf_next(data, size_t, 1 + m * 3);
}
- buf_set(data, size_t, 0, m);
- buf_next(data, size_t, 1 + m * 3);
- }
}
@@ -461,48 +447,45 @@ void hash_table_marshal(const hash_table_t* restrict this, char* restrict data)
* @return Non-zero on error, `errno` will be set accordingly.
* Destroy the table on error.
*/
-int hash_table_unmarshal(hash_table_t* restrict this, char* restrict data, remap_func* remapper)
+int
+hash_table_unmarshal(hash_table_t *restrict this, char *restrict data, remap_func *remapper)
{
- size_t i, n;
-
- /* buf_get(data, int, 0, HASH_TABLE_T_VERSION); */
- buf_next(data, int, 1);
-
- this->value_comparator = NULL;
- this->key_comparator = NULL;
- this->hasher = NULL;
-
- buf_get_next(data, size_t, this->capacity = n);
- buf_get_next(data, float, this->load_factor);
- buf_get_next(data, size_t, this->threshold);
- buf_get_next(data, size_t, this->size);
-
- fail_if (xcalloc(this->buckets, this->capacity, hash_entry_t*));
-
- for (i = 0; i < n; i++)
- {
- size_t m;
- hash_entry_t* restrict bucket;
- buf_get_next(data, size_t, m);
-
- fail_if (xmalloc(this->buckets[i] = bucket, 1, hash_entry_t));
-
- while (m--)
- {
- if (m == 0)
- bucket->next = NULL;
- else
- fail_if (xmalloc(bucket->next, 1, hash_entry_t));
- buf_get_next(data, size_t, bucket->key);
- buf_get_next(data, size_t, bucket->value);
- if (remapper != NULL)
- bucket->value = remapper(bucket->value);
- buf_get_next(data, size_t, bucket->hash);
+ size_t i, n, m;
+ hash_entry_t *restrict bucket;
+
+ /* buf_get(data, int, 0, HASH_TABLE_T_VERSION); */
+ buf_next(data, int, 1);
+
+ this->value_comparator = NULL;
+ this->key_comparator = NULL;
+ this->hasher = NULL;
+
+ buf_get_next(data, size_t, this->capacity = n);
+ buf_get_next(data, float, this->load_factor);
+ buf_get_next(data, size_t, this->threshold);
+ buf_get_next(data, size_t, this->size);
+
+ fail_if (xcalloc(this->buckets, this->capacity, hash_entry_t*));
+
+ for (i = 0; i < n; i++) {
+ buf_get_next(data, size_t, m);
+
+ fail_if (xmalloc(this->buckets[i] = bucket, 1, hash_entry_t));
+
+ while (m--) {
+ if (!m)
+ bucket->next = NULL;
+ else
+ fail_if (xmalloc(bucket->next, 1, hash_entry_t));
+ buf_get_next(data, size_t, bucket->key);
+ buf_get_next(data, size_t, bucket->value);
+ if (remapper)
+ bucket->value = remapper(bucket->value);
+ buf_get_next(data, size_t, bucket->hash);
+ }
}
- }
-
- return 0;
- fail:
- return -1;
-}
+ return 0;
+fail:
+ return -1;
+}