•HashMap count and set functions
This commit is contained in:
parent
016e428db6
commit
ce9f460e2c
@ -611,48 +611,93 @@ typedef struct HashMap {
|
|||||||
u64 sz; // count of allocated entries, a power of 2
|
u64 sz; // count of allocated entries, a power of 2
|
||||||
u64 a[];
|
u64 a[];
|
||||||
} HashMap;
|
} HashMap;
|
||||||
|
static u64 hashmap_size(usz sh) { return ((u64)1 << (64-sh)) + 32; }
|
||||||
|
static const u64 empty = ~(u64)0;
|
||||||
|
static const u64 hmask = ~(u32)0;
|
||||||
|
|
||||||
B hashmap_build(B keys, usz n) {
|
usz hashmap_count(B hash) { return c(HashMap, hash)->pop; }
|
||||||
usz ext = 32;
|
|
||||||
|
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) {
|
||||||
|
usz sh = old_map->sh - 1;
|
||||||
|
if (sh < 32) thrM("•HashMap: hash size maximum exceeded");
|
||||||
|
u64 sz = hashmap_size(sh);
|
||||||
|
HashMap* map = hashmap_alloc(old_map->pop, sh, sz);
|
||||||
|
for (u64 i=0, j=-(u64)1; i<old_map->sz; i++) {
|
||||||
|
u64 h = old_map->a[i];
|
||||||
|
if (h == empty) continue;
|
||||||
|
j++; u64 jh = h>>sh; if (j < jh) j = jh;
|
||||||
|
map->a[j] = h;
|
||||||
|
}
|
||||||
|
mm_free((Value*)old_map);
|
||||||
|
return map->a[sz-1]==empty ? map : hashmap_resize(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expects already defined: u64* hp, u64 sh, B* keys
|
||||||
|
#define HASHMAP_FIND(X, FOUND) \
|
||||||
|
u64 h = bqn_hash(X, wy_secret); \
|
||||||
|
u64 m = hmask; \
|
||||||
|
u64 v = h &~ m; \
|
||||||
|
u64 j = h >> sh; \
|
||||||
|
u64 u; while ((u=hp[j]) < v) j++; \
|
||||||
|
while (u < (v|m)) { \
|
||||||
|
usz i = u&m; \
|
||||||
|
if (equal(X, keys[i])) { FOUND } \
|
||||||
|
u = hp[++j]; \
|
||||||
|
}
|
||||||
|
// Expects usz i to be the index if new (i in FOUND is index where found)
|
||||||
|
#define HASHMAP_INSERT(X, FOUND) \
|
||||||
|
HASHMAP_FIND(X, FOUND) \
|
||||||
|
u64 je=j; while (u!=empty) { u64 s=u; je++; u=hp[je]; hp[je]=s; } \
|
||||||
|
hp[j] = v | i;
|
||||||
|
|
||||||
|
B hashmap_build(B key_arr, usz n) {
|
||||||
usz sh = CLZ(n|16)-1;
|
usz sh = CLZ(n|16)-1;
|
||||||
u64 l = (u64)1 << (64-sh);
|
u64 sz = hashmap_size(sh);
|
||||||
HashMap* map = mm_alloc(fsizeof(HashMap,a,u64,l+ext), t_hashmap);
|
HashMap* map = hashmap_alloc(n, sh, sz);
|
||||||
map->pop = n; map->sh = sh; map->sz = l;
|
|
||||||
u64* hp = map->a;
|
u64* hp = map->a;
|
||||||
B* kp = harr_ptr(keys);
|
B* keys = harr_ptr(key_arr);
|
||||||
u64 e = ~(u64)0;
|
|
||||||
u64 m = ~(u32)0;
|
|
||||||
memset64(hp, e, l+ext);
|
|
||||||
for (usz i=0; i<n; i++) {
|
for (usz i=0; i<n; i++) {
|
||||||
B key = kp[i];
|
B key = keys[i];
|
||||||
u64 h = bqn_hash(key, wy_secret);
|
HASHMAP_INSERT(key, thrM("•HashMap: 𝕨 contained duplicate keys");)
|
||||||
u64 v = (h &~ m) | i;
|
if (RARE(je == sz-1)) {
|
||||||
u64 j0 = h>>sh; u64 j = j0;
|
map=hashmap_resize(map);
|
||||||
u64 u; while ((u=hp[j]) < v) j++;
|
hp=map->a; sh=map->sh; sz=map->sz;
|
||||||
if (u < (v|m) && equal(key, kp[u&m])) thrM("•HashMap: 𝕨 contained duplicate keys");
|
}
|
||||||
u64 je=j; while (u!=e) { u64 s=u; je++; u=hp[je]; hp[je]=s; }
|
|
||||||
hp[j] = v;
|
|
||||||
}
|
}
|
||||||
return tag(map, OBJ_TAG);
|
return tag(map, OBJ_TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
B hashmap_lookup(B* vars, B w, B x) {
|
B hashmap_lookup(B* vars, B w, B x) {
|
||||||
HashMap* map = c(HashMap, vars[2]);
|
HashMap* map = c(HashMap, vars[2]);
|
||||||
u64* hp = map->a;
|
u64* hp = map->a; u64 sh = map->sh;
|
||||||
u64 h = bqn_hash(x, wy_secret);
|
B* keys = harr_ptr(vars[0]);
|
||||||
u64 m = ~(u32)0;
|
HASHMAP_FIND(x, dec(w); dec(x); return inc(harr_ptr(vars[1])[i]);)
|
||||||
u64 v = h &~ m;
|
|
||||||
u64 j = h >> map->sh;
|
|
||||||
u64 u; while ((u=hp[j]) < v) j++;
|
|
||||||
B* k = harr_ptr(vars[0]); // keys
|
|
||||||
while (u < (v|m)) {
|
|
||||||
usz i = u&m;
|
|
||||||
if (equal(x, k[i])) {
|
|
||||||
dec(x); dec(w);
|
|
||||||
return inc(harr_ptr(vars[1])[i]);
|
|
||||||
}
|
|
||||||
u = hp[++j];
|
|
||||||
}
|
|
||||||
if (q_N(w)) thrM("(hashmap).Get: key not found");
|
if (q_N(w)) thrM("(hashmap).Get: key not found");
|
||||||
dec(x); return w;
|
dec(x); return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hashmap_set(B* vars, B w, B x) {
|
||||||
|
HashMap* map = c(HashMap, vars[2]);
|
||||||
|
u64* hp = map->a; u64 sh = map->sh;
|
||||||
|
usz i = map->pop;
|
||||||
|
if (i>>(64-3-sh)>7 || hp[map->sz-1]!=empty) { // keep load <= 7/8
|
||||||
|
map=hashmap_resize(map);
|
||||||
|
vars[2] = tag(map, OBJ_TAG);
|
||||||
|
hp=map->a; sh=map->sh;
|
||||||
|
}
|
||||||
|
B* keys = harr_ptr(vars[0]);
|
||||||
|
HASHMAP_INSERT(
|
||||||
|
w,
|
||||||
|
B* s = harr_ptr(vars[1])+i; dec(*s); dec(w); *s=x; return;
|
||||||
|
)
|
||||||
|
map->pop++;
|
||||||
|
vars[0] = vec_addN(vars[0], w);
|
||||||
|
vars[1] = vec_addN(vars[1], x);
|
||||||
|
}
|
||||||
|
|||||||
@ -708,21 +708,34 @@ B currentError_c1(B t, B x) { thrM("•CurrentError: No errors as error catching
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Body* hashmap_ns;
|
static Body* hashmap_ns;
|
||||||
static B hashmap_getName; static NFnDesc* hashmap_getDesc;
|
static B hashmap_getName; static NFnDesc* hashmap_getDesc;
|
||||||
|
static B hashmap_hasName; static NFnDesc* hashmap_hasDesc;
|
||||||
|
static B hashmap_setName; static NFnDesc* hashmap_setDesc;
|
||||||
|
static B hashmap_countName; static NFnDesc* hashmap_countDesc;
|
||||||
// Hash object handling defined in search.c
|
// Hash object handling defined in search.c
|
||||||
extern B hashmap_build(B keys, usz n);
|
extern B hashmap_build(B keys, usz n);
|
||||||
extern B hashmap_lookup(B* vars, B w, B x);
|
extern B hashmap_lookup(B* vars, B w, B x);
|
||||||
B hashmap_get_c2(B t, B w, B x) {
|
extern void hashmap_set(B* vars, B w, B x);
|
||||||
return hashmap_lookup(c(NS,nfn_objU(t))->sc->vars, w, x);
|
extern usz hashmap_count(B hash);
|
||||||
}
|
#define VARS c(NS,nfn_objU(t))->sc->vars
|
||||||
B hashmap_get_c1(B t, B x) {
|
B hashmap_get_c1(B t, B x ) { return hashmap_lookup(VARS, bi_N, x); }
|
||||||
return hashmap_lookup(c(NS,nfn_objU(t))->sc->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_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);
|
||||||
}
|
}
|
||||||
|
#undef VARS
|
||||||
static NOINLINE void hashmap_init() {
|
static NOINLINE void hashmap_init() {
|
||||||
hashmap_ns = m_nnsDesc("keys", "vals", "hash", "get");
|
hashmap_ns = m_nnsDesc("keys", "vals", "hash", "get", "has", "set", "count");
|
||||||
NSDesc* d = hashmap_ns->nsDesc;
|
NSDesc* d = hashmap_ns->nsDesc;
|
||||||
for (usz i = 0; i < 3; i++) d->expGIDs[i] = -1;
|
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);
|
hashmap_getName = m_c8vec_0("get"); gc_add(hashmap_getName); hashmap_getDesc = registerNFn(m_c8vec_0("(hashmap).Get"), hashmap_get_c1, hashmap_get_c2);
|
||||||
|
hashmap_hasName = m_c8vec_0("has"); gc_add(hashmap_hasName); hashmap_hasDesc = registerNFn(m_c8vec_0("(hashmap).Has"), hashmap_has_c1, c2_bad);
|
||||||
|
hashmap_setName = m_c8vec_0("set"); gc_add(hashmap_setName); hashmap_setDesc = registerNFn(m_c8vec_0("(hashmap).Set"), c1_bad, hashmap_set_c2);
|
||||||
|
hashmap_countName = m_c8vec_0("count"); gc_add(hashmap_countName); hashmap_countDesc = registerNFn(m_c8vec_0("(hashmap).Count"), hashmap_count_c1, c2_bad);
|
||||||
}
|
}
|
||||||
B hashMap_c2(B t, B w, B x) {
|
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);
|
if (!isArr(w) || RNK(w)!=1 || !isArr(x) || RNK(x)!=1) thrF("•HashMap: Arguments must be lists (%H≡≢𝕨, %H≡≢𝕩)", w, x);
|
||||||
@ -731,9 +744,9 @@ B hashMap_c2(B t, B w, B x) {
|
|||||||
if (hashmap_ns==NULL) hashmap_init();
|
if (hashmap_ns==NULL) hashmap_init();
|
||||||
w = taga(toHArr(w)); x = taga(toHArr(x));
|
w = taga(toHArr(w)); x = taga(toHArr(x));
|
||||||
B h = hashmap_build(w, n);
|
B h = hashmap_build(w, n);
|
||||||
B ns = m_nns(hashmap_ns, w, x, h, m_nfn(hashmap_getDesc, 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_countDesc, bi_N));
|
||||||
Scope* sc = c(NS,ns)->sc;
|
Scope* sc = c(NS,ns)->sc;
|
||||||
for (usz i = 3; i < 4; i++) nfn_swapObj(sc->vars[i], incG(ns));
|
for (usz i = 3; i < 7; i++) nfn_swapObj(sc->vars[i], incG(ns));
|
||||||
return ns;
|
return ns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,6 +45,7 @@ a←(•ParseFloat¨ "1.2"‿"-0"‿"0")∾-⊸⋈0÷0 ⋄ ! (0‿3‿3‿3⊏a)
|
|||||||
!"⊐: Rank of 𝕩 must be at least the cell rank of 𝕨 (2‿2‿2 ≡ ≢𝕨, ⟨2⟩ ≡ ≢𝕩)" % (2‿2‿2⥊1‿2)⊐1‿2
|
!"⊐: Rank of 𝕩 must be at least the cell rank of 𝕨 (2‿2‿2 ≡ ≢𝕨, ⟨2⟩ ≡ ≢𝕩)" % (2‿2‿2⥊1‿2)⊐1‿2
|
||||||
!"⊒: Rank of 𝕩 must be at least the cell rank of 𝕨 (2‿2‿2 ≡ ≢𝕨, ⟨2⟩ ≡ ≢𝕩)" % (2‿2‿2⥊1‿2)⊒1‿2
|
!"⊒: Rank of 𝕩 must be at least the cell rank of 𝕨 (2‿2‿2 ≡ ≢𝕨, ⟨2⟩ ≡ ≢𝕩)" % (2‿2‿2⥊1‿2)⊒1‿2
|
||||||
|
|
||||||
⟨"get"⟩ %% •ns.Keys "abc"‿"de"‿"fgh" •HashMap ↕3
|
|
||||||
⟨2⟩ %% ("abc"‿"de"‿"fgh" •HashMap ⥊¨↕3).Get "fgh"
|
⟨2⟩ %% ("abc"‿"de"‿"fgh" •HashMap ⥊¨↕3).Get "fgh"
|
||||||
∞ %% ∞ ("abc"‿"de"‿"fgh" •HashMap ⥊¨↕3).Get "fghi"
|
∞ %% ∞ ("abc"‿"de"‿"fgh" •HashMap ⥊¨↕3).Get "fghi"
|
||||||
|
3 %% ("abc"‿"de"‿"fgh" •HashMap ⥊¨↕3).Count@
|
||||||
|
"B" %% ("b" ("a"‿"b" •HashMap "A"‿"C").Set "B").Get "b"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user