mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
draft fix approach 2
This commit is contained in:
parent
37e8e05206
commit
121b30393c
4 changed files with 58 additions and 17 deletions
|
|
@ -11,6 +11,7 @@ local function derive<T>(source: () -> T): () -> T
|
||||||
|
|
||||||
return function()
|
return function()
|
||||||
push_child_to_scope(node)
|
push_child_to_scope(node)
|
||||||
|
evaluate_node(node)
|
||||||
return node.cache
|
return node.cache
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
local flags = require "./flags"
|
local flags = require "./flags"
|
||||||
|
local update_id = 0
|
||||||
|
|
||||||
export type SourceNode<T> = {
|
export type SourceNode<T> = {
|
||||||
cache: T,
|
cache: T,
|
||||||
|
needs_queue_children: boolean,
|
||||||
[number]: Node<T>
|
[number]: Node<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Node<T> = {
|
export type Node<T> = {
|
||||||
cache: T,
|
cache: T,
|
||||||
|
last_eval_update_id: number,
|
||||||
|
needs_queue_children: boolean,
|
||||||
effect: ((T) -> T) | false,
|
effect: ((T) -> T) | false,
|
||||||
cleanups: { () -> () } | false,
|
cleanups: { () -> () } | false,
|
||||||
|
|
||||||
|
|
@ -147,6 +151,7 @@ end
|
||||||
local update_queue = { n = 0 } :: { n: number, [number]: Node<any> }
|
local update_queue = { n = 0 } :: { n: number, [number]: Node<any> }
|
||||||
|
|
||||||
local function evaluate_node<T>(node: Node<T>)
|
local function evaluate_node<T>(node: Node<T>)
|
||||||
|
if update_id == node.last_eval_update_id then return node.needs_queue_children end
|
||||||
if flags.strict then
|
if flags.strict then
|
||||||
local initial_value = node.cache
|
local initial_value = node.cache
|
||||||
|
|
||||||
|
|
@ -169,7 +174,10 @@ local function evaluate_node<T>(node: Node<T>)
|
||||||
node.cache = new_value :: T
|
node.cache = new_value :: T
|
||||||
end
|
end
|
||||||
|
|
||||||
return initial_value ~= node.cache
|
local needs_queue_children = initial_value ~= node.cache
|
||||||
|
node.needs_queue_children = needs_queue_children
|
||||||
|
node.last_eval_update_id = update_id
|
||||||
|
return needs_queue_children
|
||||||
else
|
else
|
||||||
local cur_value = node.cache
|
local cur_value = node.cache
|
||||||
|
|
||||||
|
|
@ -185,18 +193,24 @@ local function evaluate_node<T>(node: Node<T>)
|
||||||
update_queue.n = 0
|
update_queue.n = 0
|
||||||
error(`effect error:\n{new_value}\n`, 0)
|
error(`effect error:\n{new_value}\n`, 0)
|
||||||
end
|
end
|
||||||
|
local needs_queue_children = cur_value ~= new_value
|
||||||
|
node.needs_queue_children = needs_queue_children
|
||||||
|
node.last_eval_update_id = update_id
|
||||||
node.cache = new_value
|
node.cache = new_value
|
||||||
return cur_value ~= new_value
|
return needs_queue_children
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function queue_children_for_update<T>(node: SourceNode<T>)
|
local function queue_children_for_update<T>(node: SourceNode<T>)
|
||||||
|
node.needs_queue_children = false
|
||||||
local i = update_queue.n
|
local i = update_queue.n
|
||||||
while node[1] do
|
local j = 1
|
||||||
|
|
||||||
|
while node[j] do
|
||||||
|
if node[j].last_eval_update_id == update_id then j += 1; continue end
|
||||||
i += 1
|
i += 1
|
||||||
update_queue[i] = node[1]
|
update_queue[i] = node[j]
|
||||||
unparent(node[1])
|
unparent(node[j])
|
||||||
end
|
end
|
||||||
update_queue.n = i
|
update_queue.n = i
|
||||||
end
|
end
|
||||||
|
|
@ -222,8 +236,9 @@ local function flush_update_queue(from: number)
|
||||||
update_queue.n = from
|
update_queue.n = from
|
||||||
end
|
end
|
||||||
|
|
||||||
local function update_descendants<T>(root: SourceNode<T>)
|
local function update_descendants<T>(root: SourceNode<T>, is_root_update: boolean?)
|
||||||
local n0 = update_queue.n
|
local n0 = update_queue.n
|
||||||
|
if is_root_update then update_id += 1 end
|
||||||
queue_children_for_update(root)
|
queue_children_for_update(root)
|
||||||
|
|
||||||
if flags.batch then return end
|
if flags.batch then return end
|
||||||
|
|
@ -258,6 +273,8 @@ local function create_node<T>(owner: false | Node<any>, effect: false | (T) -> T
|
||||||
effect = effect,
|
effect = effect,
|
||||||
cleanups = false,
|
cleanups = false,
|
||||||
|
|
||||||
|
needs_queue_children = false,
|
||||||
|
last_eval_update_id = 0,
|
||||||
context = false,
|
context = false,
|
||||||
|
|
||||||
owner = owner,
|
owner = owner,
|
||||||
|
|
@ -278,7 +295,7 @@ local function create_node<T>(owner: false | Node<any>, effect: false | (T) -> T
|
||||||
end
|
end
|
||||||
|
|
||||||
local function create_source_node<T>(value: T): SourceNode<T>
|
local function create_source_node<T>(value: T): SourceNode<T>
|
||||||
return { cache = value }
|
return { cache = value, needs_queue_children = false }
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_children<T>(node: Node<T>): { Node<unknown> }
|
local function get_children<T>(node: Node<T>): { Node<unknown> }
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ local function source<T>(initial_value: T): Source<T>
|
||||||
end
|
end
|
||||||
|
|
||||||
node.cache = v
|
node.cache = v
|
||||||
update_descendants(node)
|
update_descendants(node, true)
|
||||||
return v
|
return v
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,9 +98,9 @@ TEST("graph", function()
|
||||||
pop_scope()
|
pop_scope()
|
||||||
|
|
||||||
CHECK(count == 1)
|
CHECK(count == 1)
|
||||||
update_descendants(a)
|
update_descendants(a, true)
|
||||||
CHECK(count == 2)
|
CHECK(count == 2)
|
||||||
update_descendants(b)
|
update_descendants(b, true)
|
||||||
CHECK(count == 3)
|
CHECK(count == 3)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -119,7 +119,7 @@ TEST("graph", function()
|
||||||
push_scope(c); push_child_to_scope(a); pop_scope()
|
push_scope(c); push_child_to_scope(a); pop_scope()
|
||||||
push_scope(d); push_child_to_scope(b); push_child_to_scope(c); pop_scope()
|
push_scope(d); push_child_to_scope(b); push_child_to_scope(c); pop_scope()
|
||||||
|
|
||||||
update_descendants(a)
|
update_descendants(a, true)
|
||||||
|
|
||||||
CHECK(b_cnt == 1)
|
CHECK(b_cnt == 1)
|
||||||
CHECK(c_cnt == 1)
|
CHECK(c_cnt == 1)
|
||||||
|
|
@ -138,7 +138,7 @@ TEST("graph", function()
|
||||||
|
|
||||||
push_scope(c); assert(type(c.effect) == "function" and c.effect)(NIL); pop_scope()
|
push_scope(c); assert(type(c.effect) == "function" and c.effect)(NIL); pop_scope()
|
||||||
|
|
||||||
update_descendants(a)
|
update_descendants(a, true)
|
||||||
|
|
||||||
CHECK(#get_children(a) == 1)
|
CHECK(#get_children(a) == 1)
|
||||||
CHECK(#get_children(b) == 1)
|
CHECK(#get_children(b) == 1)
|
||||||
|
|
@ -286,14 +286,14 @@ TEST("graph", function()
|
||||||
local a, b, c, d, e, f = node(root), node(root), node(root), node(root), node(root), node(root)
|
local a, b, c, d, e, f = node(root), node(root), node(root), node(root), node(root), node(root)
|
||||||
|
|
||||||
function b.effect(x)
|
function b.effect(x)
|
||||||
update_descendants(d)
|
update_descendants(d, true)
|
||||||
return not x
|
return not x
|
||||||
end
|
end
|
||||||
|
|
||||||
push_child(a, b); push_child(a, c)
|
push_child(a, b); push_child(a, c)
|
||||||
push_child(d, e); push_child(d, f)
|
push_child(d, e); push_child(d, f)
|
||||||
|
|
||||||
update_descendants(a)
|
update_descendants(a, true)
|
||||||
|
|
||||||
CHECK(true)
|
CHECK(true)
|
||||||
end
|
end
|
||||||
|
|
@ -2517,6 +2517,29 @@ TEST("graph edge cases", wrap_root(function()
|
||||||
local effect = vide.effect
|
local effect = vide.effect
|
||||||
local root = vide.root
|
local root = vide.root
|
||||||
|
|
||||||
|
do CASE "brother requires older brother"
|
||||||
|
--[[
|
||||||
|
A
|
||||||
|
^ ^
|
||||||
|
B <-- C
|
||||||
|
]]
|
||||||
|
|
||||||
|
local count = { b = 0, c = 0 }
|
||||||
|
local a = source(0)
|
||||||
|
local b
|
||||||
|
|
||||||
|
local function upd_c() count.c += 1; return a()* (b and b() or 0) end
|
||||||
|
local c = derive(upd_c)
|
||||||
|
|
||||||
|
local function upd_b() count.b += 1; return a()*2 end
|
||||||
|
b = derive(upd_b)
|
||||||
|
|
||||||
|
a(2)
|
||||||
|
print('CAVALO', count.b, count.c)
|
||||||
|
CHECK(count.b == 2)
|
||||||
|
CHECK(count.c == 2)
|
||||||
|
end
|
||||||
|
|
||||||
do CASE "diamond A,B,C,D"
|
do CASE "diamond A,B,C,D"
|
||||||
--[[
|
--[[
|
||||||
|
|
||||||
|
|
@ -2577,14 +2600,14 @@ TEST("graph edge cases", wrap_root(function()
|
||||||
CHECK(count.b == 2)
|
CHECK(count.b == 2)
|
||||||
CHECK(count.c == 2)
|
CHECK(count.c == 2)
|
||||||
CHECK(count.d == 2)
|
CHECK(count.d == 2)
|
||||||
CHECK(count.e == 3) -- todo: redundant re-eval
|
CHECK(count.e == 2)
|
||||||
CHECK(e() == 4)
|
CHECK(e() == 4)
|
||||||
|
|
||||||
a(3)
|
a(3)
|
||||||
CHECK(count.b == 2)
|
CHECK(count.b == 2)
|
||||||
CHECK(count.c == 3)
|
CHECK(count.c == 3)
|
||||||
CHECK(count.d == 3)
|
CHECK(count.d == 3)
|
||||||
CHECK(count.e == 4)
|
CHECK(count.e == 3)
|
||||||
CHECK(e() == 12)
|
CHECK(e() == 12)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue