mirror of
https://github.com/littensy/charm.git
synced 2026-10-20 17:51:37 +00:00
perf: simplify mapped logic
This commit is contained in:
parent
f704acce71
commit
b61d0b3b86
2 changed files with 14 additions and 56 deletions
|
|
@ -10,7 +10,7 @@ local function run(name: string, test: () -> ())
|
||||||
table.clear(times)
|
table.clear(times)
|
||||||
table.clear(stack)
|
table.clear(stack)
|
||||||
|
|
||||||
while os.clock() - start < 1 do
|
while os.clock() - start < 2 do
|
||||||
iter += 1
|
iter += 1
|
||||||
test()
|
test()
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,12 @@ type Mapped =
|
||||||
& (<KI, VI, KO, VO>(selector: () -> { [KI]: VI }, mapper: (item: VI, key: KI) -> (VO, KO)) -> () -> { [KO]: VO })
|
& (<KI, VI, KO, VO>(selector: () -> { [KI]: VI }, mapper: (item: VI, key: KI) -> (VO, KO)) -> () -> { [KO]: VO })
|
||||||
& (<K, VI, VO>(selector: () -> { [K]: VI }, mapper: (item: VI, key: K) -> VO) -> () -> { [K]: VO })
|
& (<K, VI, VO>(selector: () -> { [K]: VI }, mapper: (item: VI, key: K) -> VO) -> () -> { [K]: VO })
|
||||||
|
|
||||||
local function ensureCanMutateOutput<KO, VO>(output: { [KO]: VO }, previous: { [KO]: VO }): { [KO]: VO }
|
local function ensureCanMutateOutput<KO, VO>(output: { [KO]: VO }, previous: { [KO]: VO }?): { [KO]: VO }
|
||||||
return if output == previous then table.clone(output) else output
|
return if output == previous then table.clone(output) else output
|
||||||
end
|
end
|
||||||
|
|
||||||
local function mapped<KI, VI, KO, VO>(selector: () -> { [KI]: VI }, mapper: (item: VI, key: KI) -> (VO, KO)): () -> { [KO]: VO }
|
local function mapped<KI, VI, KO, VO>(selector: () -> { [KI]: VI }, mapper: (item: VI, key: KI) -> (VO, KO)): () -> { [KO]: VO }
|
||||||
local currentData: { [KI]: VI }
|
local currentData: { [KI]: VI } = {}
|
||||||
local keyCache: { [KI]: KO } = {}
|
local keyCache: { [KI]: KO } = {}
|
||||||
|
|
||||||
local function map(value: VI, key: KI): (VO, KO)
|
local function map(value: VI, key: KI): (VO, KO)
|
||||||
|
|
@ -31,75 +31,33 @@ local function mapped<KI, VI, KO, VO>(selector: () -> { [KI]: VI }, mapper: (ite
|
||||||
end
|
end
|
||||||
|
|
||||||
return computed(function(previousOutput)
|
return computed(function(previousOutput)
|
||||||
|
local currentOutput: { [KO]: VO } = previousOutput or {}
|
||||||
local previousData = currentData
|
local previousData = currentData
|
||||||
currentData = selector()
|
currentData = selector()
|
||||||
|
|
||||||
-- Only perform additions if this is the first run
|
for key, cachedKey in keyCache do
|
||||||
if not previousOutput then
|
if currentData[key] ~= nil then
|
||||||
local output: { [KO]: VO } = {}
|
continue
|
||||||
|
|
||||||
for key, value in currentData do
|
|
||||||
local valueOut, keyOut = map(value, key)
|
|
||||||
if valueOut ~= nil then
|
|
||||||
output[keyOut] = valueOut
|
|
||||||
keyCache[key] = keyOut
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return output
|
currentOutput = ensureCanMutateOutput(currentOutput, previousOutput)
|
||||||
|
currentOutput[cachedKey] = nil
|
||||||
|
keyCache[key] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local output = previousOutput
|
|
||||||
|
|
||||||
-- Check equality since the selector might not be a computed value
|
|
||||||
if currentData == previousData then
|
|
||||||
return output
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Clear removed values from the output and key cache
|
|
||||||
for key in previousData do
|
|
||||||
if currentData[key] == nil then
|
|
||||||
local keyOut = keyCache[key]
|
|
||||||
if keyOut then
|
|
||||||
output = ensureCanMutateOutput(output, previousOutput)
|
|
||||||
output[keyOut] = nil
|
|
||||||
keyCache[key] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Process new or changed values
|
|
||||||
for key, value in currentData do
|
for key, value in currentData do
|
||||||
if value == previousData[key] then
|
if value == previousData[key] then
|
||||||
continue
|
continue
|
||||||
end
|
end
|
||||||
|
|
||||||
local valueOut, keyOut = map(value, key)
|
local valueOut, keyOut = map(value, key)
|
||||||
local cachedKeyOut = keyCache[key]
|
|
||||||
|
|
||||||
if valueOut ~= nil then
|
currentOutput = ensureCanMutateOutput(currentOutput, previousOutput)
|
||||||
-- Skip update if the key and value are the same
|
currentOutput[keyOut] = valueOut
|
||||||
if keyOut == cachedKeyOut and valueOut == output[cachedKeyOut] then
|
keyCache[key] = keyOut
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
output = ensureCanMutateOutput(output, previousOutput)
|
|
||||||
output[keyOut] = valueOut
|
|
||||||
keyCache[key] = keyOut
|
|
||||||
|
|
||||||
-- Remove the old key if a new key is assigned
|
|
||||||
if cachedKeyOut ~= nil and keyOut ~= cachedKeyOut then
|
|
||||||
output[cachedKeyOut] = nil
|
|
||||||
end
|
|
||||||
elseif cachedKeyOut ~= nil then
|
|
||||||
-- Remove the cached key if the new value is nil
|
|
||||||
output = ensureCanMutateOutput(output, previousOutput)
|
|
||||||
output[cachedKeyOut] = nil
|
|
||||||
keyCache[key] = nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return output
|
return currentOutput
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue