ludic.ui: props kept an instance, a call's arguments a depth, a loop's index shared, an absent attribute's text without a Value; runtime Value.clear - benchmark 36 -> 20 KB a frame
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
46888b6716
commit
51a5e06f5c
10 changed files with 43 additions and 5 deletions
|
|
@ -36,6 +36,9 @@ export state UiState {
|
||||||
pl_cur: UiPool = null
|
pl_cur: UiPool = null
|
||||||
mm: UiMemo = null # memo.ludic: splits, gradients and keys by their text
|
mm: UiMemo = null # memo.ludic: splits, gradients and keys by their text
|
||||||
mm_ints: []string = null
|
mm_ints: []string = null
|
||||||
|
mm_ivals: []Val = null
|
||||||
|
ev_depth: int = 0 # eval.ludic: a call's arguments, in lists kept one a depth
|
||||||
|
ev_args: []Val = new []Val
|
||||||
ly_depth: int = 0 # layout_run.ludic: the lists a line lays out with, one a depth
|
ly_depth: int = 0 # layout_run.ludic: the lists a line lays out with, one a depth
|
||||||
ly_sizes: [][]float = new [][]float
|
ly_sizes: [][]float = new [][]float
|
||||||
ly_frozen: [][]bool = new [][]bool
|
ly_frozen: [][]bool = new [][]bool
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ function bd_each(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string, out: []UiN
|
||||||
for j in 0 .. Value.count(list) {
|
for j in 0 .. Value.count(list) {
|
||||||
let le = env_new(ui_st, e)
|
let le = env_new(ui_st, e)
|
||||||
env_bind(le, as_name, Value.at(list, j))
|
env_bind(le, as_name, Value.at(list, j))
|
||||||
env_bind(le, at_name, Value.int(j))
|
env_bind(le, at_name, mm_ival(ui_st, j))
|
||||||
var id = mm_int(ui_st, j)
|
var id = mm_int(ui_st, j)
|
||||||
if by != null { id = ui_eval_text(ui_st, by, le) }
|
if by != null { id = ui_eval_text(ui_st, by, le) }
|
||||||
bd_kids(ui_st, k.kids, le, mm_join(ui_st, key, "#", id), out)
|
bd_kids(ui_st, k.kids, le, mm_join(ui_st, key, "#", id), out)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ function bd_class(ui_st: mut UiState, k: UiTpl, e: UiEnv, key: string, out: []Ui
|
||||||
let cls = k.cls
|
let cls = k.cls
|
||||||
uc_load(ui_st, cls)
|
uc_load(ui_st, cls)
|
||||||
let it = in_get(ui_st, key, cls)
|
let it = in_get(ui_st, key, cls)
|
||||||
let props = Value.object()
|
if it.props == null { it.props = Value.object() }
|
||||||
|
let props = it.props
|
||||||
|
Value.clear(props)
|
||||||
for i in 0 .. len(k.keys) {
|
for i in 0 .. len(k.keys) {
|
||||||
let a = k.keys[i]
|
let a = k.keys[i]
|
||||||
if a != "class" and a != "style" and a != "id" { Value.put(props, a, ui_eval(ui_st, k.vals[i], e)) }
|
if a != "class" and a != "style" and a != "id" { Value.put(props, a, ui_eval(ui_st, k.vals[i], e)) }
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ function el_text(ui_st: mut UiState, n: UiNode, s: string) -> void {
|
||||||
function el_keep(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> void {
|
function el_keep(ui_st: mut UiState, n: UiNode, key: string, v: Val) -> void {
|
||||||
let s = vl_text_u(ui_st, v)
|
let s = vl_text_u(ui_st, v)
|
||||||
if key == "id" { n.id = s } else if key == "class" {
|
if key == "id" { n.id = s } else if key == "class" {
|
||||||
let parts = lss_split(s, 32)
|
let parts = mm_split(ui_st, s, 32)
|
||||||
for i in 0 .. len(parts) {
|
for i in 0 .. len(parts) {
|
||||||
if len(parts[i]) > 0 { push(n.classes, parts[i]) }
|
if len(parts[i]) > 0 { push(n.classes, parts[i]) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,18 @@ function ui_eval(ui_st: mut UiState, x: UiExpr, e: UiEnv) -> Val {
|
||||||
}
|
}
|
||||||
# a call: len() and range() are the template's own, anything else is the view's
|
# a call: len() and range() are the template's own, anything else is the view's
|
||||||
function ev_call(ui_st: mut UiState, x: UiExpr, e: UiEnv) -> Val {
|
function ev_call(ui_st: mut UiState, x: UiExpr, e: UiEnv) -> Val {
|
||||||
let args = Value.list()
|
let depth = ui_st.ev_depth
|
||||||
|
while len(ui_st.ev_args) <= depth { push(ui_st.ev_args, Value.list()) }
|
||||||
|
let args = ui_st.ev_args[depth]
|
||||||
|
Value.clear(args)
|
||||||
|
ui_st.ev_depth = depth + 1
|
||||||
for i in 0 .. len(x.args) { Value.add(args, ui_eval(ui_st, x.args[i], e)) }
|
for i in 0 .. len(x.args) { Value.add(args, ui_eval(ui_st, x.args[i], e)) }
|
||||||
|
let r = ev_call_with(ui_st, x, e, args)
|
||||||
|
ui_st.ev_depth = depth
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
# the call itself, its arguments evaluated; a callee reads them and keeps none
|
||||||
|
function ev_call_with(ui_st: mut UiState, x: UiExpr, e: UiEnv, args: Val) -> Val {
|
||||||
if x.s == "len" and len(x.args) == 1 { return Value.int(Value.count(Value.at(args, 0))) }
|
if x.s == "len" and len(x.args) == 1 { return Value.int(Value.count(Value.at(args, 0))) }
|
||||||
if x.s == "range" and len(x.args) == 1 {
|
if x.s == "range" and len(x.args) == 1 {
|
||||||
let out = Value.list()
|
let out = Value.list()
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ property UiInst {
|
||||||
cls: UiClass = null
|
cls: UiClass = null
|
||||||
ptr: pointer = null
|
ptr: pointer = null
|
||||||
seen: int = 0
|
seen: int = 0
|
||||||
|
props: Val = null # its props, filled again each frame into the same object
|
||||||
}
|
}
|
||||||
function in_get(ui_st: mut UiState, key: string, k: UiClass) -> UiInst {
|
function in_get(ui_st: mut UiState, key: string, k: UiClass) -> UiInst {
|
||||||
for i in 0 .. len(ui_st.in_list) {
|
for i in 0 .. len(ui_st.in_list) {
|
||||||
|
|
|
||||||
|
|
@ -40,3 +40,12 @@ function mm_int(ui_st: mut UiState, i: int) -> string {
|
||||||
}
|
}
|
||||||
return ui_st.mm_ints[i]
|
return ui_st.mm_ints[i]
|
||||||
}
|
}
|
||||||
|
# a small whole number as a Value, made once and shared: read it, never change it (a loop's index)
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,13 @@ export function ui_attr(n: UiNode, key: string) -> Val {
|
||||||
}
|
}
|
||||||
return Value.null()
|
return Value.null()
|
||||||
}
|
}
|
||||||
export function ui_attr_text(n: UiNode, key: string) -> string { return vl_text(ui_attr(n, key)) }
|
export function ui_attr_text(n: UiNode, key: string) -> string {
|
||||||
|
if n.akeys == null { return "" }
|
||||||
|
for i in 0 .. len(n.akeys) {
|
||||||
|
if n.akeys[i] == key { return vl_text(n.vals[i]) }
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
# a boolean attribute: present with no value is true, as HTML's are (<button autofocus>)
|
# a boolean attribute: present with no value is true, as HTML's are (<button autofocus>)
|
||||||
export function ui_attr_on(n: UiNode, key: string) -> bool {
|
export function ui_attr_on(n: UiNode, key: string) -> bool {
|
||||||
if n.akeys == null { return false }
|
if n.akeys == null { return false }
|
||||||
|
|
|
||||||
|
|
@ -479,6 +479,7 @@ namespace Value {
|
||||||
alias as_float(value) = value_as_float
|
alias as_float(value) = value_as_float
|
||||||
alias as_str(value) = value_as_str
|
alias as_str(value) = value_as_str
|
||||||
alias free(value) = value_free
|
alias free(value) = value_free
|
||||||
|
alias clear(value) = value_clear
|
||||||
}
|
}
|
||||||
namespace Json {
|
namespace Json {
|
||||||
alias encode(value) = json_encode
|
alias encode(value) = json_encode
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,12 @@ function value_put(obj: Val, key: pointer, item: Val) -> Val {
|
||||||
# --- accessors --------------------------------------------------------------
|
# --- accessors --------------------------------------------------------------
|
||||||
function value_kind(v: Val) -> int { return v.tag }
|
function value_kind(v: Val) -> int { return v.tag }
|
||||||
function value_count(v: Val) -> int { return value_n(v) }
|
function value_count(v: Val) -> int { return value_n(v) }
|
||||||
|
# a list or an object emptied in place, its room kept - for one filled again every frame
|
||||||
|
function value_clear(v: Val) -> void {
|
||||||
|
if v.kids == null { return }
|
||||||
|
List.clear(v.kids)
|
||||||
|
List.clear(v.keys)
|
||||||
|
}
|
||||||
function value_as_int(v: Val) -> int {
|
function value_as_int(v: Val) -> int {
|
||||||
if v.tag == 7 { return int(float_from_bits(v.num)) }
|
if v.tag == 7 { return int(float_from_bits(v.num)) }
|
||||||
return v.num
|
return v.num
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue