ludic/packages/ludic.ui/memo_join.ludic

64 lines
2.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 or i >= MM_INT_MOST { return string(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]
}