Serialize: Use numbers for refs to work around LuaJIT limits

This commit is contained in:
Lars Mueller 2022-08-17 11:35:26 +02:00 committed by SmallJoker
parent c607bee19e
commit 6c24dc4e23
1 changed files with 12 additions and 7 deletions

View File

@ -61,17 +61,18 @@ end
-- Serializes Lua nil, booleans, numbers, strings, tables and even functions -- Serializes Lua nil, booleans, numbers, strings, tables and even functions
-- Tables are referenced by reference, strings are referenced by value. Supports circular tables. -- Tables are referenced by reference, strings are referenced by value. Supports circular tables.
local function serialize(value, write) local function serialize(value, write)
local reference, refnum = "r1", 1 local reference, refnum = "1", 1
-- [object] = reference string -- [object] = reference
local references = {} local references = {}
-- Circular tables that must be filled using `table[key] = value` statements -- Circular tables that must be filled using `table[key] = value` statements
local to_fill = {} local to_fill = {}
for object, count in pairs(count_objects(value)) do for object, count in pairs(count_objects(value)) do
local type_ = type(object) local type_ = type(object)
-- Object must appear more than once. If it is a string, the reference has to be shorter than the string. -- Object must appear more than once. If it is a string, the reference has to be shorter than the string.
if count >= 2 and (type_ ~= "string" or #reference + 2 < #object) then if count >= 2 and (type_ ~= "string" or #reference + 5 < #object) then
write"_["
write(reference) write(reference)
write("=") write("]=")
if type_ == "table" then if type_ == "table" then
write("{}") write("{}")
elseif type_ == "function" then elseif type_ == "function" then
@ -85,7 +86,7 @@ local function serialize(value, write)
to_fill[object] = reference to_fill[object] = reference
end end
refnum = refnum + 1 refnum = refnum + 1
reference = ("r%X"):format(refnum) reference = ("%d"):format(refnum)
end end
end end
-- Used to decide whether we should do "key=..." -- Used to decide whether we should do "key=..."
@ -110,7 +111,9 @@ local function serialize(value, write)
-- Reference types: table, function and string -- Reference types: table, function and string
local ref = references[value] local ref = references[value]
if ref then if ref then
return write(ref) write"_["
write(ref)
return write"]"
end end
if type_ == "string" then if type_ == "string" then
return write(quote(value)) return write(quote(value))
@ -156,7 +159,9 @@ local function serialize(value, write)
-- Write the statements to fill circular tables -- Write the statements to fill circular tables
for table, ref in pairs(to_fill) do for table, ref in pairs(to_fill) do
for k, v in pairs(table) do for k, v in pairs(table) do
write("_[")
write(ref) write(ref)
write("]")
if use_short_key(k) then if use_short_key(k) then
write(".") write(".")
write(k) write(k)
@ -202,7 +207,7 @@ function core.deserialize(str, safe)
if not func then return nil, err end if not func then return nil, err end
-- math.huge is serialized to inf, NaNs are serialized to nan by Lua -- math.huge is serialized to inf, NaNs are serialized to nan by Lua
local env = {inf = math_huge, nan = nan} local env = {inf = math_huge, nan = nan, _ = {}}
if safe then if safe then
env.loadstring = dummy_func env.loadstring = dummy_func
else else