Fix recursive tracking

This commit is contained in:
Gabriel Tofvesson 2024-10-14 12:59:37 +02:00
parent 5b11cb12f5
commit 053b59cf00

View File

@ -73,7 +73,7 @@ end
local RecursionSentinel = {} local RecursionSentinel = {}
function RecursionSentinel.make(table, index) function RecursionSentinel.make(table, index)
local obj = { table = table } local obj = { table = table, index = index }
setmetatable(obj, RecursionSentinel) setmetatable(obj, RecursionSentinel)
return obj return obj
end end
@ -87,42 +87,38 @@ function RecursionSentinel.isKnown(knownTables, value)
end end
function RecursionSentinel.getSentinel(knownTables, value) function RecursionSentinel.getSentinel(knownTables, value)
local sentinel = knownTables[value] return knownTables[value] or RecursionSentinel.add(knownTables, value)
if sentinel == nil then
sentinel = knownTables[value]
knownTables[#knownTables+1] = value
knownTables[value] = RecursionSentinel.make(value, #knownTables)
end
return sentinel
end end
function RecursionSentinel.add(knownTables, value) function RecursionSentinel.add(knownTables, value)
local sentinel = RecursionSentinel.make(value) local sentinel = RecursionSentinel.make(value, #knownTables)
knownTables[value] = sentinel knownTables[value] = sentinel
return sentinel return sentinel
end end
function RecursionSentinel.pop(knownTables) function RecursionSentinel.remove(knownTables, value)
local value = knownTables[#knownTables] local sentinel = knownTables[value]
knownTables[#knownTables] = nil if sentinel then
sentinel.index = nil
end
knownTables[value] = nil knownTables[value] = nil
end end
local function cloneNonRecursive(value, sentinels) local function cloneNonRecursive(value, sentinels)
if type(value) == "table" then if type(value) == "table" then
local sentinel = RecursionSentinel.getSentinel(sentinels, value)
if RecursionSentinel.isKnown(sentinels, value) then if RecursionSentinel.isKnown(sentinels, value) then
return RecursionSentinel.getSentinel(sentinels, value) return sentinel
end end
local clone = {} local clone = {}
local sentinel = RecursionSentinel.add(sentinels, value)
for i,v in ipairs(value) do for i,v in ipairs(value) do
clone[i] = cloneNonRecursive(v, sentinels) clone[i] = cloneNonRecursive(v, sentinels)
end end
for k,v in pairs(value) do for k,v in pairs(value) do
clone[cloneNonRecursive(k, sentinels)] = cloneNonRecursive(v, sentinels) clone[cloneNonRecursive(k, sentinels)] = cloneNonRecursive(v, sentinels)
end end
RecursionSentinel.pop(sentinels) RecursionSentinel.remove(sentinels, sentinel.table)
sentinel.value = clone sentinel.value = clone
return sentinel.value return sentinel.value