mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
perf(push_child): defer unparent until evaluate, keeping unchanged ordered parents
This commit is contained in:
parent
19eaeb424f
commit
d7df0d9850
1 changed files with 42 additions and 11 deletions
|
|
@ -1,5 +1,8 @@
|
||||||
local flags = require "./flags"
|
local flags = require "./flags"
|
||||||
|
|
||||||
|
local TEMPORALLY_UNPARENTED = -1
|
||||||
|
type TEMPORALLY_UNPARENTED = number
|
||||||
|
|
||||||
export type SourceNode<T> = {
|
export type SourceNode<T> = {
|
||||||
cache: T,
|
cache: T,
|
||||||
[number]: Node<T>
|
[number]: Node<T>
|
||||||
|
|
@ -15,6 +18,7 @@ export type Node<T> = {
|
||||||
owned: { Node<T> } | false,
|
owned: { Node<T> } | false,
|
||||||
owner: Node<T> | false,
|
owner: Node<T> | false,
|
||||||
|
|
||||||
|
pushing_parent_index: number | TEMPORALLY_UNPARENTED,
|
||||||
parents: { SourceNode<T> },
|
parents: { SourceNode<T> },
|
||||||
[number]: Node<T> -- children
|
[number]: Node<T> -- children
|
||||||
}
|
}
|
||||||
|
|
@ -66,11 +70,6 @@ local function assert_stable_scope(): Node<unknown>
|
||||||
return scope
|
return scope
|
||||||
end
|
end
|
||||||
|
|
||||||
local function push_child<T>(parent: SourceNode<any>, child: Node<any>)
|
|
||||||
table.insert(parent, child)
|
|
||||||
table.insert(child.parents, parent)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function push_scope<T>(node: Node<T>)
|
local function push_scope<T>(node: Node<T>)
|
||||||
local n = scopes.n + 1
|
local n = scopes.n + 1
|
||||||
scopes.n = n
|
scopes.n = n
|
||||||
|
|
@ -109,7 +108,22 @@ local function find_and_swap_pop<T>(t: { T }, v: T)
|
||||||
t[n] = nil
|
t[n] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function push_child<T>(parent: SourceNode<any>, child: Node<any>)
|
||||||
|
local parent_index = child.pushing_parent_index
|
||||||
|
local parents = child.parents
|
||||||
|
|
||||||
|
child.pushing_parent_index = parent_index + 1
|
||||||
|
local previous_parent = parents[parent_index]
|
||||||
|
|
||||||
|
if previous_parent == parent then return end
|
||||||
|
parents[parent_index] = parent
|
||||||
|
|
||||||
|
if previous_parent then find_and_swap_pop(previous_parent, child) end
|
||||||
|
table.insert(parent, child)
|
||||||
|
end
|
||||||
|
|
||||||
local function unparent<T>(node: Node<T>)
|
local function unparent<T>(node: Node<T>)
|
||||||
|
if node.pushing_parent_index == TEMPORALLY_UNPARENTED then return end
|
||||||
local parents = node.parents
|
local parents = node.parents
|
||||||
|
|
||||||
for i, parent in parents do
|
for i, parent in parents do
|
||||||
|
|
@ -146,6 +160,14 @@ end
|
||||||
|
|
||||||
local update_queue = { n = 0 } :: { n: number, [number]: Node<any> }
|
local update_queue = { n = 0 } :: { n: number, [number]: Node<any> }
|
||||||
|
|
||||||
|
local function unparent_unuseds<T>(node: Node<T>)
|
||||||
|
local parents = node.parents
|
||||||
|
for i = node.pushing_parent_index+1, #parents do
|
||||||
|
find_and_swap_pop(parents[i], node)
|
||||||
|
parents[i] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function evaluate_node<T>(node: Node<T>)
|
local function evaluate_node<T>(node: Node<T>)
|
||||||
if flags.strict then
|
if flags.strict then
|
||||||
if table.find(scopes, node) then
|
if table.find(scopes, node) then
|
||||||
|
|
@ -159,10 +181,13 @@ local function evaluate_node<T>(node: Node<T>)
|
||||||
|
|
||||||
flush_cleanups(node)
|
flush_cleanups(node)
|
||||||
destroy_owned(node)
|
destroy_owned(node)
|
||||||
|
node.pushing_parent_index = 1
|
||||||
|
|
||||||
push_scope(node)
|
push_scope(node)
|
||||||
local ok, new_value = ycall(node.effect :: (T) -> T, cur_value)
|
local ok, new_value = ycall(node.effect :: (T) -> T, cur_value)
|
||||||
|
|
||||||
pop_scope()
|
pop_scope()
|
||||||
|
unparent_unuseds(node)
|
||||||
|
|
||||||
if not ok then
|
if not ok then
|
||||||
table.clear(update_queue)
|
table.clear(update_queue)
|
||||||
|
|
@ -179,10 +204,13 @@ local function evaluate_node<T>(node: Node<T>)
|
||||||
|
|
||||||
flush_cleanups(node)
|
flush_cleanups(node)
|
||||||
destroy_owned(node)
|
destroy_owned(node)
|
||||||
|
node.pushing_parent_index = 1
|
||||||
|
|
||||||
push_scope(node)
|
push_scope(node)
|
||||||
local ok, new_value = pcall(node.effect :: (T) -> T, node.cache)
|
local ok, new_value = pcall(node.effect :: (T) -> T, node.cache)
|
||||||
|
|
||||||
pop_scope()
|
pop_scope()
|
||||||
|
unparent_unuseds(node)
|
||||||
|
|
||||||
if not ok then
|
if not ok then
|
||||||
table.clear(update_queue)
|
table.clear(update_queue)
|
||||||
|
|
@ -196,13 +224,15 @@ local function evaluate_node<T>(node: Node<T>)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function queue_children_for_update<T>(node: SourceNode<T>)
|
local function queue_children_for_update<T>(node: SourceNode<T>)
|
||||||
local i = update_queue.n
|
local queue_length = update_queue.n
|
||||||
while node[1] do
|
for j = 1, #node do
|
||||||
i += 1
|
if node[j].pushing_parent_index == TEMPORALLY_UNPARENTED then continue end
|
||||||
update_queue[i] = node[1]
|
node[j].pushing_parent_index = TEMPORALLY_UNPARENTED
|
||||||
unparent(node[1])
|
|
||||||
|
queue_length += 1
|
||||||
|
update_queue[queue_length] = node[j]
|
||||||
end
|
end
|
||||||
update_queue.n = i
|
update_queue.n = queue_length
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_update_queue_length()
|
local function get_update_queue_length()
|
||||||
|
|
@ -267,6 +297,7 @@ local function create_node<T>(owner: false | Node<any>, effect: false | (T) -> T
|
||||||
owner = owner,
|
owner = owner,
|
||||||
owned = false,
|
owned = false,
|
||||||
|
|
||||||
|
pushing_parent_index = 1,
|
||||||
parents = {},
|
parents = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue