123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- // Copyright: SPDX-License-Identifier: GPL-3.0-only
- #include "c_rhash_internal.h"
- #include <stdlib.h>
- #include <string.h>
- #ifdef DEBUG_VERBOSE
- #include <stdio.h>
- #endif
- #define c_rmalloc(...) malloc(__VA_ARGS__)
- #define c_rcalloc(...) calloc(__VA_ARGS__)
- #define c_rfree(...) free(__VA_ARGS__)
- static inline uint32_t simple_hash(const char *name) {
- unsigned char *s = (unsigned char *) name;
- uint32_t hval = 0x811c9dc5;
- while (*s) {
- hval *= 16777619;
- hval ^= (uint32_t) *s++;
- }
- return hval;
- }
- c_rhash c_rhash_new(size_t bin_count) {
- if (!bin_count)
- bin_count = 1000;
- c_rhash hash = c_rcalloc(1, sizeof(struct c_rhash_s) + (bin_count * sizeof(struct bin_ll*)) );
- if (hash == NULL)
- return NULL;
- hash->bin_count = bin_count;
- hash->bins = (c_rhash_bin *)((char*)hash + sizeof(struct c_rhash_s));
- return hash;
- }
- static size_t get_itemtype_len(uint8_t item_type, const void* item_data) {
- switch (item_type) {
- case ITEMTYPE_STRING:
- return strlen(item_data) + 1;
- case ITEMTYPE_UINT64:
- return sizeof(uint64_t);
- case ITEMTYPE_UINT8:
- return 1;
- case ITEMTYPE_OPAQUE_PTR:
- return sizeof(void*);
- default:
- return 0;
- }
- }
- static int compare_bin_item(struct bin_item *item, uint8_t key_type, const void *key) {
- if (item->key_type != key_type)
- return 1;
- size_t key_value_len = get_itemtype_len(key_type, key);
- if(key_type == ITEMTYPE_STRING) {
- size_t new_key_value_len = get_itemtype_len(item->key_type, item->key);
- if (new_key_value_len != key_value_len)
- return 1;
- }
- if(memcmp(item->key, key, key_value_len) == 0) {
- return 0;
- }
- return 1;
- }
- static int insert_into_bin(c_rhash_bin *bin, uint8_t key_type, const void *key, uint8_t value_type, const void *value) {
- struct bin_item *prev = NULL;
- while (*bin != NULL) {
- if (!compare_bin_item(*bin, key_type, key)) {
- #ifdef DEBUG_VERBOSE
- printf("Key already present! Updating value!\n");
- #endif
- // TODO: optimize here if the new value is of different kind compared to the old one
- // in case it is not crazily bigger we can reuse the memory and avoid malloc and free
- c_rfree((*bin)->value);
- (*bin)->value_type = value_type;
- (*bin)->value = c_rmalloc(get_itemtype_len(value_type, value));
- if ((*bin)->value == NULL)
- return 1;
- memcpy((*bin)->value, value, get_itemtype_len(value_type, value));
- return 0;
- }
- prev = *bin;
- bin = &(*bin)->next;
- }
- if (*bin == NULL)
- *bin = c_rcalloc(1, sizeof(struct bin_item));
- if (prev != NULL)
- prev->next = *bin;
- (*bin)->key_type = key_type;
- size_t len = get_itemtype_len(key_type, key);
- (*bin)->key = c_rmalloc(len);
- memcpy((*bin)->key, key, len);
- (*bin)->value_type = value_type;
- len = get_itemtype_len(value_type, value);
- (*bin)->value = c_rmalloc(len);
- memcpy((*bin)->value, value, len);
- return 0;
- }
- static inline uint32_t get_bin_idx_str(c_rhash hash, const char *key) {
- uint32_t nhash = simple_hash(key);
- return nhash % hash->bin_count;
- }
- static inline c_rhash_bin *get_binptr_by_str(c_rhash hash, const char *key) {
- return &hash->bins[get_bin_idx_str(hash, key)];
- }
- int c_rhash_insert_str_ptr(c_rhash hash, const char *key, void *value) {
- c_rhash_bin *bin = get_binptr_by_str(hash, key);
- #ifdef DEBUG_VERBOSE
- if (bin != NULL)
- printf("COLLISION. There will be more than one item in bin idx=%d\n", nhash);
- #endif
- return insert_into_bin(bin, ITEMTYPE_STRING, key, ITEMTYPE_OPAQUE_PTR, &value);
- }
- int c_rhash_insert_str_uint8(c_rhash hash, const char *key, uint8_t value) {
- c_rhash_bin *bin = get_binptr_by_str(hash, key);
- #ifdef DEBUG_VERBOSE
- if (bin != NULL)
- printf("COLLISION. There will be more than one item in bin idx=%d\n", nhash);
- #endif
- return insert_into_bin(bin, ITEMTYPE_STRING, key, ITEMTYPE_UINT8, &value);
- }
- int c_rhash_insert_uint64_ptr(c_rhash hash, uint64_t key, void *value) {
- c_rhash_bin *bin = &hash->bins[key % hash->bin_count];
- #ifdef DEBUG_VERBOSE
- if (bin != NULL)
- printf("COLLISION. There will be more than one item in bin idx=%d\n", nhash);
- #endif
- return insert_into_bin(bin, ITEMTYPE_UINT64, &key, ITEMTYPE_OPAQUE_PTR, &value);
- }
- int c_rhash_get_uint8_by_str(c_rhash hash, const char *key, uint8_t *ret_val) {
- uint32_t nhash = get_bin_idx_str(hash, key);
- struct bin_item *bin = hash->bins[nhash];
- while (bin) {
- if (bin->key_type == ITEMTYPE_STRING) {
- if (!strcmp(bin->key, key)) {
- *ret_val = *(uint8_t*)bin->value;
- return 0;
- }
- }
- bin = bin->next;
- }
- return 1;
- }
- int c_rhash_get_ptr_by_str(c_rhash hash, const char *key, void **ret_val) {
- uint32_t nhash = get_bin_idx_str(hash, key);
- struct bin_item *bin = hash->bins[nhash];
- while (bin) {
- if (bin->key_type == ITEMTYPE_STRING) {
- if (!strcmp(bin->key, key)) {
- *ret_val = *((void**)bin->value);
- return 0;
- }
- }
- bin = bin->next;
- }
- *ret_val = NULL;
- return 1;
- }
- int c_rhash_get_ptr_by_uint64(c_rhash hash, uint64_t key, void **ret_val) {
- uint32_t nhash = key % hash->bin_count;
- struct bin_item *bin = hash->bins[nhash];
- while (bin) {
- if (bin->key_type == ITEMTYPE_UINT64) {
- if (*((uint64_t *)bin->key) == key) {
- *ret_val = *((void**)bin->value);
- return 0;
- }
- }
- bin = bin->next;
- }
- *ret_val = NULL;
- return 1;
- }
- static void c_rhash_destroy_bin(c_rhash_bin bin) {
- struct bin_item *next;
- do {
- next = bin->next;
- c_rfree(bin->key);
- c_rfree(bin->value);
- c_rfree(bin);
- bin = next;
- } while (bin != NULL);
- }
- int c_rhash_iter_uint64_keys(c_rhash hash, c_rhash_iter_t *iter, uint64_t *key) {
- while (iter->bin < hash->bin_count) {
- if (iter->item != NULL)
- iter->item = iter->item->next;
- if (iter->item == NULL) {
- if (iter->initialized)
- iter->bin++;
- else
- iter->initialized = 1;
- if (iter->bin < hash->bin_count)
- iter->item = hash->bins[iter->bin];
- }
- if (iter->item != NULL && iter->item->key_type == ITEMTYPE_UINT64) {
- *key = *(uint64_t*)iter->item->key;
- return 0;
- }
- }
- return 1;
- }
- int c_rhash_iter_str_keys(c_rhash hash, c_rhash_iter_t *iter, const char **key) {
- while (iter->bin < hash->bin_count) {
- if (iter->item != NULL)
- iter->item = iter->item->next;
- if (iter->item == NULL) {
- if (iter->initialized)
- iter->bin++;
- else
- iter->initialized = 1;
- if (iter->bin < hash->bin_count)
- iter->item = hash->bins[iter->bin];
- }
- if (iter->item != NULL && iter->item->key_type == ITEMTYPE_STRING) {
- *key = (const char*)iter->item->key;
- return 0;
- }
- }
- return 1;
- }
- void c_rhash_destroy(c_rhash hash) {
- for (size_t i = 0; i < hash->bin_count; i++) {
- if (hash->bins[i] != NULL)
- c_rhash_destroy_bin(hash->bins[i]);
- }
- c_rfree(hash);
- }
|