ludic/packages/ludic.base/text_intern.ludic
Orkuncakilkaya 6fb5118afd capacities (25.5a): @max(n) on a list field, and a full table is a failure
'@max(64) boxes: []Box' on a property's or a state's field is a promise: the grow path of a push to
that field (only the grow path, so nothing is paid until it doubles) checks it, and growing past n is
reported by the fence - 'PoolState.boxes grew past its @max(16) (it holds 16)' - counted under
count, said under warn, and under fail (a headless or dev build's default) the run ends with exit 87.
Mem.over("what") is the same for a package's own table: ludic.base's StrTable past its most
(sb_intern) and ludic.ui's memo past three quarters of MM_CAP no longer quietly copy per call. The
census counts overflows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 16:43:02 +03:00

56 lines
1.7 KiB
Text

# text_intern.ludic - a kept buffer's bytes as ONE string per distinct text: looked up by content
# (FNV-1a, compared in place), copied out only the first time. Every string handed on is the
# table's and never changes, so a memo keyed on it stays right; past `most` texts a plain copy
export property StrTable {
hs: words = null # open addressing: each slot's hash, and its entry + 1
at: words = null
ss: []string = new []string
most: int = 8192
}
export function strs_new(most: int) -> StrTable {
let tb = new StrTable
tb.most = Math.max(most, 1)
var cap = 16
while cap < tb.most * 2 { cap = cap * 2 }
tb.hs = words(cap)
tb.at = words(cap)
return tb
}
export function strs_count(tb: StrTable) -> int { return len(tb.ss) }
function sb_hash(sb: StrBuf) -> int {
var h = -2128831035
for i in 0 .. sb.n { h = (h ^ sb.b[i]) * 16777619 }
return h
}
function sb_same(sb: StrBuf, s: string) -> bool {
let sp: string = s
if len(sp) != sb.n { return false }
for i in 0 .. sb.n { if sp[i] != sb.b[i] { return false } }
return true
}
# the table's string for the buffer's bytes
@alloc_ok("intern: one string per distinct text, up to the table's most, then kept")
export function sb_intern(sb: StrBuf, tb: StrTable) -> string {
let h = sb_hash(sb)
let mask = len(tb.hs) - 1
var slot = h & mask
while tb.at[slot] != 0 {
let e = tb.at[slot] - 1
if tb.hs[slot] == h and sb_same(sb, tb.ss[e]) { return tb.ss[e] }
slot = (slot + 1) & mask
}
let s = text_of(sb.b, sb.n)
if len(tb.ss) >= tb.most {
Mem.over("a StrTable past its most (sb_intern)") # 25.5a: a full table is a failure, not a copy per call
return s
}
push(tb.ss, s)
tb.hs[slot] = h
tb.at[slot] = len(tb.ss)
return s
}