From 53beab531be30e9e329a453183767ee8360b2d40 Mon Sep 17 00:00:00 2001 From: Marshall Lochbaum Date: Tue, 28 Nov 2023 11:09:32 -0500 Subject: [PATCH] =?UTF-8?q?=E2=80=A2HashMap=20key=20and=20value=20list=20c?= =?UTF-8?q?ompaction=20and=20methods=20to=20return=20those=20lists?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/builtins/search.c | 46 +++++++++++++++++++++++++++++++++++++++++-- src/builtins/sysfn.c | 15 ++++++++++---- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/builtins/search.c b/src/builtins/search.c index 2cb5081d..2eac975f 100644 --- a/src/builtins/search.c +++ b/src/builtins/search.c @@ -617,14 +617,14 @@ static const u64 hmask = ~(u32)0; usz hashmap_count(B hash) { return c(HashMap, hash)->pop; } -HashMap* hashmap_alloc(usz pop, usz sh, u64 sz) { +static HashMap* hashmap_alloc(usz pop, usz sh, u64 sz) { HashMap* map = mm_alloc(fsizeof(HashMap,a,u64,sz), t_hashmap); map->pop = pop; map->sh = sh; map->sz = sz; memset64(map->a, empty, sz); return map; } -NOINLINE HashMap* hashmap_resize(HashMap* old_map) { +static NOINLINE HashMap* hashmap_resize(HashMap* old_map) { usz sh = old_map->sh - 1; if (sh < 32) thrM("•HashMap: hash size maximum exceeded"); u64 sz = hashmap_size(sh); @@ -639,6 +639,47 @@ NOINLINE HashMap* hashmap_resize(HashMap* old_map) { return map->a[sz-1]==empty ? map : hashmap_resize(map); } +static NOINLINE void hashmap_compact(B* vars) { + B k = vars[0]; B* keys = harr_ptr(k); + B v = vars[1]; B* vals = harr_ptr(v); + assert(reusable(k) && reusable(v)); + usz l0 = IA(k); usz l = l0; + while (l>0 && q_N(keys[l-1])) l--; + TALLOC(usz, ind_map, l+1); + ind_map[0] = -1; // Index by i+1 to maintain empty entries + usz j = 0; // Number of entries seen + for (usz i=0; i 0) { + HashMap* map = c(HashMap, vars[2]); + assert(j == map->pop); + u64 sz = map->sz; + u64* hp = map->a; + for (u64 i=0; ipop == IA(r)) return r; + if (!reusable(vars[0])) vars[0] = taga(cpyHArr(vars[0])); + if (!reusable(vars[1])) vars[1] = taga(cpyHArr(vars[1])); + hashmap_compact(vars); + return vars[which]; +} + // Expects already defined: u64* hp, u64 sh, B* keys #define HASHMAP_FIND(X, FOUND) \ u64 h = bqn_hash(X, wy_secret); \ @@ -718,6 +759,7 @@ void hashmap_delete(B* vars, B x) { if (!reusable(vb)) { vars[1]=vb=taga(cpyHArr(vb)); } usz p = --(map->pop); dec(keys[i]); keys[i]=bi_N; B* s = harr_ptr(vb)+i; dec(*s); *s=bi_N; + if (p==0 || p+32 < IA(kb)/2) hashmap_compact(vars); return; ) thrM("(hashmap).Delete: key not found"); diff --git a/src/builtins/sysfn.c b/src/builtins/sysfn.c index 836e0b68..c43e3702 100644 --- a/src/builtins/sysfn.c +++ b/src/builtins/sysfn.c @@ -713,26 +713,31 @@ static B hashmap_hasName; static NFnDesc* hashmap_hasDesc; static B hashmap_setName; static NFnDesc* hashmap_setDesc; static B hashmap_deleteName; static NFnDesc* hashmap_deleteDesc; static B hashmap_countName; static NFnDesc* hashmap_countDesc; +static B hashmap_keysName; static NFnDesc* hashmap_keysDesc; +static B hashmap_valuesName; static NFnDesc* hashmap_valuesDesc; // Hash object handling defined in search.c extern B hashmap_build(B keys, usz n); extern B hashmap_lookup(B* vars, B w, B x); extern void hashmap_set(B* vars, B w, B x); extern void hashmap_delete(B* vars, B x); extern usz hashmap_count(B hash); +extern B hashmap_keys_or_vals(B* vars, usz which); #define VARS c(NS,nfn_objU(t))->sc->vars B hashmap_get_c1(B t, B x ) { return hashmap_lookup(VARS, bi_N, x); } B hashmap_get_c2(B t, B w, B x) { return hashmap_lookup(VARS, w, x); } B hashmap_set_c2(B t, B w, B x) { hashmap_set(VARS, w, x); return inc(nfn_objU(t)); } B hashmap_delete_c1(B t, B x ) { hashmap_delete(VARS, x); return inc(nfn_objU(t)); } -B hashmap_count_c1(B t, B x) { dec(x); return m_usz(hashmap_count(VARS[2])); } B hashmap_has_c1(B t, B x) { B l = hashmap_lookup(VARS, bi_noVar, x); if (l.u==bi_noVar.u) return m_f64(0); dec(l); return m_f64(1); } +B hashmap_count_c1(B t, B x) { dec(x); return m_usz(hashmap_count(VARS[2])); } +B hashmap_keys_c1 (B t, B x) { dec(x); return inc(hashmap_keys_or_vals(VARS, 0)); } +B hashmap_values_c1(B t, B x) { dec(x); return inc(hashmap_keys_or_vals(VARS, 1)); } #undef VARS static NOINLINE void hashmap_init() { - hashmap_ns = m_nnsDesc("keys", "vals", "hash", "get", "has", "set", "delete", "count"); + hashmap_ns = m_nnsDesc("keylist", "vallist", "hash", "get", "has", "set", "delete", "count", "keys", "values"); NSDesc* d = hashmap_ns->nsDesc; for (usz i = 0; i < 3; i++) d->expGIDs[i] = -1; hashmap_getName = m_c8vec_0("get"); gc_add(hashmap_getName); hashmap_getDesc = registerNFn(m_c8vec_0("(hashmap).Get"), hashmap_get_c1, hashmap_get_c2); @@ -740,6 +745,8 @@ static NOINLINE void hashmap_init() { hashmap_setName = m_c8vec_0("set"); gc_add(hashmap_setName); hashmap_setDesc = registerNFn(m_c8vec_0("(hashmap).Set"), c1_bad, hashmap_set_c2); hashmap_deleteName = m_c8vec_0("delete"); gc_add(hashmap_deleteName); hashmap_deleteDesc = registerNFn(m_c8vec_0("(hashmap).Delete"), hashmap_delete_c1, c2_bad); hashmap_countName = m_c8vec_0("count"); gc_add(hashmap_countName); hashmap_countDesc = registerNFn(m_c8vec_0("(hashmap).Count"), hashmap_count_c1, c2_bad); + hashmap_keysName = m_c8vec_0("keys"); gc_add(hashmap_keysName); hashmap_keysDesc = registerNFn(m_c8vec_0("(hashmap).Keys"), hashmap_keys_c1, c2_bad); + hashmap_valuesName = m_c8vec_0("values"); gc_add(hashmap_valuesName); hashmap_valuesDesc = registerNFn(m_c8vec_0("(hashmap).Values"), hashmap_values_c1, c2_bad); } B hashMap_c2(B t, B w, B x) { if (!isArr(w) || RNK(w)!=1 || !isArr(x) || RNK(x)!=1) thrF("•HashMap: Arguments must be lists (%H≡≢𝕨, %H≡≢𝕩)", w, x); @@ -748,9 +755,9 @@ B hashMap_c2(B t, B w, B x) { if (hashmap_ns==NULL) hashmap_init(); w = taga(toHArr(w)); x = taga(toHArr(x)); B h = hashmap_build(w, n); - B ns = m_nns(hashmap_ns, w, x, h, m_nfn(hashmap_getDesc, bi_N), m_nfn(hashmap_hasDesc, bi_N), m_nfn(hashmap_setDesc, bi_N), m_nfn(hashmap_deleteDesc, bi_N), m_nfn(hashmap_countDesc, bi_N)); + B ns = m_nns(hashmap_ns, w, x, h, m_nfn(hashmap_getDesc, bi_N), m_nfn(hashmap_hasDesc, bi_N), m_nfn(hashmap_setDesc, bi_N), m_nfn(hashmap_deleteDesc, bi_N), m_nfn(hashmap_countDesc, bi_N), m_nfn(hashmap_keysDesc, bi_N), m_nfn(hashmap_valuesDesc, bi_N)); Scope* sc = c(NS,ns)->sc; - for (usz i = 3; i < 8; i++) nfn_swapObj(sc->vars[i], incG(ns)); + for (usz i = 3; i < 10; i++) nfn_swapObj(sc->vars[i], incG(ns)); return ns; }