Found by the windowed walk's exit scan (mm_int 1.2 MB, lss_strip 451 KB unreachable). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
3.5 KiB
Text
92 lines
3.5 KiB
Text
# memo_join.ludic - a key joined from its parent's key, a separator and a part ("App/3",
|
|
# "App/3#7", "App/3/ui-thumb"), found by comparing in place, so an element's key is made once
|
|
# the element first appears and never again
|
|
function mm_hash_join(a: string, sep: string, b: string) -> int {
|
|
var h = 216613626 ^ (MM_JOIN & 255)
|
|
for i in 0 .. len(a) { h = ((h ^ a[i]) * 16777619) & 2147483647 }
|
|
h = ((h ^ sep[0]) * 16777619) & 2147483647
|
|
for i in 0 .. len(b) { h = ((h ^ b[i]) * 16777619) & 2147483647 }
|
|
return h
|
|
}
|
|
function mm_is_join(k: string, a: string, sep: string, b: string) -> bool {
|
|
let na = len(a)
|
|
if len(k) != na + 1 + len(b) or k[na] != sep[0] { return false }
|
|
return sat(k, 0, a) and sat(k, na + 1, b)
|
|
}
|
|
# a + sep + b, the same string every frame
|
|
@alloc_ok("a memo miss: a joined key made once, bounded by MM_CAP")
|
|
function mm_join(ui_st: mut UiState, a: string, sep: string, b: string) -> string {
|
|
let m = mm_of(ui_st)
|
|
var at = mm_hash_join(a, sep, b) & (MM_CAP - 1)
|
|
while m.slots[at] != 0 {
|
|
let i = m.slots[at] - 1
|
|
if m.tags[i] == MM_JOIN and mm_is_join(m.keys[i], a, sep, b) { return m.keys[i] }
|
|
at = (at + 1) & (MM_CAP - 1)
|
|
}
|
|
let k = a + sep + b
|
|
if len(m.keys) * 4 >= MM_CAP * 3 { return k }
|
|
push(m.keys, k)
|
|
push(m.tags, MM_JOIN)
|
|
push(m.lists, null)
|
|
push(m.grads, null)
|
|
push(m.texts, null)
|
|
push(m.vals, null)
|
|
push(m.vtpls, null)
|
|
push(m.n1, 0.0)
|
|
push(m.n2, 0.0)
|
|
m.slots[at] = len(m.keys)
|
|
return k
|
|
}
|
|
# a whole number's text, made once (a key's index, a count, money): 0..1023 at the start, the rest up
|
|
# to MM_INT_MOST the first time each is shown; only past that is one made per call
|
|
const MM_INT_MOST: int = 65536
|
|
@alloc_ok("a memo miss: a number's text made the first time it is shown")
|
|
function mm_int(ui_st: mut UiState, i: int) -> string {
|
|
if i < 0 and i > 0 - MM_INT_MOST { return mm_int_neg(ui_st, 0 - i) }
|
|
if i < 0 or i >= MM_INT_MOST { return mm_int_big(ui_st, i) }
|
|
if ui_st.mm_ints == null {
|
|
ui_st.mm_ints = new []string
|
|
for k in 0 .. 1024 { push(ui_st.mm_ints, string(k)) }
|
|
}
|
|
let l = ui_st.mm_ints
|
|
while len(l) <= i { push(l, "") }
|
|
if i >= 1024 and len(l[i]) == 0 { l[i] = string(i) }
|
|
return l[i]
|
|
}
|
|
# a small whole number as a Value, made once and shared: read it, never change it (a loop's index)
|
|
@alloc_ok("once: the small numbers' Values")
|
|
function mm_ival(ui_st: mut UiState, i: int) -> Val {
|
|
if i < 0 or i >= 1024 { return Value.int(i) }
|
|
if ui_st.mm_ivals == null {
|
|
ui_st.mm_ivals = new []Val
|
|
for k in 0 .. 1024 { push(ui_st.mm_ivals, Value.int(k)) }
|
|
}
|
|
return ui_st.mm_ivals[i]
|
|
}
|
|
# a negative whole number's text (a coordinate, a delta), made once per value like mm_int's
|
|
@alloc_ok("a memo miss: a negative number's text made the first time it is shown")
|
|
function mm_int_neg(ui_st: mut UiState, n: int) -> string {
|
|
let l = ui_st.mm_negs
|
|
while len(l) <= n { push(l, "") }
|
|
if len(l[n]) == 0 { l[n] = string(0 - n) }
|
|
return l[n]
|
|
}
|
|
# past MM_INT_MOST: the last MM_BIG seen, kept by value, so a number held for a while is made once
|
|
const MM_BIG: int = 16
|
|
@alloc_ok("a number past the table: at most MM_BIG texts kept, replaced oldest first")
|
|
function mm_int_big(ui_st: mut UiState, i: int) -> string {
|
|
for k in 0 .. len(ui_st.mm_big_v) {
|
|
if ui_st.mm_big_v[k] == i { return ui_st.mm_big_s[k] }
|
|
}
|
|
let s = string(i)
|
|
if len(ui_st.mm_big_v) < MM_BIG {
|
|
push(ui_st.mm_big_v, i)
|
|
push(ui_st.mm_big_s, s)
|
|
} else {
|
|
let at = ui_st.mm_big_at % MM_BIG
|
|
ui_st.mm_big_v[at] = i
|
|
ui_st.mm_big_s[at] = s
|
|
ui_st.mm_big_at = at + 1
|
|
}
|
|
return s
|
|
}
|