diff --git a/src/singeli/src/hashmap.singeli b/src/singeli/src/hashtab.singeli similarity index 87% rename from src/singeli/src/hashmap.singeli rename to src/singeli/src/hashtab.singeli index 0e7ca77a..f07e2a05 100644 --- a/src/singeli/src/hashmap.singeli +++ b/src/singeli/src/hashtab.singeli @@ -1,6 +1,13 @@ local include 'skin/cext' local include './cbqnDefs' # talloc/tfree +# Search primitives +# Function params are passed as names to keep generated code readable +def names = tup{'memberOf', 'count', 'indexOf'} +def prims = tup{'∊', '⊒', '⊐' } +def map{{f,...fs}, {t,...ts}, v} = if (v==f) t else map{fs, ts, v} +def to_prim = map{names, prims, .} + # Defined in C def memset{p:pT, v, l} = { emit{void, merge{'memset',fmtnat{elwidth{pT}}}, p, v, l} diff --git a/src/singeli/src/search.singeli b/src/singeli/src/search.singeli index 4f544160..40b2e35c 100644 --- a/src/singeli/src/search.singeli +++ b/src/singeli/src/search.singeli @@ -1,7 +1,7 @@ include './base' include './mask' include './vecfold' -include './hashmap' +include './hashtab' def findFirst{C, M, F, ...v1} = { def exit = makelabel{} @@ -333,16 +333,11 @@ exportT{'simd_getRangeRaw', each{getRange, tup{i8,i16,i32,f64}}} # Hash tables -def names = tup{'memberOf', 'count', 'indexOf'} -def prims = tup{'∊', '⊒', '⊐' } -def map{{f,...fs}, {t,...ts}, v} = if (v==f) t else map{fs, ts, v} -def to_prim = map{names, prims, .} - oper &- ({v:T,m} => v & -promote{T,m}) infix left 35 def rty{name} = if (to_prim{name}=='∊') i8 else i32 def ity{name} = (to_prim{name}=='⊒')**(*u32) -fn hashtab{T, name}(rp:*rty{name}, ip:*T, m:usz, fp:*T, n:usz, ilink:ity{name}) = { +fn hashtab{T, name}(rp:*rty{name}, ip:*T, m:usz, fp:*T, n:usz, links:ity{name}) = { def wt = width{T} def prim = to_prim{name} def stop = m @@ -365,18 +360,70 @@ fn hashtab{T, name}(rp:*rty{name}, ip:*T, m:usz, fp:*T, n:usz, ilink:ity{name}) } def {hash,...vals} = tabs - each{store{.,0,0}, ilink} + def {set_tab, set_maxh, fixup, get_res} = match (prim) { + {('∊')} => { + has_maxh:u1 = 0 + def set{j,je,kr,dup} = { setlabel{dup} } + def setm{found, i} = has_maxh |= found + end := maxh>>sh # Clip trailing maxh if it shouldn't be in the table + def usem{} = { + if (has_maxh) { while (load{hash,end}!=maxh) ++end } + else end += promote{T,ext} # Unreachable + } + def get{found, j} = promote{i8, found & (j { + 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, i1-load{inds,j}} + store{inds, j, i1} + } + def get{found, j} = { + ti := load{inds, j}; mi := ti &- found + store{inds, j, ti - load{link,mi}} + i32~~(m - mi) + } + tup{set, {found,i}=>{}, {}=>{}, get} + } + } def lookup=makelabel{}; def abort=makelabel{}; def dup=makelabel{} cc:usz = 0 # Collision counter - has_maxh:u1 = 0 - def ind_maxh = @collect (prim=='⊐') {mi:u32=0} i:usz=0; while (1) { e := tern{m-i>b, i+b, m} while (i < e) { - h := hash_val{load{ip,if (prim!='⊒') i else (m-i-1)}}; j := h>>sh - each{{mi}=>{mi|=i&-((h==maxh)&~has_maxh)}, ind_maxh} - has_maxh |= h==maxh + 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) @@ -392,20 +439,8 @@ fn hashtab{T, name}(rp:*rty{name}, ip:*T, m:usz, fp:*T, n:usz, ilink:ity{name}) } while (k != maxh) cc += cast_i{usz, je-j0} } - if (prim!='⊒') { - each{store{., j, .}, tabs, tup{h,...aux**(m-i)}} - setlabel{dup} - } else { - # maxh entry either stores 0 or is the last entry and stores an - # index, so this preserves all values - ++je; each{{p,v}=>store{p,je,v|load{p,je}}, vals, kr} - each{store{.,j,0}, vals} - store{hash, j, h} - setlabel{dup} - i1 := i+1 - each{{p,q} => store{p, i1, i1-load{q,j}}, ilink, vals} - each{store{., j, .}, vals, tup{i1}} - } + store{hash, j, h} + set_tab{j, je, kr, dup} ++i } if (i == m) goto{lookup} @@ -418,24 +453,11 @@ fn hashtab{T, name}(rp:*rty{name}, ip:*T, m:usz, fp:*T, n:usz, ilink:ity{name}) } setlabel{lookup} - end := maxh>>sh + promote{T,ext} # Unreachable - if ((prim!='⊒') and has_maxh) { - end=maxh>>sh; while (load{hash,end}!=maxh) ++end - each{store{.,end,.}, vals, ind_maxh} - } + fixup{} @for (rp, fp over n) { h := hash_val{fp}; j := h>>sh - k:=undefined{T}; while ((k=load{hash,j}) < h) ++j - rp = (match (prim) { - {('∊')} => promote{i8, (k==h) & (j i32~~(m - (load{tupsel{0,vals}, j} &- (k==h))) - {('⊒')} => { - def {inds} = vals - ti := load{inds, j}; mi := ti &- (k==h) - store{inds, j, ti - load{tupsel{0,ilink},mi}} - i32~~(m - mi) - } - }) + k := undefined{T}; while ((k=load{hash,j}) < h) ++j + rp = get_res{k==h, j} } setlabel{abort} diff --git a/src/singeli/src/selfsearch.singeli b/src/singeli/src/selfsearch.singeli index 37571407..834de1f3 100644 --- a/src/singeli/src/selfsearch.singeli +++ b/src/singeli/src/selfsearch.singeli @@ -1,11 +1,6 @@ include './base' local include 'skin/cext' -include './hashmap' - -def names = tup{'memberOf', 'count', 'indexOf'} -def prims = tup{'∊', '⊒', '⊐' } -def map{{f,...fs}, {t,...ts}, v} = if (v==f) t else map{fs, ts, v} -def to_prim = map{names, prims, .} +include './hashtab' # Resizing hash table, with fallback def rty{name} = if (to_prim{name}=='∊') i8 else i32 @@ -68,7 +63,7 @@ fn selfhashtab{T, name}(rp:*rty{name}, xp:*T, n:usz) = { if (k!=h) { val<-{j}ctr; ++ctr; hash<-{j}h } val->j } - tup{{b}=>promote{u32,b}*ctr, res} + tup{{b}=>ctr & -promote{u32,b}, res} } }