Skip to content

Commit

Permalink
Add HtSU hashtable
Browse files Browse the repository at this point in the history
  • Loading branch information
Luc Tielen committed Aug 10, 2023
1 parent ca9d06e commit 97ff9f5
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 1 deletion.
37 changes: 37 additions & 0 deletions include/sdb/ht_su.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef SDB_HT_SU_H
#define SDB_HT_SU_H

/*
* This header provides a hashtable HtSU that has char* as key and ut64 as
* value (a "stringmap"). The hashtable takes ownership of the keys by making a
* copy of the key, and will free the pointers once they are removed from the
* hashtable.
*/

#include "sdb/types.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef uint64_t ut64;

typedef struct HtSU_t HtSU;
typedef struct HtSU_entry_t HtSU_Entry;

typedef bool (*HtSUForEachCallback)(void *user, const char *key, const ut64 value);

SDB_API HtSU* ht_su_new0(void);
SDB_API void ht_su_free(HtSU *hm);
SDB_API bool ht_su_insert(HtSU *hm, const char *key, ut64 value);
SDB_API bool ht_su_update(HtSU *hm, const char *key, ut64 value);
SDB_API bool ht_su_update_key(HtSU *hm, const char *old_key, const char *new_key);
SDB_API bool ht_su_delete(HtSU *hm, const char *key);
SDB_API ut64 ht_su_find(HtSU *hm, const char *key, bool* found);
SDB_API void ht_su_foreach(HtSU *hm, HtSUForEachCallback cb, void *user);

#ifdef __cplusplus
}
#endif

#endif
4 changes: 3 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ libsdb_sources = [
'src/ht_up.c',
'src/ht_pp.c',
'src/ht_pu.c',
'src/ht_su.c',
'src/journal.c',
'src/json.c',
'src/lock.c',
Expand Down Expand Up @@ -112,7 +113,8 @@ if not meson.is_subproject()
'include/sdb/ht_pp.h',
'include/sdb/ht_up.h',
'include/sdb/ht_uu.h',
'include/sdb/ht_up.h',
'include/sdb/ht_pu.h',
'include/sdb/ht_su.h',
'include/sdb/ls.h',
'include/sdb/sdb.h',
'include/sdb/ht.h',
Expand Down
176 changes: 176 additions & 0 deletions src/ht_su.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/* sdb - MIT - Copyright 2018-2023 - ret2libc, pancake, luc-tielen */

#include <stdint.h>
#include "sdb/ht_su.h"
#include "sdb/heap.h"
#include "sdb/sdb.h"
#include "../../../libr/include/cwisstable.h" // XXX use cwisstable from sdb itself

#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtypedef-redefinition"
#endif

static inline void string_copy(void *dst, const void *src);
static inline void string_dtor(void *val);
static inline size_t string_hash(const void *val);
static inline bool string_eq(const void *a, const void *b);

CWISS_DECLARE_FLAT_HASHMAP(HtSU, char*, float, string_copy, string_dtor, string_hash, string_eq);

static inline void string_copy(void *dst_, const void *src_) {
const HtSU_Entry *src = src_;
HtSU_Entry *dst = dst_;

const size_t len = strlen (src->key);
dst->key = sdb_gh_malloc (len + 1);
dst->val = src->val;
memcpy (dst->key, src->key, len + 1);
}

static inline void string_dtor(void *val) {
char *str = *(char**)val;
sdb_gh_free (str);
}

static inline size_t string_hash(const void *val) {
const char *str = *(const char *const *)val;
const size_t len = strlen (str);
CWISS_FxHash_State state = 0;
CWISS_FxHash_Write (&state, str, len);
return state;
}

static inline bool string_eq(const void *a, const void *b) {
const char *ap = *(const char* const *)a;
const char *bp = *(const char* const *)b;
return strcmp (ap, bp) == 0;
}

#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif

SDB_API HtSU* ht_su_new0(void) {
HtSU *hm = sdb_gh_calloc (1, sizeof (HtSU));
if (hm) {
*hm = HtSU_new (0);
}
return hm;
}

SDB_API void ht_su_free(HtSU *hm) {
if (hm) {
HtSU_destroy (hm);
sdb_gh_free (hm);
}
}

SDB_API bool ht_su_insert(HtSU *hm, const char *key, ut64 value) {
assert (hm && key);

char *key_copy = sdb_strdup (key);
if (!key_copy) {
return false;
}

HtSU_Entry entry = { .key = key_copy, .val = value };
HtSU_Insert result = HtSU_insert (hm, &entry);
if (!result.inserted) {
sdb_gh_free (key_copy);
return false;
}
return true;
}

SDB_API bool ht_su_update(HtSU *hm, const char *key, ut64 value) {
assert (hm && key);

char *key_copy = sdb_strdup (key);
if (!key_copy) {
return false;
}

HtSU_Entry entry = { .key = key_copy, .val = value };
HtSU_Insert insert_result = HtSU_insert (hm, &entry);
if (!insert_result.inserted) {
sdb_gh_free (key_copy);

HtSU_Entry *existing_entry = HtSU_Iter_get (&insert_result.iter);
existing_entry->val = value;
}

return true;
}

// Update the key of an element in the hashtable
SDB_API bool ht_su_update_key(HtSU *hm, const char *old_key, const char *new_key) {
assert (hm && old_key && new_key);

HtSU_Iter iter = HtSU_find (hm, (const HtSU_Key*) &old_key);
HtSU_Entry *entry = HtSU_Iter_get (&iter);
if (!entry) {
return false;
}

// Do nothing if keys are the same
if (SDB_UNLIKELY (strcmp (old_key, new_key) == 0)) {
return true;
}

char *key_copy = sdb_strdup (new_key);
if (!key_copy) {
return false;
}

// First try inserting the new key
HtSU_Entry new_entry = { .key = key_copy, .val = entry->val };
HtSU_Insert result = HtSU_insert (hm, &new_entry);
if (!result.inserted) {
sdb_gh_free (key_copy);
return false;
}

// Then remove entry for the old key
HtSU_erase_at (iter);
return true;
}

SDB_API bool ht_su_delete(HtSU *hm, const char *key) {
assert (hm && key);
return HtSU_erase (hm, (const HtSU_Key*) &key);
}

SDB_API ut64 ht_su_find(HtSU *hm, const char *key, bool* found) {
assert (hm && key);

if (found) {
*found = false;
}

HtSU_Iter iter = HtSU_find (hm, (const HtSU_Key*) &key);
HtSU_Entry *entry = HtSU_Iter_get (&iter);
if (!entry) {
return 0;
}

if (found) {
*found = true;
}
return entry->val;
}

// Iterates over all elements in the hashtable, calling the cb function on each Kv.
// If the cb returns false, the iteration is stopped.
// cb should not modify the hashtable.
SDB_API void ht_su_foreach(HtSU *hm, HtSUForEachCallback cb, void *user) {
assert (hm);
HtSU_CIter iter;
const HtSU_Entry *entry;

for (iter = HtSU_citer (hm); (entry = HtSU_CIter_get (&iter)) != NULL; HtSU_CIter_next (&iter)) {
if (!cb (user, entry->key, entry->val)) {
return;
}
}
}

0 comments on commit 97ff9f5

Please sign in to comment.