Integrate simple hashset

This commit is contained in:
Justin Ethier 2021-01-08 13:53:40 -08:00
parent dc8c13abd3
commit c9f4d8243c
2 changed files with 247 additions and 1 deletions

View file

@ -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;
}

View file

@ -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);