From c9f4d8243cf925cbd305ab469bae0bfb12984973 Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 8 Jan 2021 13:53:40 -0800 Subject: [PATCH] Integrate simple hashset --- ck-polyfill.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++ ck-polyfill.h | 70 +++++++++++++++++++- 2 files changed, 247 insertions(+), 1 deletion(-) diff --git a/ck-polyfill.c b/ck-polyfill.c index 55acadfc..16c3a0a5 100644 --- a/ck-polyfill.c +++ b/ck-polyfill.c @@ -191,3 +191,181 @@ ck_pr_load_8(const uint8_t *target) pthread_mutex_unlock(&glock); return result; } + + +// Simple hashset + +static const size_t prime_1 = 73; +static const size_t prime_2 = 5009; + +struct simple_hashset_item_st { + size_t hash; + char* item; +}; + +struct simple_hashset_st { + size_t nbits; + size_t mask; + + size_t capacity; + struct simple_hashset_item_st *items; + size_t nitems; + size_t n_deleted_items; + + hash_func_t hash_func; +}; + +size_t hash_function(char* p, size_t len) +{ + size_t hash = 0; + for (; *p; ++p) + hash ^= *p + 0x9e3779b9 + (hash << 6) + (hash >> 2); + return hash; +} + +simple_hashset_t simple_hashset_create() +{ + simple_hashset_t set = (simple_hashset_t)calloc(1, sizeof(struct simple_hashset_st)); + + if (set == NULL) { + return NULL; + } + + set->hash_func = hash_function; + set->nbits = 3; + set->capacity = (size_t)(1 << set->nbits); + set->mask = set->capacity - 1; + set->items = (struct simple_hashset_item_st*)calloc(set->capacity, sizeof(struct simple_hashset_item_st)); + if (set->items == NULL) { + simple_hashset_destroy(set); + return NULL; + } + set->nitems = 0; + set->n_deleted_items = 0; + return set; +} + +void simple_hashset_clean(simple_hashset_t set) +{ + set->nitems = 0; + set->n_deleted_items = 0; + + size_t i = 0; + while(i != set->capacity) + set->items[i++].hash = 0; +} + +size_t simple_hashset_num_items(simple_hashset_t set) +{ + return set->nitems; +} + +void simple_hashset_destroy(simple_hashset_t set) +{ + if (set) { + free(set->items); + } + free(set); +} + +void simple_hashset_set_hash_function(simple_hashset_t set, hash_func_t func) +{ + set->hash_func = func; +} + +static int simple_hashset_add_member(simple_hashset_t set, char* key, size_t hash) +{ + size_t index; + + if (hash < 2) { + return -1; + } + + index = set->mask & (prime_1 * hash); + + while (set->items[index].hash != 0 && set->items[index].hash != 1) { + if (set->items[index].hash == hash) { + return 0; + } + else { + /* search free slot */ + index = set->mask & (index + prime_2); + } + } + + ++set->nitems; + if (set->items[index].hash == 1) { + --set->n_deleted_items; + } + + set->items[index].hash = hash; + set->items[index].item = key; + return 1; +} + +static void set_maybe_rehash(simple_hashset_t set) +{ + struct simple_hashset_item_st *old_items; + size_t old_capacity, index; + + + if (set->nitems + set->n_deleted_items >= (double)set->capacity * 0.85) { + old_items = set->items; + old_capacity = set->capacity; + ++set->nbits; + set->capacity = (size_t)(1 << set->nbits); + set->mask = set->capacity - 1; + set->items = (struct simple_hashset_item_st*)calloc(set->capacity, sizeof(struct simple_hashset_item_st)); + set->nitems = 0; + set->n_deleted_items = 0; + //assert(set->items); + for (index = 0; index < old_capacity; ++index) { + simple_hashset_add_member(set, old_items[index].item, old_items[index].hash); + } + free(old_items); + } +} + +int simple_hashset_add(simple_hashset_t set, char* key, size_t key_len) +{ + size_t hash = set->hash_func(key, key_len); + int rv = simple_hashset_add_member(set, key, hash); + set_maybe_rehash(set); + return rv; +} + +int simple_hashset_remove(simple_hashset_t set, char* key, size_t key_len) +{ + size_t hash = set->hash_func(key, key_len); + size_t index = set->mask & (prime_1 * hash); + + while (set->items[index].hash != 0) { + if (set->items[index].hash == hash) { + set->items[index].hash = 1; + --set->nitems; + ++set->n_deleted_items; + return 1; + } else { + index = set->mask & (index + prime_2); + } + } + return 0; +} + +int simple_hashset_is_member(simple_hashset_t set, char* key, size_t key_len) +{ + size_t hash = set->hash_func(key, key_len); + size_t index = set->mask & (prime_1 * hash); + + while (set->items[index].hash != 0) { + if (set->items[index].hash == hash) { + return 1; + } else { + index = set->mask & (index + prime_2); + } + } + return 0; +} + + + diff --git a/ck-polyfill.h b/ck-polyfill.h index 0884561c..58a33980 100644 --- a/ck-polyfill.h +++ b/ck-polyfill.h @@ -8,6 +8,59 @@ void ck_polyfill_init(); +/////////////////////////////////////////////////////////////////////////////// +// Simple hashset (hashset with string support) + /* hash function */ + typedef size_t(*hash_func_t)(char*, size_t); + + struct simple_hashset_st; + typedef struct simple_hashset_st *simple_hashset_t; + + struct hashmap_st; + typedef struct hashmap_st *hashmap_t; + + /* + * HASHSET FUNCTIONS + */ + + /* create hashset instance */ + simple_hashset_t simple_hashset_create(void); + + /* destroy hashset instance */ + void simple_hashset_destroy(simple_hashset_t set); + + /* set hash function */ + void simple_hashset_set_hash_function(simple_hashset_t set, hash_func_t func); + + /* Just clear data but do not create anything*/ + void simple_hashset_clean(simple_hashset_t set); + + /* total items count */ + size_t simple_hashset_num_items(simple_hashset_t set); + + /* add item into the hashset. + * + * @note 0 and 1 is special values, meaning nil and deleted items. the + * function will return -1 indicating error. + * + * returns zero if the item already in the set and non-zero otherwise + */ + int simple_hashset_add(simple_hashset_t set, char* key, size_t key_len); + + /* remove item from the hashset + * + * returns non-zero if the item was removed and zero if the item wasn't + * exist + */ + int simple_hashset_remove(simple_hashset_t set, char *key, size_t key_len); + + /* check if existence of the item + * + * returns non-zero if the item exists and zero otherwise + */ + int simple_hashset_is_member(simple_hashset_t set, char* key, size_t key_len); + +/////////////////////////////////////////////////////////////////////////////// // CK Hashset section #define CK_HS_MODE_OBJECT 0 @@ -16,8 +69,20 @@ void ck_polyfill_init(); struct ck_hs { // TODO }; + typedef struct ck_hs ck_hs_t; +/* + * Hash callback function. + */ +typedef unsigned long ck_hs_hash_cb_t(const void *, unsigned long); + +/* + * Returns pointer to object if objects are equivalent. + */ +typedef bool ck_hs_compare_cb_t(const void *, const void *); + +/* CK_HS_HASH(hs, hs_hash, value); bool ck_hs_init(ck_hs_t *, unsigned int, ck_hs_hash_cb_t *, @@ -25,6 +90,7 @@ bool ck_hs_init(ck_hs_t *, unsigned int, ck_hs_hash_cb_t *, void *ck_hs_get(ck_hs_t *, unsigned long, const void *); bool ck_hs_put(ck_hs_t *, unsigned long, const void *); +*/ /* struct ck_hs { @@ -40,6 +106,7 @@ typedef struct ck_hs ck_hs_t; */ +/////////////////////////////////////////////////////////////////////////////// // CK Array section struct ck_array { pthread_mutex_t lock; @@ -136,7 +203,8 @@ ck_array_commit(ck_array_t *array); _ck_i < tmpc; \ _ck_i++, (*b) = tmp[_ck_i]) -// CAS section +/////////////////////////////////////////////////////////////////////////////// +// CK PR section bool ck_pr_cas_ptr(void *target, void *old_value, void *new_value);