diff options
| author | chenzizhan <[email protected]> | 2024-07-26 18:02:29 +0800 |
|---|---|---|
| committer | chenzizhan <[email protected]> | 2024-07-26 18:02:29 +0800 |
| commit | 240bbbb0e0409a6bca409eb319a0a00960cbc6fb (patch) | |
| tree | b15ddd24d6b851ccf797a5919df52d7994e4dbc9 /src/cells/hash_table.c | |
| parent | 3f46275f81d2d5af416f27fb24ab2c5ac21ec418 (diff) | |
| parent | 97e8724310c1a0d51600d723c6d3dcb6c4495d5f (diff) | |
Merge branch 'refactor-heavykeeper-newkey' into develop-version4
Diffstat (limited to 'src/cells/hash_table.c')
| -rw-r--r-- | src/cells/hash_table.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/src/cells/hash_table.c b/src/cells/hash_table.c new file mode 100644 index 0000000..255a3ef --- /dev/null +++ b/src/cells/hash_table.c @@ -0,0 +1,233 @@ +#include "hash_table.h" + +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "uthash.h" + +#include "fieldstat.h" +#include "exdata.h" + +struct entry { + char *key; + size_t key_len; + void *exdata; + bool dying; + UT_hash_handle hh; +}; + +struct hash_table { + struct entry *key_exdata_map; + int current_cell_num; + int max_cell_num; + + exdata_new_cb new_fn; + exdata_free_cb free_fn; + exdata_merge_cb merge_fn; + exdata_reset_cb reset_fn; + exdata_copy_cb copy_fn; +}; +static void *default_new_fn(void *arg) { + return NULL; +} + +static void default_free_fn(void *exdata) { + return; +} + +static void default_merge_fn(void *dest, void *src) { + return; +} + +static void default_reset_fn(void *exdata) { + return; +} + +static void *default_copy_fn(void *exdata) { + return exdata; +} + + +struct hash_table *hash_table_new(int max_query_num) { + struct hash_table *pthis = calloc(1, sizeof(struct hash_table)); + + pthis->max_cell_num = max_query_num; + + pthis->new_fn = default_new_fn; + pthis->free_fn = default_free_fn; + pthis->merge_fn = default_merge_fn; + pthis->reset_fn = default_reset_fn; + pthis->copy_fn = default_copy_fn; + return pthis; +} + +void hash_table_free(struct hash_table *pthis) { + if (pthis == NULL) { + return; + } + struct entry *item, *tmp; + HASH_ITER(hh, pthis->key_exdata_map, item, tmp) { + HASH_DEL(pthis->key_exdata_map, item); + free(item->key); + pthis->free_fn(item->exdata); + free(item); + } + free(pthis); +} + +void hash_table_reset(struct hash_table *pthis) { + struct entry *node, *tmp; + HASH_ITER(hh, pthis->key_exdata_map, node, tmp) { + if (!node->dying) { + node->dying = true; + pthis->reset_fn(node->exdata); + continue; + } + HASH_DEL(pthis->key_exdata_map, node); + free(node->key); + pthis->free_fn(node->exdata); + free(node); + } + + pthis->current_cell_num = 0; +} + +static char *my_keydup(const char *key, size_t key_len) { + char *ret = calloc(1, key_len + 1); + memcpy(ret, key, key_len); + return ret; +} + +int hash_table_add(struct hash_table *pthis, const char *key, size_t key_len, void *arg) { + struct entry *item; + HASH_FIND(hh, pthis->key_exdata_map, key, key_len, item); + if (item != NULL && !item->dying) { + return 1; + } + + if (pthis->current_cell_num >= pthis->max_cell_num) { + return 0; + } + + if (item != NULL) { + assert(item->dying); + item->dying = false; + pthis->current_cell_num++; + return 1; + } + + item = calloc(1, sizeof(struct entry)); + item->key = my_keydup(key, key_len); + item->key_len = key_len; + item->exdata = pthis->new_fn(arg); + item->dying = false; + HASH_ADD_KEYPTR(hh, pthis->key_exdata_map, item->key, key_len, item); + + pthis->current_cell_num++; + return 1; +} + +void hash_table_set_exdata_schema(struct hash_table *pthis, exdata_new_cb new_fn, exdata_free_cb free_fn, exdata_merge_cb merge_fn, exdata_reset_cb reset_fn, exdata_copy_cb copy_fn) { + pthis->new_fn = new_fn; + pthis->free_fn = free_fn; + pthis->merge_fn = merge_fn; + pthis->reset_fn = reset_fn; + pthis->copy_fn = copy_fn; +} + +void *hash_table_get0_exdata(struct hash_table *pthis, const char *key, size_t key_len) { + struct entry *item; + HASH_FIND(hh, pthis->key_exdata_map, key, key_len, item); + if (item == NULL || item->dying) { + return NULL; + } + return item->exdata; +} + +int hash_table_get_count(const struct hash_table *pthis) { + return pthis->current_cell_num; +} + +size_t hash_table_list(const struct hash_table *pthis, void **exdatas, size_t n_exdatas) { + size_t actual_len = pthis->current_cell_num; + if (actual_len == 0) { + return 0; + } + + struct entry *item, *tmp; + size_t i = 0; + HASH_ITER(hh, pthis->key_exdata_map, item, tmp) { + if (item->dying) { + continue; + } + if (i >= n_exdatas) { + break; + } + exdatas[i] = item->exdata; + i++; + } + return actual_len < n_exdatas ? actual_len : n_exdatas; +} + +int hash_table_merge(struct hash_table *dest, struct hash_table *src) { + struct entry *item_src, *tmp; + struct entry *item_dst; + HASH_ITER(hh, src->key_exdata_map, item_src, tmp) { + if (item_src->dying) { + continue; + } + + HASH_FIND(hh, dest->key_exdata_map, item_src->key, item_src->key_len, item_dst); + if (item_dst != NULL && !item_dst->dying) { + dest->merge_fn(item_dst->exdata, item_src->exdata); + continue; + } + + if (dest->current_cell_num >= dest->max_cell_num) { + continue; // cannot add more cells + } + + if (item_dst == NULL) { + item_dst = calloc(1, sizeof(struct entry)); + item_dst->key = my_keydup(item_src->key, item_src->key_len); + item_dst->key_len = item_src->key_len; + item_dst->dying = false; + item_dst->exdata = dest->copy_fn(item_src->exdata); + HASH_ADD_KEYPTR(hh, dest->key_exdata_map, item_dst->key, item_dst->key_len, item_dst); + dest->current_cell_num++; + } else { + assert(item_dst->dying); + item_dst->dying = false; + dest->merge_fn(item_dst->exdata, item_src->exdata); //item_dst->exdata should be empty, but just merge to it. + dest->current_cell_num++; + } + } + return 0; +} + +struct hash_table *hash_table_copy(const struct hash_table *src) { + struct hash_table *pthis = calloc(1, sizeof(struct hash_table)); + pthis->max_cell_num = src->max_cell_num; + pthis->current_cell_num = src->current_cell_num; + pthis->new_fn = src->new_fn; + pthis->free_fn = src->free_fn; + pthis->merge_fn = src->merge_fn; + pthis->reset_fn = src->reset_fn; + pthis->copy_fn = src->copy_fn; + + struct entry *item, *tmp; + HASH_ITER(hh, src->key_exdata_map, item, tmp) { + if (item->dying) { + continue; + } + struct entry *new_item = calloc(1, sizeof(struct entry)); + new_item->key = my_keydup(item->key, item->key_len); + new_item->key_len = item->key_len; + new_item->exdata = pthis->copy_fn(item->exdata); + new_item->dying = false; + HASH_ADD_KEYPTR(hh, pthis->key_exdata_map, new_item->key, new_item->key_len, new_item); + } + return pthis; +} |
