# eval_text.ludic - a text with holes ("{n} left") worked out: its pieces are found in the memo by # comparing in place, so the text it was last frame (and the frame before) is its kept Value, and a # text is built only the first time it reads that way. The memo is bounded; past it a text is built as ever function ev_text(ui_st: mut UiState, x: UiExpr, e: UiEnv) -> Val { let depth = ui_st.tx_depth # a hole may hold a text of its own: a kept list of pieces a depth @alloc_ok("once per depth of nesting, then kept") while len(ui_st.tx_pieces) <= depth { push(ui_st.tx_pieces, new []string) } let ps = ui_st.tx_pieces[depth] ui_st.tx_depth = depth + 1 List.clear(ps) for i in 0 .. len(x.args) { tx_piece(ui_st, ps, ui_eval(ui_st, x.args[i], e)) } ui_st.tx_depth = depth return tx_memo(ui_st, ps) } # the text these pieces join into, from the memo when it read this way before, else joined and kept function tx_memo(ui_st: mut UiState, ps: []string) -> Val { let m = mm_of(ui_st) var h = 216613626 ^ (MM_TEXT & 255) for p in 0 .. len(ps) { let t = ps[p] for i in 0 .. len(t) { h = ((h ^ t[i]) * 16777619) & 2147483647 } } var at = h & (MM_CAP - 1) while m.slots[at] != 0 { let i = m.slots[at] - 1 if m.tags[i] == MM_TEXT and tx_same(ps, m.keys[i]) { return m.vals[i] } at = (at + 1) & (MM_CAP - 1) } return ev_text_new(ui_st, m, ps) } # a text read this way for the first time: joined, and kept in the memo with its Value @alloc_ok("a memo miss: once per distinct text, bounded by MM_CAP") function ev_text_new(ui_st: mut UiState, m: UiMemo, ps: []string) -> Val { var out = "" for p in 0 .. len(ps) { out = out + ps[p] } let j = mm_add(m, MM_TEXT, out) if j < 0 { return uv_str(ui_st, out) } m.vals[j] = Value.str(out) return m.vals[j] } function tx_same(ps: []string, k: string) -> bool { var at = 0 for p in 0 .. len(ps) { if not sat(k, at, ps[p]) { return false } at += len(ps[p]) } return at == len(k) } # a hole's value as pieces: a float to one decimal from kept texts (its whole part from mm_int, its tenth a # literal), so a bar's width moving every frame makes no string - and reads 42.5%, never 7.470598e-07% function tx_piece(ui_st: mut UiState, ps: []string, v: Val) -> void { let k = Value.kind(v) if k != 2 and k != 7 { ui_kept(ps, vl_text_u(ui_st, v)) return } var t = int(Math.round(Value.as_float(v) * 10.0)) if t < 0 { ui_kept(ps, "-") t = 0 - t } ui_kept(ps, mm_int(ui_st, t / 10)) let d = t % 10 if d != 0 { ui_kept(ps, tx_tenth(d)) } } function tx_tenth(d: int) -> string { if d == 1 { return ".1" } if d == 2 { return ".2" } if d == 3 { return ".3" } if d == 4 { return ".4" } if d == 5 { return ".5" } if d == 6 { return ".6" } if d == 7 { return ".7" } if d == 8 { return ".8" } return ".9" }