174 lines
3.7 KiB
C
174 lines
3.7 KiB
C
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "ucore/htable.h"
|
|
|
|
int uc_htable_init(struct UHTable *table, size_t buckets)
|
|
{
|
|
if (buckets == 0) {
|
|
return EINVAL;
|
|
}
|
|
|
|
table->buckets = calloc(buckets, sizeof *table->buckets);
|
|
if (table->buckets == NULL) {
|
|
return ENOMEM;
|
|
}
|
|
|
|
table->cnt_buckets = buckets;
|
|
table->cnt_elements = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void uc_htable_destroy(struct UHTable *table)
|
|
{
|
|
free(table->buckets);
|
|
table->buckets = NULL;
|
|
table->cnt_elements = table->cnt_buckets = -1;
|
|
}
|
|
|
|
struct UHNode *uc_htable_first_hash(const struct UHTable *table, size_t hash)
|
|
{
|
|
size_t bucket = uc_htable_bucket(table, hash);
|
|
struct UHNode *it = table->buckets[bucket];
|
|
|
|
while (it && it->hash != hash) {
|
|
it = it->next;
|
|
}
|
|
|
|
return it;
|
|
}
|
|
|
|
//given a node, find the next one in the chain with the given hash
|
|
struct UHNode *uc_htable_next_hash_hlp(struct UHNode *next, size_t hash)
|
|
{
|
|
while (next && next->hash != hash) {
|
|
next = next->next;
|
|
}
|
|
|
|
return next;
|
|
}
|
|
|
|
//find a node, starting at bucket
|
|
struct UHNode *uc_htable_iter_hlp(struct UHTable *table, size_t start_bucket)
|
|
{
|
|
size_t i;
|
|
struct UHNode *found = NULL;
|
|
|
|
//search through buckets until a node is found
|
|
for (i = start_bucket; i < table->cnt_buckets; i++) {
|
|
found = uc_htable_first_bucket(table, i);
|
|
if (found != NULL) {
|
|
break;
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
struct UHNode *uc_htable_next(struct UHTable *table, struct UHNode *node)
|
|
{
|
|
struct UHNode *found;
|
|
|
|
found = uc_htable_next_in_bucket(node);
|
|
if (found == NULL) {
|
|
size_t current_bucket = uc_htable_bucket(table, node->hash);
|
|
found = uc_htable_iter_hlp(table, current_bucket + 1);
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
void uc_htable_swap(struct UHTable *a, struct UHTable *b)
|
|
{
|
|
struct UHTable tmp;
|
|
|
|
tmp = *a;
|
|
*a = *b;
|
|
*b = tmp;
|
|
}
|
|
|
|
int uc_htable_has_node(struct UHTable *table, struct UHNode *node)
|
|
{
|
|
struct UHNode *iter;
|
|
|
|
UC_HTABLE_FOREACH_BUCKET(table, iter, node->hash) {
|
|
if (node == iter) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void uc_htable_clear(struct UHTable *table)
|
|
{
|
|
memset(table->buckets, 0 , sizeof *table->buckets * table->cnt_buckets);
|
|
table->cnt_elements = 0;
|
|
}
|
|
|
|
void uc_htable_insert(struct UHTable *table, struct UHNode *node, size_t hash)
|
|
{
|
|
size_t bucket = uc_htable_bucket(table, hash);
|
|
|
|
node->next = table->buckets[bucket];
|
|
table->buckets[bucket] = node;
|
|
node->hash = hash;
|
|
|
|
table->cnt_elements++;
|
|
}
|
|
|
|
void uc_htable_remove(struct UHTable *table, struct UHNode *node)
|
|
{
|
|
struct UHNode **it = &table->buckets[uc_htable_bucket(table, node->hash)];
|
|
|
|
while (*it) {
|
|
|
|
if (*it == node) {
|
|
*it = (*it)->next;
|
|
table->cnt_elements--;
|
|
break;
|
|
}
|
|
|
|
it = &(*it)->next;
|
|
}
|
|
}
|
|
|
|
int uc_htable_resize(struct UHTable *table, size_t buckets)
|
|
{
|
|
struct UHTable tmp_table;
|
|
int rc;
|
|
size_t h;
|
|
|
|
if (buckets == 0) {
|
|
return EINVAL;
|
|
}
|
|
|
|
//create new temp table
|
|
rc = uc_htable_init(&tmp_table, buckets);
|
|
if (rc != 0) {
|
|
return rc;
|
|
}
|
|
|
|
|
|
//move all the nodes to the new temp table
|
|
for (h = 0; h < table->cnt_buckets; h++) {
|
|
struct UHNode *next;
|
|
struct UHNode *node;
|
|
|
|
for (node = uc_htable_first_bucket(table, h);
|
|
node != NULL;
|
|
node = next) {
|
|
next = node->next;
|
|
uc_htable_insert(&tmp_table, node, node->hash);
|
|
}
|
|
}
|
|
|
|
//replace the existing table with the resized temp table
|
|
uc_htable_swap(&tmp_table, table);
|
|
uc_htable_destroy(&tmp_table);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|