commit
a5ce138385
@ -15,6 +15,7 @@
|
|||||||
/* sysfn.c*/D(nGet,"•ns.Get") D(nHas,"•ns.Has") M(nKeys,"•ns.Keys") \
|
/* sysfn.c*/D(nGet,"•ns.Get") D(nHas,"•ns.Has") M(nKeys,"•ns.Keys") \
|
||||||
/* sysfn.c*/M(fName,"•file.Name") M(fParent,"•file.Parent") \
|
/* sysfn.c*/M(fName,"•file.Name") M(fParent,"•file.Parent") \
|
||||||
/* sysfn.c*/M(tRawMode,"•term.RawMode") M(tFlush,"•term.Flush") M(tCharB,"•term.CharB") M(tCharN,"•term.CharN") M(tOutRaw,"•term.OutRaw") M(tErrRaw,"•term.ErrRaw") \
|
/* sysfn.c*/M(tRawMode,"•term.RawMode") M(tFlush,"•term.Flush") M(tCharB,"•term.CharB") M(tCharN,"•term.CharN") M(tOutRaw,"•term.OutRaw") M(tErrRaw,"•term.ErrRaw") \
|
||||||
|
/* sysfn.c*/D(hashMap,"•HashMap") \
|
||||||
/* inverse.c*/M(setInvReg,"(SetInvReg)") M(setInvSwap,"(SetInvSwap)") M(nativeInvReg,"(NativeInvReg)") M(nativeInvSwap,"(NativeInvSwap)") \
|
/* inverse.c*/M(setInvReg,"(SetInvReg)") M(setInvSwap,"(SetInvSwap)") M(nativeInvReg,"(NativeInvReg)") M(nativeInvSwap,"(NativeInvSwap)") \
|
||||||
/*internal.c*/M(itype,"•internal.Type") M(elType,"•internal.ElType") M(refc,"•internal.Refc") M(isPure,"•internal.IsPure") A(info,"•internal.Info") \
|
/*internal.c*/M(itype,"•internal.Type") M(elType,"•internal.ElType") M(refc,"•internal.Refc") M(isPure,"•internal.IsPure") A(info,"•internal.Info") \
|
||||||
/*internal.c*/M(heapDump,"•internal.HeapDump") M(internalGC,"•internal.GC") M(heapStats,"•internal.HeapStats") \
|
/*internal.c*/M(heapDump,"•internal.HeapDump") M(internalGC,"•internal.GC") M(heapStats,"•internal.HeapStats") \
|
||||||
|
|||||||
@ -601,3 +601,167 @@ void search_init(void) {
|
|||||||
getRange_fns[4] = getRange_f64;
|
getRange_fns[4] = getRange_f64;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// •HashMap implementation
|
||||||
|
typedef struct HashMap {
|
||||||
|
struct Value;
|
||||||
|
u64 pop; // count of defined entries
|
||||||
|
u64 sh; // shift to turn hash into index
|
||||||
|
u64 sz; // count of allocated entries, a power of 2
|
||||||
|
u64 a[]; // lower 32 bits: index into keys/vals; upper 32 bits: upper 32 bits of hash
|
||||||
|
} 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;
|
||||||
|
|
||||||
|
usz hashmap_count(B hash) { return c(HashMap, hash)->pop; }
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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<l; i++) {
|
||||||
|
B ki = keys[i];
|
||||||
|
keys[j] = ki;
|
||||||
|
vals[j] = vals[i];
|
||||||
|
ind_map[i+1] = j;
|
||||||
|
j += !q_N(ki);
|
||||||
|
}
|
||||||
|
IA(k) = IA(v) = j;
|
||||||
|
FINISH_OVERALLOC_A(k, j*sizeof(B), (l0-j)*sizeof(B));
|
||||||
|
FINISH_OVERALLOC_A(v, j*sizeof(B), (l0-j)*sizeof(B));
|
||||||
|
if (j > 0) {
|
||||||
|
HashMap* map = c(HashMap, vars[2]);
|
||||||
|
assert(j == map->pop);
|
||||||
|
u64 sz = map->sz;
|
||||||
|
u64* hp = map->a;
|
||||||
|
for (u64 i=0; i<sz; i++) {
|
||||||
|
u64 h = hp[i];
|
||||||
|
hp[i] = (h&~hmask) | ind_map[(u32)h + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TFREE(ind_map);
|
||||||
|
}
|
||||||
|
B hashmap_keys_or_vals(B* vars, usz which) {
|
||||||
|
assert(which < 2);
|
||||||
|
B r = vars[which];
|
||||||
|
if (c(HashMap, vars[2])->pop == 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); \
|
||||||
|
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;
|
||||||
|
u64 sz = hashmap_size(sh);
|
||||||
|
HashMap* map = hashmap_alloc(n, sh, sz);
|
||||||
|
u64* hp = map->a;
|
||||||
|
B* keys = harr_ptr(key_arr);
|
||||||
|
for (usz i=0; i<n; i++) {
|
||||||
|
B key = keys[i];
|
||||||
|
HASHMAP_INSERT(key, thrM("•HashMap: 𝕨 contained duplicate keys");)
|
||||||
|
if (RARE(je == sz-1)) {
|
||||||
|
map=hashmap_resize(map);
|
||||||
|
hp=map->a; sh=map->sh; sz=map->sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tag(map, OBJ_TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
B hashmap_lookup(B* vars, B w, B x) {
|
||||||
|
HashMap* map = c(HashMap, vars[2]);
|
||||||
|
u64* hp = map->a; u64 sh = map->sh;
|
||||||
|
B* keys = harr_ptr(vars[0]);
|
||||||
|
HASHMAP_FIND(x, dec(w); dec(x); return inc(harr_ptr(vars[1])[i]);)
|
||||||
|
if (q_N(w)) thrM("(hashmap).Get: key not found");
|
||||||
|
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 = IA(vars[0]);
|
||||||
|
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++;
|
||||||
|
if (map->pop>>(64-3-sh)>7 || je==map->sz-1) { // keep load <= 7/8
|
||||||
|
vars[2] = bi_N; // hashmap_resize might free then alloc
|
||||||
|
map = hashmap_resize(map);
|
||||||
|
vars[2] = tag(map, OBJ_TAG);
|
||||||
|
hp=map->a; sh=map->sh;
|
||||||
|
}
|
||||||
|
vars[0] = vec_addN(vars[0], w);
|
||||||
|
vars[1] = vec_addN(vars[1], x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hashmap_delete(B* vars, B x) {
|
||||||
|
HashMap* map = c(HashMap, vars[2]);
|
||||||
|
u64* hp = map->a; u64 sh = map->sh;
|
||||||
|
B kb = vars[0]; B* keys = harr_ptr(kb);
|
||||||
|
HASHMAP_FIND(x,
|
||||||
|
dec(x);
|
||||||
|
do {
|
||||||
|
u64 jp=j; j++;
|
||||||
|
u=hp[j]; if (u>>sh==j) u=empty;
|
||||||
|
hp[jp]=u;
|
||||||
|
} while (u!=empty);
|
||||||
|
B vb = vars[1];
|
||||||
|
if (!reusable(kb)) { vars[0]=kb=taga(cpyHArr(kb)); keys=harr_ptr(kb); }
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|||||||
@ -707,6 +707,60 @@ B currentError_c1(B t, B x) {
|
|||||||
B currentError_c1(B t, B x) { thrM("•CurrentError: No errors as error catching has been disabled"); }
|
B currentError_c1(B t, B x) { thrM("•CurrentError: No errors as error catching has been disabled"); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static Body* hashmap_ns;
|
||||||
|
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_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_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("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);
|
||||||
|
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_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);
|
||||||
|
usz n = IA(w);
|
||||||
|
if (n != IA(x)) thrF("•HashMap: 𝕨 and 𝕩 must have the same length (%s≡≠𝕨, %s≡≠𝕩)", n, IA(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), m_nfn(hashmap_keysDesc, bi_N), m_nfn(hashmap_valuesDesc, bi_N));
|
||||||
|
Scope* sc = c(NS,ns)->sc;
|
||||||
|
for (usz i = 3; i < 10; i++) nfn_swapObj(sc->vars[i], incG(ns));
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
|
|
||||||
static NFnDesc* fileAtDesc;
|
static NFnDesc* fileAtDesc;
|
||||||
B fileAt_c1(B d, B x) {
|
B fileAt_c1(B d, B x) {
|
||||||
return path_rel(nfn_objU(d), x, "•file.At");
|
return path_rel(nfn_objU(d), x, "•file.At");
|
||||||
@ -1623,6 +1677,7 @@ static Body* file_nsGen;
|
|||||||
F("fromutf8", U"•FromUTF8", bi_fromUtf8) \
|
F("fromutf8", U"•FromUTF8", bi_fromUtf8) \
|
||||||
F("toutf8", U"•ToUTF8", bi_toUtf8) \
|
F("toutf8", U"•ToUTF8", bi_toUtf8) \
|
||||||
F("currenterror", U"•CurrentError", bi_currentError) \
|
F("currenterror", U"•CurrentError", bi_currentError) \
|
||||||
|
F("hashmap", U"•HashMap", bi_hashMap) \
|
||||||
F("math", U"•math", tag(0,VAR_TAG)) \
|
F("math", U"•math", tag(0,VAR_TAG)) \
|
||||||
F("rand", U"•rand", tag(1,VAR_TAG)) \
|
F("rand", U"•rand", tag(1,VAR_TAG)) \
|
||||||
F("term", U"•term", tag(2,VAR_TAG)) \
|
F("term", U"•term", tag(2,VAR_TAG)) \
|
||||||
|
|||||||
@ -44,3 +44,18 @@ 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 ≡ ≢𝕩)" % 1‿2∊2‿2‿2⥊1‿2
|
!"∊: Rank of 𝕨 must be at least the cell rank of 𝕩 (⟨2⟩ ≡ ≢𝕨, 2‿2‿2 ≡ ≢𝕩)" % 1‿2∊2‿2‿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
|
!"⊒: Rank of 𝕩 must be at least the cell rank of 𝕨 (2‿2‿2 ≡ ≢𝕨, ⟨2⟩ ≡ ≢𝕩)" % (2‿2‿2⥊1‿2)⊒1‿2
|
||||||
|
|
||||||
|
# hashmap
|
||||||
|
("abc"‿"de"‿"fgh" •HashMap ⥊¨↕3).Get "fgh" %% ⟨2⟩
|
||||||
|
∞ ("abc"‿"de"‿"fgh" •HashMap ⥊¨↕3).Get "fghi" %% ∞
|
||||||
|
("abc"‿"de"‿"fgh" •HashMap ⥊¨↕3).Count"xy" %% 3
|
||||||
|
("b" ("a"‿"b" •HashMap "A"‿"C").Set "B").Get "b" %% "B"
|
||||||
|
((•HashMap˜↕4).Set´ 1‿"one").Keys↕2 %% ↕4
|
||||||
|
(((•HashMap˜↕4).Delete 1).Set´ 1‿"one").Keys@ %% 0‿2‿3‿1
|
||||||
|
(((•HashMap˜↕4).Delete 1).Set´ 1‿"one").Values@ %% 0‿2‿3‿"one"
|
||||||
|
({𝕩.Set´"xy"}⍟4•HashMap˜↕0).Count@ %% 1
|
||||||
|
!"•HashMap: Arguments must be lists (⟨⟩≡≢𝕨, ⟨3⟩≡≢𝕩)" % 'a' •HashMap "str"
|
||||||
|
!"•HashMap: 𝕨 and 𝕩 must have the same length (4≡≠𝕨, 3≡≠𝕩)" % "stri" •HashMap "str"
|
||||||
|
!"•HashMap: 𝕨 contained duplicate keys" % "strs" •HashMap "stri"
|
||||||
|
!"(hashmap).Get: key not found" % ("abc"‿"de"‿"fgh" •HashMap ⥊¨↕3).Get "fg"
|
||||||
|
!"(hashmap).Delete: key not found" % ("abc"‿"de"‿"fgh" •HashMap ⥊¨↕3).Delete 'a'
|
||||||
|
|||||||
42
test/hashmap.bqn
Normal file
42
test/hashmap.bqn
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
u ← ⌊100×(•UnixTime+1|100וMonoTime)@
|
||||||
|
ro← •MakeRand •Show u
|
||||||
|
R ← ro.Range
|
||||||
|
|
||||||
|
err ← 1 # Run operations that should error
|
||||||
|
|
||||||
|
Test ← {iter 𝕊 n:
|
||||||
|
# Global set of keys that might be used
|
||||||
|
keys ← ⊒⊸(-⊸∾⍟(0<⊣)¨) (R⟜15 R¨ 1-˜1e6⌊∘⋆R⟜0) n
|
||||||
|
# Which keys are currently set, and count
|
||||||
|
c ← +´ mask ← 0 = n R 20+R 10
|
||||||
|
# Value for key if set
|
||||||
|
vals ← ((R⟜≠⊏⊢)⟜⊢‿÷‿⥊‿↕ {𝕎𝕩}¨ R⟜10) n
|
||||||
|
|
||||||
|
map ← keys •HashMap○(mask⊸/) vals
|
||||||
|
|
||||||
|
# Single operations and checks
|
||||||
|
_er ← { err ? ! 0∘𝔽⎊1 𝕩⊑keys ; 1 }
|
||||||
|
Cnt ← {𝕊: ! c ≡ map.Count@ }
|
||||||
|
Key ← {𝕊: ! (mask/keys) ≡○∧ map.Keys@ }
|
||||||
|
Val ← {𝕊: ! (mask/vals) ≡○∧ map.Values@ }
|
||||||
|
Has ← { ! (𝕩⊑mask) ≡ map.Has 𝕩⊑keys }
|
||||||
|
Get ← { 𝕩⊑mask ? ! (𝕩⊑vals) ≡ map.Get 𝕩⊑keys ; map.Get _er 𝕩 }
|
||||||
|
Set ← { 𝕨 map.Set˜ 𝕩⊑keys ⋄ vals 𝕨˙⌾(𝕩⊸⊑)↩ ⋄ mask {c+↩¬𝕩⋄1}⌾(𝕩⊸⊑)↩ ⋄ @ }
|
||||||
|
Del ← { 𝕩⊑mask ? map.Delete 𝕩⊑keys ⋄ mask 0⌾(𝕩⊸⊑)↩ ⋄ c-↩1 ; map.Delete _er 𝕩 }
|
||||||
|
|
||||||
|
Selection ← { (𝕨≤1)◶⟨R·⌊1.5⊸×,𝕨⟩⊸⌊⊸ro.Deal∘≠⊸⊏ 𝕩 }
|
||||||
|
RandVal ← R∘100
|
||||||
|
ops ← ⟨Cnt, Has, Get, Del, (R∘n⊑vals˙)Set⊢, RandVal⊸Set⟩
|
||||||
|
|
||||||
|
# Larger sets: argument is number of ops (sometimes overridden)
|
||||||
|
FullCheck ← Key∘Val∘Cnt
|
||||||
|
Deletes ← { Del¨ 𝕩 Selection mask }
|
||||||
|
Restores ← { ⊏⟜vals⊸(Set¨) 𝕩 Selection ¬mask }
|
||||||
|
RandomOps ← (R⟜≠⊏⊢)⟜ops {𝕎𝕩}¨ R⟜n
|
||||||
|
RandomSame ← R∘≠⊸⊑∘ops {𝕎𝕩}¨ R⟜n
|
||||||
|
opSets ← FullCheck‿Deletes‿Restores‿RandomOps‿RandomSame
|
||||||
|
((R⟜≠⊏⊢)⟜opSets {𝕎𝕩}¨ R⟜100) iter
|
||||||
|
}
|
||||||
|
|
||||||
|
1e5 Test 1e2
|
||||||
|
1e4 Test 1e4
|
||||||
Loading…
Reference in New Issue
Block a user