Turn hash function definition structure inside-out
This commit is contained in:
parent
aded9d4782
commit
f1485ca98c
@ -364,16 +364,59 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
|
|||||||
}
|
}
|
||||||
def {hash,...vals} = tabs
|
def {hash,...vals} = tabs
|
||||||
|
|
||||||
def {set_tab, set_maxh, fixup, get_res} = match (prim) {
|
def abort = makelabel{}
|
||||||
{('∊')} => {
|
i:usz = 0 # Saved to determine if hashing finished
|
||||||
has_maxh:u1 = 0
|
def insert_all{set_tab, set_maxh, dup, ...uniq} = {
|
||||||
def set{j,je,kr,dup} = { setlabel{dup} }
|
cc:usz = 0 # Collision counter
|
||||||
def setm{found, i} = has_maxh |= found
|
def insert_finish = makelabel{}
|
||||||
end := maxh>>sh # Clip trailing maxh if it shouldn't be in the table
|
while (1) {
|
||||||
def usem{} = {
|
e := tern{m-i>b, i+b, m}
|
||||||
if (swap) {
|
while (i < e) {
|
||||||
swap_sides{}; i=m # i==m return value is kind of dumb
|
def ii = if (prim!='⊒') i else m-i-1
|
||||||
@for (ip over m) { # Remove values in ip from hash
|
h := hash_val{load{ip,ii}}; j := h>>sh
|
||||||
|
set_maxh{h==maxh, i}
|
||||||
|
kv := each{load{.,j}, tabs}; def {k,...kr} = kv
|
||||||
|
# Robin Hood insertion
|
||||||
|
j0 := j; je := j # Save value; end of chain (insert at j)
|
||||||
|
if (k != maxh) {
|
||||||
|
if (k == h) goto{dup}
|
||||||
|
do {
|
||||||
|
++je; knv := each{load{.,je}, tabs}; def {kn,..._} = knv
|
||||||
|
def c = promote{T, h >= k}
|
||||||
|
j += c
|
||||||
|
if (kn == h) goto{dup}
|
||||||
|
each{store{.,je-c,.}, tabs, kv}
|
||||||
|
each{=, kv, knv}
|
||||||
|
} while (k != maxh)
|
||||||
|
cc += cast_i{usz, je-j0}
|
||||||
|
}
|
||||||
|
each{{u} => { u += promote{usz,h!=maxh} }, uniq}
|
||||||
|
store{hash, j, h}
|
||||||
|
set_tab{j, je, kr}
|
||||||
|
++i
|
||||||
|
}
|
||||||
|
if (i == m) goto{insert_finish}
|
||||||
|
# Check collision counter and possibly resize (needs tuning)
|
||||||
|
if (cc >= stop and sz == msz) goto{abort}
|
||||||
|
if (16*cc >= stop and sz < msz) {
|
||||||
|
hash_resize{cc, 2} # Factor of 4
|
||||||
|
if (cc >= stop) goto{abort}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setlabel{insert_finish}
|
||||||
|
}
|
||||||
|
|
||||||
|
def hash_remove{j,h} = {
|
||||||
|
do {
|
||||||
|
jp:=j; ++j
|
||||||
|
h=load{hash,j}
|
||||||
|
if (h>>sh == j) h = maxh
|
||||||
|
store{hash, jp, h}
|
||||||
|
each{{t} => store{t, jp, load{t,j}}, vals}
|
||||||
|
} while (h!=maxh)
|
||||||
|
}
|
||||||
|
def memb_remove{uniq, has_maxh} = {
|
||||||
|
@for (ip over m) {
|
||||||
h := hash_val{ip}; j := h>>sh
|
h := hash_val{ip}; j := h>>sh
|
||||||
def shortcut = makelabel{}
|
def shortcut = makelabel{}
|
||||||
if (h == maxh) {
|
if (h == maxh) {
|
||||||
@ -396,102 +439,6 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try_vec_memb{T, hash, sz, sh, maxh, has_maxh, swap, rp, fp, n, abort}
|
|
||||||
if (has_maxh) { while (load{hash,end}!=maxh) ++end }
|
|
||||||
else end += promote{T,ext} # Unreachable
|
|
||||||
}
|
|
||||||
def get{found, j} = promote{i8, swap ^ (found & (j<end))}
|
|
||||||
tup{set, setm, usem, get}
|
|
||||||
}
|
|
||||||
{('⊐')} => {
|
|
||||||
def {inds} = vals
|
|
||||||
has_maxh:u1 = 0
|
|
||||||
ind_maxh:u32 = 0
|
|
||||||
def set{j,je,kr,dup} = {
|
|
||||||
store{inds, j, m-i} # So it can be cleared with one &- in get{}
|
|
||||||
setlabel{dup}
|
|
||||||
}
|
|
||||||
def setm{found, i} = {
|
|
||||||
ind_maxh |= i &- (found&~has_maxh)
|
|
||||||
has_maxh |= found
|
|
||||||
}
|
|
||||||
def usem{} = {
|
|
||||||
if (has_maxh) {
|
|
||||||
end := maxh>>sh; while (load{hash,end}!=maxh) ++end
|
|
||||||
store{inds, end, ind_maxh}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
def get{found, j} = i32~~(m - (load{inds, j} &- found))
|
|
||||||
tup{set, setm, usem, get}
|
|
||||||
}
|
|
||||||
{('⊒')} => {
|
|
||||||
def {inds} = vals; def {link} = links
|
|
||||||
store{link,0,0}
|
|
||||||
def set{j,je,{kr},dup} = {
|
|
||||||
# maxh entry either stores 0 or is the last entry and stores an
|
|
||||||
# index, so this preserves all values
|
|
||||||
++je; store{inds, je, kr|load{inds,je}}
|
|
||||||
store{inds, j, 0}
|
|
||||||
setlabel{dup}
|
|
||||||
i1 := i+1
|
|
||||||
store{link, i1, load{inds,j}}
|
|
||||||
store{inds, j, i1}
|
|
||||||
}
|
|
||||||
def get{found, j} = assert{0}
|
|
||||||
tup{set, {found,i}=>{}, {}=>{}, get}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def lookup=makelabel{}; def abort=makelabel{}; def dup=makelabel{}
|
|
||||||
cc:usz = 0 # Collision counter
|
|
||||||
uniq:usz = 0 # Uniques inserted
|
|
||||||
i:usz=0; while (1) {
|
|
||||||
e := tern{m-i>b, i+b, m}
|
|
||||||
while (i < e) {
|
|
||||||
def ii = if (prim!='⊒') i else m-i-1
|
|
||||||
h := hash_val{load{ip,ii}}; j := h>>sh
|
|
||||||
set_maxh{h==maxh, i}
|
|
||||||
kv := each{load{.,j}, tabs}; def {k,...kr} = kv
|
|
||||||
# Robin Hood insertion
|
|
||||||
j0 := j; je := j # Save value; end of chain (insert at j)
|
|
||||||
if (k != maxh) {
|
|
||||||
if (k == h) goto{dup}
|
|
||||||
do {
|
|
||||||
++je; knv := each{load{.,je}, tabs}; def {kn,..._} = knv
|
|
||||||
def c = promote{T, h >= k}
|
|
||||||
j += c
|
|
||||||
if (kn == h) goto{dup}
|
|
||||||
each{store{.,je-c,.}, tabs, kv}
|
|
||||||
each{=, kv, knv}
|
|
||||||
} while (k != maxh)
|
|
||||||
cc += cast_i{usz, je-j0}
|
|
||||||
}
|
|
||||||
if (prim=='∊') uniq += promote{usz,h!=maxh}
|
|
||||||
store{hash, j, h}
|
|
||||||
set_tab{j, je, kr, dup}
|
|
||||||
++i
|
|
||||||
}
|
|
||||||
if (i == m) goto{lookup}
|
|
||||||
# Check collision counter and possibly resize (needs tuning)
|
|
||||||
if (cc >= stop and sz == msz) goto{abort}
|
|
||||||
if (16*cc >= stop and sz < msz) {
|
|
||||||
hash_resize{cc, 2} # Factor of 4
|
|
||||||
if (cc >= stop) goto{abort}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def hash_remove{j,h} = {
|
|
||||||
do {
|
|
||||||
jp:=j; ++j
|
|
||||||
h=load{hash,j}
|
|
||||||
if (h>>sh == j) h = maxh
|
|
||||||
store{hash, jp, h}
|
|
||||||
each{{t} => store{t, jp, load{t,j}}, vals}
|
|
||||||
} while (h!=maxh)
|
|
||||||
}
|
|
||||||
|
|
||||||
setlabel{lookup}
|
|
||||||
fixup{}
|
|
||||||
def prog_lookup{swap} = { # Progressive Index-of lookup
|
def prog_lookup{swap} = { # Progressive Index-of lookup
|
||||||
def rev{a,b} = if (swap) tup{b,a} else tup{a,b}
|
def rev{a,b} = if (swap) tup{b,a} else tup{a,b}
|
||||||
memset{*u32~~rp, ...rev{m,n}}
|
memset{*u32~~rp, ...rev{m,n}}
|
||||||
@ -514,9 +461,8 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
|
|||||||
}
|
}
|
||||||
setlabel{shortcut}
|
setlabel{shortcut}
|
||||||
}
|
}
|
||||||
if (prim=='⊒') {
|
|
||||||
if (not swap) prog_lookup{0} else prog_lookup{1}
|
def lookup_all{get_res} = {
|
||||||
} else {
|
|
||||||
@for (rp, fp over n) {
|
@for (rp, fp over n) {
|
||||||
h := hash_val{fp}; j := h>>sh
|
h := hash_val{fp}; j := h>>sh
|
||||||
k := undefined{T}; while ((k=load{hash,j}) < h) ++j
|
k := undefined{T}; while ((k=load{hash,j}) < h) ++j
|
||||||
@ -524,6 +470,65 @@ fn hashtab{T, name}(rp:*rty{name}, iv:*void, m:usz, fv:*void, n:usz, links:ity{n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match (prim, ...vals, ...links) {
|
||||||
|
{('∊')} => {
|
||||||
|
has_maxh:u1 = 0
|
||||||
|
uniq:usz = 0 # Uniques inserted
|
||||||
|
def dup = makelabel{}
|
||||||
|
insert_all{
|
||||||
|
{j,je,kr} => setlabel{dup},
|
||||||
|
{found, i} => has_maxh |= found,
|
||||||
|
dup, uniq
|
||||||
|
}
|
||||||
|
if (swap) {
|
||||||
|
swap_sides{}; i=m # i==m return value is kind of dumb
|
||||||
|
memb_remove{uniq,has_maxh} # Remove values in ip from hash
|
||||||
|
}
|
||||||
|
try_vec_memb{T, hash, sz, sh, maxh, has_maxh, swap, rp, fp, n, abort}
|
||||||
|
end := maxh>>sh # Clip trailing maxh if it shouldn't be in the table
|
||||||
|
if (has_maxh) { while (load{hash,end}!=maxh) ++end }
|
||||||
|
else end += promote{T,ext} # Unreachable
|
||||||
|
lookup_all{{found, j} => promote{i8, swap ^ (found & (j<end))}}
|
||||||
|
}
|
||||||
|
|
||||||
|
{('⊐'), inds} => {
|
||||||
|
has_maxh:u1 = 0
|
||||||
|
ind_maxh:u32 = 0
|
||||||
|
def dup = makelabel{}
|
||||||
|
def set{j,je,kr} = {
|
||||||
|
store{inds, j, m-i} # So it can be cleared with one &- in get{}
|
||||||
|
setlabel{dup}
|
||||||
|
}
|
||||||
|
def set_maxh{found, i} = {
|
||||||
|
ind_maxh |= i &- (found&~has_maxh)
|
||||||
|
has_maxh |= found
|
||||||
|
}
|
||||||
|
insert_all{set, set_maxh, dup}
|
||||||
|
if (has_maxh) {
|
||||||
|
end := maxh>>sh; while (load{hash,end}!=maxh) ++end
|
||||||
|
store{inds, end, ind_maxh}
|
||||||
|
}
|
||||||
|
lookup_all{{found, j} => i32~~(m - (load{inds, j} &- found))}
|
||||||
|
}
|
||||||
|
|
||||||
|
{('⊒'), inds, link} => {
|
||||||
|
store{link,0,0}
|
||||||
|
def dup = makelabel{}
|
||||||
|
def set{j,je,{kr}} = {
|
||||||
|
# maxh entry either stores 0 or is the last entry and stores an
|
||||||
|
# index, so this preserves all values
|
||||||
|
++je; store{inds, je, kr|load{inds,je}}
|
||||||
|
store{inds, j, 0}
|
||||||
|
setlabel{dup}
|
||||||
|
i1 := i+1
|
||||||
|
store{link, i1, load{inds,j}}
|
||||||
|
store{inds, j, i1}
|
||||||
|
}
|
||||||
|
insert_all{set, {found,i}=>{}, dup}
|
||||||
|
if (not swap) prog_lookup{0} else prog_lookup{1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setlabel{abort}
|
setlabel{abort}
|
||||||
hash_free{}
|
hash_free{}
|
||||||
i == m # Whether it finished
|
i == m # Whether it finished
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user