From f22c7c1a73e077e013c9dc17416ff585dba2ddd5 Mon Sep 17 00:00:00 2001 From: cannoli-fruit Date: Wed, 15 Jul 2026 13:59:45 -0400 Subject: [PATCH] Implemented hashmap deletion with tombstones --- examples/hm_del.c | 29 ++++++++ examples/hm_fill.c | 7 +- lazy.h | 169 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 169 insertions(+), 36 deletions(-) create mode 100644 examples/hm_del.c diff --git a/examples/hm_del.c b/examples/hm_del.c new file mode 100644 index 0000000..e4c753c --- /dev/null +++ b/examples/hm_del.c @@ -0,0 +1,29 @@ +#include +#define LAZY_IMPL +#include "../lazy.h" + +void print_hm_idx(void *hm, size_t k) { + typedef Lz_HM(size_t, size_t) HM; + HM map = *(HM*)hm; + if (lz_hm_exists(map,k)) { + printf("hm[%zu] = %zu\n", k, lz_hm_get(map,k)); + } else { + printf("hm[%zu] = \n", k); + } +} + +int main() { + Lz_HM(size_t, size_t) hm; + lz_hm_init(hm); + for (size_t i = 0; i < 16; ++i) { + lz_hm_add(hm, i, 2*i); + } + + for (size_t i = 4; i < 12; ++i) { + lz_hm_remove(hm, i); + } + + for (size_t i = 0; i < 16; ++i) { + print_hm_idx(&hm, i); + } +} diff --git a/examples/hm_fill.c b/examples/hm_fill.c index b56c4fe..0464ff5 100644 --- a/examples/hm_fill.c +++ b/examples/hm_fill.c @@ -5,11 +5,12 @@ int main() { Lz_HM(size_t,size_t) hm; lz_hm_init(hm); - for (size_t i = 0; i < 384; ++i) { + size_t cnt = 384; + for (size_t i = 0; i < cnt; ++i) { lz_hm_add(hm, i, 2*i); } - for (size_t i = 0; i < 384; ++i) { - printf("hm[%zu] = %zu\n", i, lz_hm_get(hm,i)); + for (size_t i = 0; i < cnt; ++i) { + printf("hm[%zu] = %zu\n", i, lz_hm_get(hm, i)); } } diff --git a/lazy.h b/lazy.h index b12509d..61ec9c3 100644 --- a/lazy.h +++ b/lazy.h @@ -20,20 +20,26 @@ typedef struct { } Lz_Slc; #endif -void lz_trim_left_typ(Lz_Slc *src, int (*classfunc)(int)); -void lz_trim_right_typ(Lz_Slc *src, int (*classfunc)(int)); -void lz_trim_typ(Lz_Slc *src, int (*classfunc)(int)); -void lz_drop_left(Lz_Slc *src, size_t n); -void lz_drop_right(Lz_Slc *src, size_t n); -void lz_split_slc(Lz_Slc *src, char delim, Lz_Slc *dst); -void lz_split_slc_typ(Lz_Slc *src, int (*classfunc)(int), Lz_Slc *dst); +void lz_slc_trim_left_typ(Lz_Slc *src, int (*classfunc)(int)); +void lz_slc_trim_right_typ(Lz_Slc *src, int (*classfunc)(int)); +void lz_slc_trim_typ(Lz_Slc *src, int (*classfunc)(int)); +void lz_slc_drop_left(Lz_Slc *src, size_t n); +void lz_slc_drop_right(Lz_Slc *src, size_t n); +void lz_slc_split(Lz_Slc *src, char delim, Lz_Slc *dst); +void lz_slc_split_typ(Lz_Slc *src, int (*classfunc)(int), Lz_Slc *dst); size_t lz_hm_hash_raw_bytes(size_t cap, void *key, size_t k_s); -size_t lz_hm_hash_void_get(size_t cap, _Bool *exists, void *key, - void *keys, size_t k_s); -size_t lz_hm_hash_void_set(size_t cap, _Bool *exists, void* key, size_t k_s); +size_t lz_hm_hash_void_get(size_t cap, _Bool *exists, _Bool *tombstones, + void *key, void *keys, size_t k_s); +size_t lz_hm_hash_void_set(size_t cap, _Bool *exists, + _Bool *tombstones, void* key, size_t k_s); Lz_Slc lz_cstr_to_slc(char *dat); char *lz_cstr_dup(const char *s); +double lz_slc_atof(Lz_Slc *src); +int lz_slc_atoi(Lz_Slc *src); +long lz_slc_atol(Lz_Slc *src); +long long lz_slc_atoll(Lz_Slc *src); + #ifndef Lz_DA #define Lz_DA(T) struct {T *data; size_t cnt; size_t cap; } #endif @@ -129,6 +135,12 @@ char *lz_cstr_dup(const char *s); typedef Lz_DA(char) Lz_SB; #endif +double lz_sb_atof(Lz_SB *src); +int lz_sb_atoi(Lz_SB *src); +long lz_sb_atol(Lz_SB *src); +long long lz_sb_atoll(Lz_SB *src); + + #ifndef Lz_HM #define Lz_HM(K_t, V_t) struct {\ size_t cap;\ @@ -138,6 +150,7 @@ typedef Lz_DA(char) Lz_SB; K_t tmpkey;\ V_t tmpval;\ _Bool *exists;\ + _Bool *tombstones;\ K_t *keys;\ V_t *vals;\ } @@ -149,21 +162,24 @@ typedef Lz_DA(char) Lz_SB; (hm).cnt = 0;\ (hm).keys = malloc((hm).cap*sizeof(*(hm).keys));\ (hm).vals = malloc((hm).cap*sizeof(*(hm).vals));\ - (hm).exists = malloc((hm).cap*sizeof(_Bool));\ + (hm).exists = calloc((hm).cap,sizeof(_Bool));\ + (hm).tombstones = calloc((hm).cap,sizeof(_Bool));\ } while (0) #endif #ifndef lz_hm_hash_set #define lz_hm_hash_set(hm, k) (\ (hm).tmpkey = k,\ - lz_hm_hash_void_set((hm).cap, (hm).exists, &(hm).tmpkey, sizeof(*(hm).keys))\ + lz_hm_hash_void_set((hm).cap, (hm).exists, (hm).tombstones,\ + &(hm).tmpkey, sizeof(*(hm).keys))\ ) #endif #ifndef lz_hm_hash_get #define lz_hm_hash_get(hm, k) (\ (hm).tmpkey = k,\ - lz_hm_hash_void_get((hm).cap, (hm).exists, &(hm).tmpkey, (hm).keys, sizeof(*(hm).keys))\ + lz_hm_hash_void_get((hm).cap, (hm).exists, (hm).tombstones,\ + &(hm).tmpkey, (hm).keys, sizeof(*(hm).keys))\ ) #endif @@ -187,16 +203,21 @@ typedef Lz_DA(char) Lz_SB; void *newkeys = malloc(newcap*sizeof(*(hm).keys));\ void *newvals = malloc(newcap*sizeof(*(hm).vals));\ _Bool *newexists = calloc(newcap, sizeof(_Bool));\ + _Bool *newtombstones = calloc(newcap, sizeof(_Bool));\ + printf("Grow\n");\ \ for (size_t i = 0; i < (hm).cap; ++i) {\ if ((hm).exists[i]) {\ size_t newhash = lz_hm_hash_void_set(newcap, newexists,\ - &(hm).keys[i], sizeof(*(hm).keys));\ + newtombstones,\ + &(hm).keys[i],\ + sizeof(*(hm).keys));\ memcpy(newvals + sizeof(*(hm).vals)*newhash,\ &(hm).vals[i], sizeof(*(hm).vals));\ memcpy(newkeys + sizeof(*(hm).keys)*newhash,\ &(hm).keys[i], sizeof(*(hm).keys));\ newexists[newhash] = 1;\ + newtombstones[newhash] = 0;\ }\ }\ free((hm).vals);\ @@ -205,6 +226,8 @@ typedef Lz_DA(char) Lz_SB; (hm).keys = newkeys;\ free((hm).exists);\ (hm).exists = newexists;\ + free((hm).tombstones);\ + (hm).tombstones = newtombstones;\ (hm).cap = newcap;\ } while(0) #endif @@ -216,14 +239,23 @@ typedef Lz_DA(char) Lz_SB; (hm).vals[idx] = v;\ ++(hm).cnt;\ (hm).exists[idx] = 1;\ + (hm).tombstones[idx] = 0;\ if (4*(hm).cnt > 3*(hm).cap) {\ lz_hm_grow(hm);\ }\ } while(0) #endif -#ifdef LAZY_IMPL +#ifndef lz_hm_remove +#define lz_hm_remove(hm, k) do {\ + size_t idx = lz_hm_hash_get(hm,k);\ + (hm).tombstones[idx] = 1;\ + (hm).exists[idx] = 0;\ +} while(0) +#endif +#ifdef LAZY_IMPL +#undef LAZY_IMPL size_t lz_hm_hash_raw_bytes(size_t cap, void *key, size_t k_s) { size_t hash = 0; for (size_t i = 0; i < k_s; ++i) { @@ -234,32 +266,35 @@ size_t lz_hm_hash_raw_bytes(size_t cap, void *key, size_t k_s) { return hash % cap; } -size_t lz_hm_hash_void_get(size_t cap, _Bool *exists, void *key, - void *keys, size_t k_s) { +size_t lz_hm_hash_void_get(size_t cap, _Bool *exists, _Bool *tombstones, + void *key, void *keys, size_t k_s) { size_t hash = lz_hm_hash_raw_bytes(cap, key, k_s); for (size_t i = 0; i < cap; ++i) { size_t localhash = (hash + i) % cap; int diff = memcmp(keys+k_s*localhash, key, k_s); - if (diff == 0) { + size_t tombstone = tombstones[localhash]; + if (diff == 0 && !tombstone) { return localhash; } size_t istaken = exists[localhash]; - if (!istaken) { + if (!istaken && !tombstone) { return (size_t)-1; } } return (size_t)-1; } -size_t lz_hm_hash_void_set(size_t cap, _Bool *exists, void* key, size_t k_s) { +size_t lz_hm_hash_void_set(size_t cap, _Bool *exists, + _Bool *tombstones, void* key, size_t k_s) { size_t hash = lz_hm_hash_raw_bytes(cap, key, k_s); for (size_t i = 0; i < cap; ++i) { size_t localhash = (hash + i) % cap; + _Bool tombstone = tombstones[localhash]; _Bool istaken = exists[localhash]; - if (!istaken) return localhash; + if (!istaken || tombstone) return localhash; } return (size_t)-1; } @@ -274,35 +309,35 @@ char *lz_cstr_dup(const char *s) { memcpy(p, s, n+1); return p; } -void lz_drop_left(Lz_Slc *src, size_t n) { +void lz_slc_drop_left(Lz_Slc *src, size_t n) { if (src->cnt < n) n = src->cnt; src->data += n; src->cnt -= n; } -void lz_drop_right(Lz_Slc *src, size_t n) { +void lz_slc_drop_right(Lz_Slc *src, size_t n) { if (src->cnt < n) n = src->cnt; src->cnt -= n; } -void lz_trim_left_typ(Lz_Slc *src, int (*classfunc)(int)) { +void lz_slc_trim_left_typ(Lz_Slc *src, int (*classfunc)(int)) { while (classfunc(src->data[0])) { - lz_drop_left(src, 1); + lz_slc_drop_left(src, 1); } } -void lz_trim_right_typ(Lz_Slc *src, int (*classfunc)(int)) { +void lz_slc_trim_right_typ(Lz_Slc *src, int (*classfunc)(int)) { while (classfunc(src->data[src->cnt-1])) { - lz_drop_right(src, 1); + lz_slc_drop_right(src, 1); } } -void lz_trim_typ(Lz_Slc *src, int (*classfunc)(int)) { - lz_trim_left_typ(src, classfunc); - lz_trim_right_typ(src, classfunc); +void lz_slc_trim_typ(Lz_Slc *src, int (*classfunc)(int)) { + lz_slc_trim_left_typ(src, classfunc); + lz_slc_trim_right_typ(src, classfunc); } -void lz_split_slc(Lz_Slc *src, char delim, Lz_Slc *dst) { +void lz_slc_split(Lz_Slc *src, char delim, Lz_Slc *dst) { size_t i = 0; while (i < src->cnt && src->data[i] != delim) { ++i; @@ -317,7 +352,7 @@ void lz_split_slc(Lz_Slc *src, char delim, Lz_Slc *dst) { } } -void lz_split_slc_typ(Lz_Slc *src, int (*classfunc)(int), Lz_Slc *dst) { +void lz_slc_split_typ(Lz_Slc *src, int (*classfunc)(int), Lz_Slc *dst) { size_t i = 0; while (i < src->cnt && !classfunc(src->data[i])) { ++i; @@ -330,7 +365,7 @@ void lz_split_slc_typ(Lz_Slc *src, int (*classfunc)(int), Lz_Slc *dst) { } else { src->cnt = 0; } - lz_trim_left_typ(src, classfunc); + lz_slc_trim_left_typ(src, classfunc); } Lz_SB lz_sb_from_cstr(const char *dat) { @@ -348,4 +383,72 @@ Lz_Slc lz_cstr_to_slc(char *dat) { out.cnt = strlen(dat); return out; } + +double lz_slc_atof(Lz_Slc *src) { + char *cstr = malloc(src->cnt+1); + memcpy(cstr, src->data, src->cnt); + cstr[src->cnt] = 0; + double x = atof(cstr); + free(cstr); + return x; +} +int lz_slc_atoi(Lz_Slc *src) { + char *cstr = malloc(src->cnt+1); + memcpy(cstr, src->data, src->cnt); + cstr[src->cnt] = 0; + int x = atoi(cstr); + free(cstr); + return x; +} +long lz_slc_atol(Lz_Slc *src) { + char *cstr = malloc(src->cnt+1); + memcpy(cstr, src->data, src->cnt); + cstr[src->cnt] = 0; + int x = atol(cstr); + free(cstr); + return x; +} +long long lz_slc_atoll(Lz_Slc *src) { + char *cstr = malloc(src->cnt+1); + memcpy(cstr, src->data, src->cnt); + cstr[src->cnt] = 0; + int x = atoll(cstr); + free(cstr); + return x; +} + + + +double lz_sb_atof(Lz_SB *src) { + char *cstr = malloc(src->cnt+1); + memcpy(cstr, src->data, src->cnt); + cstr[src->cnt] = 0; + double x = atof(cstr); + free(cstr); + return x; +} +int lz_sb_atoi(Lz_SB *src) { + char *cstr = malloc(src->cnt+1); + memcpy(cstr, src->data, src->cnt); + cstr[src->cnt] = 0; + int x = atoi(cstr); + free(cstr); + return x; +} +long lz_sb_atol(Lz_SB *src) { + char *cstr = malloc(src->cnt+1); + memcpy(cstr, src->data, src->cnt); + cstr[src->cnt] = 0; + int x = atol(cstr); + free(cstr); + return x; +} +long long lz_sb_atoll(Lz_SB *src) { + char *cstr = malloc(src->cnt+1); + memcpy(cstr, src->data, src->cnt); + cstr[src->cnt] = 0; + int x = atoll(cstr); + free(cstr); + return x; +} #endif