mirror of
https://github.com/centau/vide.git
synced 2026-08-20 14:41:37 +00:00
This commit is contained in:
parent
e03082c941
commit
fa2709f182
8 changed files with 367 additions and 216 deletions
|
|
@ -32,100 +32,6 @@ Creates a new source state with the given value.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
## derive()
|
|
||||||
|
|
||||||
Derives a new state from existing states.
|
|
||||||
|
|
||||||
- ### Type
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function derive<T>(source: () -> T): () -> T
|
|
||||||
```
|
|
||||||
|
|
||||||
- ### Details
|
|
||||||
|
|
||||||
The derived state will have its value recalculated when any source state it
|
|
||||||
derives from is updated.
|
|
||||||
|
|
||||||
Anytime its value is recalculated it is also cached, subsequent calls will
|
|
||||||
retun this cached value until it recalculates again.
|
|
||||||
|
|
||||||
Takes a callback that is immediately run to determine what states are being
|
|
||||||
referenced.
|
|
||||||
|
|
||||||
> ⚠️ Non-yielding.
|
|
||||||
|
|
||||||
- ### Example
|
|
||||||
|
|
||||||
```lua
|
|
||||||
local count = wrap(0)
|
|
||||||
local text = derive(function() return `count: {count()}` end)
|
|
||||||
|
|
||||||
text() -- "count: 0"
|
|
||||||
|
|
||||||
count(1)
|
|
||||||
|
|
||||||
text() -- "count: 1"
|
|
||||||
```
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
## map()
|
|
||||||
|
|
||||||
Maps each value in a table state to a new table state.
|
|
||||||
|
|
||||||
- ### Type
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function map<KI, VI, VO>(
|
|
||||||
source: () -> Map<KI, VI>,
|
|
||||||
transform: (value: () -> VI, index: KI) -> VO
|
|
||||||
): Map<KI, VO>
|
|
||||||
|
|
||||||
- ### Details
|
|
||||||
|
|
||||||
The transform function is called only ever *once* for each index in the
|
|
||||||
source table. The first argument is a state containing the index's value and
|
|
||||||
the second argument is just the index.
|
|
||||||
|
|
||||||
Anytime a new index is added, the transform function will be called again for
|
|
||||||
that new index.
|
|
||||||
|
|
||||||
Anytime an existing index changes, the transform function is not rerun,
|
|
||||||
instead the passed state for that index will update, causing anything
|
|
||||||
depending on it to update too.
|
|
||||||
|
|
||||||
Returns a state containing the mapped key-value pairs.
|
|
||||||
|
|
||||||
> ⚠️ Non-yielding.
|
|
||||||
|
|
||||||
- ### Example
|
|
||||||
|
|
||||||
```lua
|
|
||||||
type Item = {
|
|
||||||
name: string,
|
|
||||||
icon: number
|
|
||||||
}
|
|
||||||
|
|
||||||
local items = source {} :: () -> Array<Item>
|
|
||||||
|
|
||||||
local displays = map(numbers, function(item, i)
|
|
||||||
return ItemDisplay {
|
|
||||||
Name = function()
|
|
||||||
return item().name
|
|
||||||
end,
|
|
||||||
|
|
||||||
Image = function()
|
|
||||||
return "rbxassetid://" .. item().icon
|
|
||||||
end,
|
|
||||||
|
|
||||||
LayoutOrder = i
|
|
||||||
}
|
|
||||||
end)
|
|
||||||
```
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
## watch()
|
## watch()
|
||||||
|
|
||||||
Runs a callback on state change.
|
Runs a callback on state change.
|
||||||
|
|
@ -166,3 +72,179 @@ Runs a callback on state change.
|
||||||
```
|
```
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## derive()
|
||||||
|
|
||||||
|
Derives a new state from existing states.
|
||||||
|
|
||||||
|
- ### Type
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function derive<T>(source: () -> T): () -> T
|
||||||
|
```
|
||||||
|
|
||||||
|
- ### Details
|
||||||
|
|
||||||
|
The derived state will have its value recalculated when any source state it
|
||||||
|
derives from is updated.
|
||||||
|
|
||||||
|
Anytime its value is recalculated it is also cached, subsequent calls will
|
||||||
|
retun this cached value until it recalculates again.
|
||||||
|
|
||||||
|
Takes a callback that is immediately run to determine what states are being
|
||||||
|
referenced.
|
||||||
|
|
||||||
|
> ⚠️ Non-yielding.
|
||||||
|
|
||||||
|
- ### Example
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local count = wrap(0)
|
||||||
|
local text = derive(function() return `count: {count()}` end)
|
||||||
|
|
||||||
|
text() -- "count: 0"
|
||||||
|
|
||||||
|
count(1)
|
||||||
|
|
||||||
|
text() -- "count: 1"
|
||||||
|
```
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## indexes()
|
||||||
|
|
||||||
|
Maps each index in a table to an object.
|
||||||
|
|
||||||
|
- ### Type
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function indexes<KI, VI, VO>(
|
||||||
|
source: () -> Map<KI, VI>,
|
||||||
|
transform: (value: () -> VI, index: KI) -> VO
|
||||||
|
): Array<VO>
|
||||||
|
|
||||||
|
- ### Details
|
||||||
|
|
||||||
|
The transform function is called only ever *once* for each index in the
|
||||||
|
source table. The first argument is a state containing the index's value and
|
||||||
|
the second argument is just the index.
|
||||||
|
|
||||||
|
Anytime a new index is added, the transform function will be called again for
|
||||||
|
that new index.
|
||||||
|
|
||||||
|
Anytime an existing index value changes, the transform function is not rerun,
|
||||||
|
instead the passed state for that index will update, causing anything
|
||||||
|
depending on it to update too.
|
||||||
|
|
||||||
|
Returns a state containing an array of all objects returned by the transform.
|
||||||
|
|
||||||
|
> ⚠️ Non-yielding.
|
||||||
|
|
||||||
|
- ### Example
|
||||||
|
|
||||||
|
The intended purpose of this function is to map each index in a table to
|
||||||
|
a UI element.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
type Item = {
|
||||||
|
name: string,
|
||||||
|
icon: number
|
||||||
|
}
|
||||||
|
|
||||||
|
local items = source {} :: () -> Array<Item>
|
||||||
|
|
||||||
|
local displays = indexes(numbers, function(item, i)
|
||||||
|
return ItemDisplay {
|
||||||
|
Name = function()
|
||||||
|
return item().name
|
||||||
|
end,
|
||||||
|
|
||||||
|
Image = function()
|
||||||
|
return "rbxassetid://" .. item().icon
|
||||||
|
end,
|
||||||
|
|
||||||
|
LayoutOrder = i
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## values()
|
||||||
|
|
||||||
|
Maps each value in a table to an object.
|
||||||
|
|
||||||
|
- ### Type
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function values<KI, VI, VO>(
|
||||||
|
source: () -> Map<KI, VI>,
|
||||||
|
transform: (value: VI, index: () -> KI) -> VO
|
||||||
|
): Array<VO>
|
||||||
|
|
||||||
|
- ### Details
|
||||||
|
|
||||||
|
The transform function is called only ever *once* for each value in the
|
||||||
|
source table. The first argument is the index's value and
|
||||||
|
the second argument is a state containing the index.
|
||||||
|
|
||||||
|
Anytime a new value is added, the transform function will be called again
|
||||||
|
for that new value.
|
||||||
|
|
||||||
|
Anytime an existing value's index changes, the transform function is not
|
||||||
|
rerun, instead the passed state for that value will update, causing anything
|
||||||
|
depending on it to update too.
|
||||||
|
|
||||||
|
Returns a state containing an array of all objects returned by the transform.
|
||||||
|
|
||||||
|
> ⚠️ Non-yielding.
|
||||||
|
|
||||||
|
- ### Example
|
||||||
|
|
||||||
|
The intended purpose of this function is to map each value in a table to
|
||||||
|
a UI element.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
type Item = {
|
||||||
|
name: string,
|
||||||
|
icon: number
|
||||||
|
}
|
||||||
|
|
||||||
|
local items = source {} :: () -> Array<Item>
|
||||||
|
|
||||||
|
local displays = values(numbers, function(item, i)
|
||||||
|
return ItemDisplay {
|
||||||
|
Name = item.Name
|
||||||
|
|
||||||
|
Image = "rbxassetid://" .. item.icon,
|
||||||
|
|
||||||
|
LayoutOrder = i
|
||||||
|
}
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
- ### Extra
|
||||||
|
|
||||||
|
When should you use `indexes()` and `values()`?
|
||||||
|
|
||||||
|
`values()` should be used when you have a fixed set of objects where the
|
||||||
|
same objects can be re-arranged in the source table. It maps a value to a
|
||||||
|
UI element.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
- List of all players.
|
||||||
|
- Inventory of items.
|
||||||
|
- Chat message history.
|
||||||
|
- Toast notifications.
|
||||||
|
|
||||||
|
`indexes()` should be used in other cases, especially when your source table
|
||||||
|
has primitive value. It maps an index to a UI element.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
- List of character or weapon stats.
|
||||||
|
|
||||||
|
In most cases, both functions will appear to have the same behavior.
|
||||||
|
The main difference is performance, picking the right function to use can
|
||||||
|
result in less property updates and less re-renders.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ type Item = {
|
||||||
local items = source({} :: Array<Item>)
|
local items = source({} :: Array<Item>)
|
||||||
|
|
||||||
List {
|
List {
|
||||||
Children = map(items, function(item, i)
|
Children = indexes(items, function(item, i)
|
||||||
return create "ImageLabel" {
|
return create "ImageLabel" {
|
||||||
Image = function()
|
Image = function()
|
||||||
return "rbxassetid://" .. item().Icon
|
return "rbxassetid://" .. item().Icon
|
||||||
|
|
|
||||||
|
|
@ -88,32 +88,32 @@ local function bind_parent(instance: Instance, fn: () -> Instance?)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function bind_children(parent: Instance, fn: () -> { Instance })
|
local function bind_children(parent: Instance, fn: () -> { Instance })
|
||||||
local currentChildrenSet: { [Instance]: true } = {} -- cache of all children parented before update
|
local current_child_set: { [Instance]: true } = {} -- cache of all children parented before update
|
||||||
local newChildrenSet: { [Instance]: true } = {} -- cache of all children parented after update
|
local new_child_set: { [Instance]: true } = {} -- cache of all children parented after update
|
||||||
|
|
||||||
setup(parent, function(parent_weak)
|
setup(parent, function(parent_weak)
|
||||||
local newChildren = fn() -- all (and only) children that should be parented after this update
|
local new_childs = fn() -- all (and only) children that should be parented after this update
|
||||||
if newChildren and type(newChildren) ~= "table" then
|
if new_childs and type(new_childs) ~= "table" then
|
||||||
throw(`Cannot parent instance of type { type(newChildren) } `)
|
throw(`Cannot parent instance of type { type(new_childs) } `)
|
||||||
end
|
end
|
||||||
|
|
||||||
if newChildren then
|
if new_childs then
|
||||||
for _, child in next, newChildren do
|
for _, child in next, new_childs do
|
||||||
newChildrenSet[child] = true -- record child set from this update
|
new_child_set[child] = true -- record child set from this update
|
||||||
if not currentChildrenSet[child] then
|
if not current_child_set[child] then
|
||||||
child.Parent = parent_weak -- if child wasn't already parented then parent it
|
child.Parent = parent_weak -- if child wasn't already parented then parent it
|
||||||
else
|
else
|
||||||
currentChildrenSet[child] = nil -- remove child from cache if it was already in cache
|
current_child_set[child] = nil -- remove child from cache if it was already in cache
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
for child in next, currentChildrenSet do
|
for child in next, current_child_set do
|
||||||
child.Parent = nil -- unparent all children that weren't in the new children set
|
child.Parent = nil -- unparent all children that weren't in the new children set
|
||||||
end
|
end
|
||||||
|
|
||||||
table.clear(currentChildrenSet) -- clear cache, preserve capacity
|
table.clear(current_child_set) -- clear cache, preserve capacity
|
||||||
currentChildrenSet, newChildrenSet = newChildrenSet, currentChildrenSet
|
current_child_set, new_child_set = new_child_set, current_child_set
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
65
src/map.luau
65
src/map.luau
|
|
@ -1,65 +0,0 @@
|
||||||
if not game then script = (require :: any) "test/wrap-require" end
|
|
||||||
|
|
||||||
local graph = require(script.Parent.graph)
|
|
||||||
type Node<T> = graph.Node<T>
|
|
||||||
local create = graph.create
|
|
||||||
local set = graph.set
|
|
||||||
local capture = graph.capture
|
|
||||||
local link = graph.link
|
|
||||||
|
|
||||||
type Map<K, V> = { [K]: V }
|
|
||||||
|
|
||||||
local function map<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI, K) -> VO): () -> Map<K, VO>
|
|
||||||
local input_cache = {} :: Map<K, VI>
|
|
||||||
local output_cache = {} :: Map<K, VO>
|
|
||||||
local input_nodes = {} :: Map<K, Node<VI>>
|
|
||||||
local remove_queue = {} :: { K }
|
|
||||||
|
|
||||||
local function recompute(data)
|
|
||||||
-- queue removed values
|
|
||||||
for k in next, input_cache do
|
|
||||||
if data[k] == nil then
|
|
||||||
table.insert(remove_queue, k)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- remove queued values
|
|
||||||
for _, k in next, remove_queue do
|
|
||||||
input_cache[k] = nil
|
|
||||||
output_cache[k] = nil
|
|
||||||
input_nodes[k] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- process new or changed values
|
|
||||||
for k, v in next, data do
|
|
||||||
if input_cache[k] == nil then
|
|
||||||
local node, get_value = create(v)
|
|
||||||
input_nodes[k] = node
|
|
||||||
output_cache[k] = transform(get_value, k)
|
|
||||||
elseif input_cache[k] ~= v then
|
|
||||||
set(input_nodes[k], v)
|
|
||||||
end
|
|
||||||
input_cache[k] = v
|
|
||||||
end
|
|
||||||
|
|
||||||
return output_cache
|
|
||||||
end
|
|
||||||
|
|
||||||
local function derive()
|
|
||||||
return recompute(input())
|
|
||||||
end
|
|
||||||
|
|
||||||
local output, output_get = create(output_cache)
|
|
||||||
|
|
||||||
local nodes, value = capture(input)
|
|
||||||
|
|
||||||
for _, node in next, nodes do
|
|
||||||
link(node, output, derive)
|
|
||||||
end
|
|
||||||
|
|
||||||
output.cache = recompute(value)
|
|
||||||
|
|
||||||
return output_get
|
|
||||||
end
|
|
||||||
|
|
||||||
return map
|
|
||||||
|
|
@ -9,13 +9,13 @@ local link = graph.link
|
||||||
|
|
||||||
type Map<K, V> = { [K]: V }
|
type Map<K, V> = { [K]: V }
|
||||||
|
|
||||||
-- todo: optimize, double buffering?
|
-- todo: this could be optimized
|
||||||
|
|
||||||
local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI, K) -> VO): () -> { VO }
|
local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI, K) -> VO): () -> { VO }
|
||||||
local input_cache = {} :: Map<K, VI>
|
local input_cache = {} :: Map<K, VI>
|
||||||
local output_cache = {} :: Map<K, VO>
|
local output_cache = {} :: Map<K, VO>
|
||||||
local input_nodes = {} :: Map<K, Node<VI>>
|
local input_nodes = {} :: Map<K, Node<VI>>
|
||||||
local remove_queue = {} :: { K }
|
local remove_queue = {} :: { K }
|
||||||
|
local output_array = {} :: { VO }
|
||||||
|
|
||||||
local function recompute(data)
|
local function recompute(data)
|
||||||
-- queue removed values
|
-- queue removed values
|
||||||
|
|
@ -34,23 +34,25 @@ local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI,
|
||||||
|
|
||||||
-- process new or changed values
|
-- process new or changed values
|
||||||
for k, v in next, data do
|
for k, v in next, data do
|
||||||
if input_cache[k] == nil then
|
local cv = input_cache[k]
|
||||||
|
if cv == nil then
|
||||||
local node, get_value = create(v)
|
local node, get_value = create(v)
|
||||||
input_nodes[k] = node
|
input_nodes[k] = node
|
||||||
output_cache[k] = transform(get_value, k)
|
output_cache[k] = transform(get_value, k)
|
||||||
elseif input_cache[k] ~= v then
|
input_cache[k] = v
|
||||||
|
elseif cv ~= v then
|
||||||
set(input_nodes[k], v)
|
set(input_nodes[k], v)
|
||||||
end
|
|
||||||
input_cache[k] = v
|
input_cache[k] = v
|
||||||
end
|
end
|
||||||
|
|
||||||
local output = {}
|
|
||||||
|
|
||||||
for _, v in next, output_cache do
|
|
||||||
table.insert(output, v)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return output
|
-- output elements
|
||||||
|
table.clear(output_array)
|
||||||
|
for _, v in next, output_cache do
|
||||||
|
table.insert(output_array, v)
|
||||||
|
end
|
||||||
|
|
||||||
|
return output_array
|
||||||
end
|
end
|
||||||
|
|
||||||
local function derive()
|
local function derive()
|
||||||
|
|
@ -70,50 +72,54 @@ local function indexes<K, VI, VO>(input: () -> Map<K, VI>, transform: (() -> VI,
|
||||||
return output_get
|
return output_get
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- todo: this should be optimized
|
||||||
local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () -> K) -> VO): () -> { VO }
|
local function values<K, VI, VO>(input: () -> Map<K, VI>, transform: (VI, () -> K) -> VO): () -> { VO }
|
||||||
local input_cache = {} :: Map<VI, K>
|
local input_cache_up = {} :: Map<VI, K>
|
||||||
|
local input_cache_buffer_up = {} :: Map<VI, K>
|
||||||
|
|
||||||
local output_cache = {} :: Map<VI, VO>
|
local output_cache = {} :: Map<VI, VO>
|
||||||
local input_nodes = {} :: Map<VI, Node<K>>
|
local input_nodes = {} :: Map<VI, Node<K>>
|
||||||
local remove_queue = {} :: { VI }
|
local output_array = {} :: { VO }
|
||||||
|
|
||||||
local function recompute(data: Map<K, VI>)
|
local function recompute(data: Map<K, VI>)
|
||||||
local inverted_data = {}
|
local input_cache, input_cache_buffer =
|
||||||
|
input_cache_up, input_cache_buffer_up
|
||||||
|
|
||||||
-- process new or changed values
|
-- process new or changed values
|
||||||
for i, v in next, data do
|
for i, v in next, data do
|
||||||
if input_cache[v] == nil then
|
local cv = input_cache[v]
|
||||||
|
|
||||||
|
if cv == nil then
|
||||||
local node, get_value = create(i)
|
local node, get_value = create(i)
|
||||||
input_nodes[v] = node
|
input_nodes[v] = node
|
||||||
input_cache[v] = i
|
|
||||||
output_cache[v] = transform(v, get_value)
|
output_cache[v] = transform(v, get_value)
|
||||||
elseif input_cache[v] ~= i then
|
elseif cv ~= i then
|
||||||
set(input_nodes[v], i)
|
set(input_nodes[v], i)
|
||||||
end
|
end
|
||||||
|
|
||||||
inverted_data[v] = i
|
input_cache_buffer[v] = i
|
||||||
end
|
end
|
||||||
|
|
||||||
-- queue removed values
|
-- remove old values
|
||||||
for v, k in next, input_cache do
|
for v, k in next, input_cache do
|
||||||
if inverted_data[v] == nil then
|
if input_cache_buffer[v] == nil then
|
||||||
table.insert(remove_queue, v)
|
output_cache[v] = nil
|
||||||
|
input_nodes[v] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- remove queued values
|
-- update buffer cache
|
||||||
for _, k in next, remove_queue do
|
table.clear(input_cache)
|
||||||
input_cache[k] = nil
|
input_cache_up, input_cache_buffer_up = input_cache_buffer, input_cache
|
||||||
output_cache[k] = nil
|
|
||||||
input_nodes[k] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local output = {}
|
-- output elements
|
||||||
|
table.clear(output_array)
|
||||||
|
|
||||||
for _, v in next, output_cache do
|
for _, v in next, output_cache do
|
||||||
table.insert(output, v)
|
table.insert(output_array, v)
|
||||||
end
|
end
|
||||||
|
|
||||||
return output
|
return output_array
|
||||||
end
|
end
|
||||||
|
|
||||||
local function derive()
|
local function derive()
|
||||||
|
|
|
||||||
|
|
@ -176,9 +176,9 @@ local function update_springs(dt: number)
|
||||||
|
|
||||||
set(output, value)
|
set(output, value)
|
||||||
|
|
||||||
if new_alpha > 0.9 then
|
-- if new_alpha > 0.9 then
|
||||||
table.insert(remove_queue, data)
|
-- table.insert(remove_queue, data)
|
||||||
end
|
-- end
|
||||||
end
|
end
|
||||||
|
|
||||||
for _, data in next, remove_queue do
|
for _, data in next, remove_queue do
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ local BENCH, START = require("test/testkit").benchmark()
|
||||||
|
|
||||||
local vide = require "src/init"
|
local vide = require "src/init"
|
||||||
|
|
||||||
local N = 1e6
|
local N = 2^18 -- 262144
|
||||||
|
|
||||||
BENCH("Create state", function()
|
BENCH("Create state", function()
|
||||||
local cache = table.create(N)
|
local cache = table.create(N)
|
||||||
|
|
@ -17,7 +17,7 @@ BENCH("Create state", function()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
BENCH("Get state value", function()
|
BENCH("Get value", function()
|
||||||
local state = vide.source(1)
|
local state = vide.source(1)
|
||||||
|
|
||||||
for i = 1, START(N) do
|
for i = 1, START(N) do
|
||||||
|
|
@ -25,7 +25,7 @@ BENCH("Get state value", function()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
BENCH("Set state value", function()
|
BENCH("Set value", function()
|
||||||
local state = vide.source(1)
|
local state = vide.source(1)
|
||||||
|
|
||||||
for i = 1, START(N) do
|
for i = 1, START(N) do
|
||||||
|
|
@ -45,20 +45,22 @@ BENCH("Derive 1 state", function()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
BENCH("Derive 2 states", function()
|
BENCH("Derive 4 states", function()
|
||||||
local cache = table.create(N)
|
local cache = table.create(N)
|
||||||
local state = vide.source(1)
|
local state = vide.source(1)
|
||||||
local state2 = vide.source(2)
|
local state2 = vide.source(2)
|
||||||
|
local state3 = vide.source(3)
|
||||||
|
local state4 = vide.source(4)
|
||||||
local derive = vide.derive
|
local derive = vide.derive
|
||||||
|
|
||||||
for i = 1, START(N) do
|
for i = 1, START(N) do
|
||||||
cache[i] = derive(function()
|
cache[i] = derive(function()
|
||||||
return state() + state2()
|
return state() + state2() + state3() + state4()
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
BENCH("Set state value derived", function()
|
BENCH("Set derived value", function()
|
||||||
local state = vide.source(1)
|
local state = vide.source(1)
|
||||||
local _derived = vide.derive(state)
|
local _derived = vide.derive(state)
|
||||||
|
|
||||||
|
|
@ -67,7 +69,16 @@ BENCH("Set state value derived", function()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
BENCH("Apply 4 properties", function()
|
BENCH("Apply 0 properties", function()
|
||||||
|
local apply = require "src/apply"
|
||||||
|
local instance = vide.create("Frame") {}
|
||||||
|
|
||||||
|
for i = 1, START(N) do
|
||||||
|
apply(instance, {})
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
BENCH("Apply 8 properties", function()
|
||||||
local apply = require "src/apply"
|
local apply = require "src/apply"
|
||||||
local instance = vide.create("Frame") {}
|
local instance = vide.create("Frame") {}
|
||||||
|
|
||||||
|
|
@ -76,7 +87,11 @@ BENCH("Apply 4 properties", function()
|
||||||
Name = i,
|
Name = i,
|
||||||
Name2 = i,
|
Name2 = i,
|
||||||
Name3 = i,
|
Name3 = i,
|
||||||
Name4 = i
|
Name4 = i,
|
||||||
|
Name5 = i,
|
||||||
|
Name6 = i,
|
||||||
|
Name7 = i,
|
||||||
|
Name8 = i,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
@ -93,4 +108,99 @@ BENCH("Bind state", function()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
BENCH("Update binding", function()
|
||||||
|
local apply = require "src/apply"
|
||||||
|
local instance = vide.create("Frame") {}
|
||||||
|
local state = vide.source(1)
|
||||||
|
|
||||||
|
apply(instance, {
|
||||||
|
Name = state
|
||||||
|
})
|
||||||
|
|
||||||
|
for i = 1, START(N) do
|
||||||
|
state(i)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
BENCH("indexes() no change", function()
|
||||||
|
local data = {}
|
||||||
|
|
||||||
|
for i = 1, N do
|
||||||
|
data[i] = i
|
||||||
|
end
|
||||||
|
|
||||||
|
local state = vide.source(data)
|
||||||
|
|
||||||
|
local _list = vide.values(state, function(v, i)
|
||||||
|
return {}
|
||||||
|
end)
|
||||||
|
|
||||||
|
START(N)
|
||||||
|
|
||||||
|
state(data)
|
||||||
|
end)
|
||||||
|
|
||||||
|
BENCH("indexes() all change", function()
|
||||||
|
local data = {}
|
||||||
|
|
||||||
|
for i = 1, N do
|
||||||
|
data[i] = i
|
||||||
|
end
|
||||||
|
|
||||||
|
local state = vide.source(data)
|
||||||
|
|
||||||
|
local _list = vide.values(state, function(v, i)
|
||||||
|
return {}
|
||||||
|
end)
|
||||||
|
|
||||||
|
for i, v in data do
|
||||||
|
data[i] = v + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
START(N)
|
||||||
|
|
||||||
|
state(data)
|
||||||
|
end)
|
||||||
|
|
||||||
|
BENCH("values() no change", function()
|
||||||
|
local data = {}
|
||||||
|
|
||||||
|
for i = 1, N do
|
||||||
|
data[i] = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local state = vide.source(data)
|
||||||
|
|
||||||
|
local _list = vide.values(state, function(v, i)
|
||||||
|
return {}
|
||||||
|
end)
|
||||||
|
|
||||||
|
START(N)
|
||||||
|
|
||||||
|
state(data)
|
||||||
|
end)
|
||||||
|
|
||||||
|
BENCH("values() all change", function()
|
||||||
|
local data = {}
|
||||||
|
|
||||||
|
for i = 1, N do
|
||||||
|
data[i] = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local state = vide.source(data)
|
||||||
|
|
||||||
|
local _list = vide.values(state, function(v, i)
|
||||||
|
return {}
|
||||||
|
end)
|
||||||
|
|
||||||
|
for i = 1, N do
|
||||||
|
local r = math.random(1, #data)
|
||||||
|
data[i], data[r] = data[r], data[i]
|
||||||
|
end
|
||||||
|
|
||||||
|
START(N)
|
||||||
|
|
||||||
|
state(data)
|
||||||
|
end)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -1054,15 +1054,33 @@ TEST("values()", function()
|
||||||
local input = source { 1, 2, 3 }
|
local input = source { 1, 2, 3 }
|
||||||
|
|
||||||
local output = values(input, function(v, i)
|
local output = values(input, function(v, i)
|
||||||
return v
|
return { v = v, i = i }
|
||||||
end)
|
end)
|
||||||
|
|
||||||
input { 1, 2 }
|
input { 1, 2 }
|
||||||
|
|
||||||
local t = output()
|
local t = output()
|
||||||
|
|
||||||
CHECK(t[1] == 1)
|
CHECK(t[1].v == 1)
|
||||||
CHECK(t[2] == 2)
|
CHECK(t[2].v == 2)
|
||||||
|
CHECK(t[3] == nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
do CASE "Removal reflected 2"
|
||||||
|
local input = source { 1 }
|
||||||
|
|
||||||
|
local output = values(input, function(v, i)
|
||||||
|
return { v = v, i = i }
|
||||||
|
end)
|
||||||
|
|
||||||
|
input { 2, 1 }
|
||||||
|
input { 1 }
|
||||||
|
|
||||||
|
local t = output()
|
||||||
|
|
||||||
|
CHECK(t[1].v == 1)
|
||||||
|
CHECK(t[1].i() == 1)
|
||||||
|
CHECK(t[2] == nil)
|
||||||
CHECK(t[3] == nil)
|
CHECK(t[3] == nil)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue