use a growing vector of string parts to serialize a string, returning table.concat when done

This commit is contained in:
payonel 2017-09-07 20:26:16 -07:00
parent eaf2b0cf8a
commit 1bc6e84af2

View File

@ -17,40 +17,41 @@ function serialization.serialize(value, pretty)
["until"]=true, ["while"]=true}
local id = "^[%a_][%w_]*$"
local ts = {}
local function s(v, l)
local t = type(v)
local result_pack = {}
local function recurse(current_value, depth)
local t = type(current_value)
if t == "nil" then
return "nil"
table.insert(result_pack, "nil")
elseif t == "boolean" then
return v and "true" or "false"
table.insert(result_pack, current_value and "true" or "false")
elseif t == "number" then
if v ~= v then
return "0/0"
elseif v == math.huge then
return "math.huge"
elseif v == -math.huge then
return "-math.huge"
if current_value ~= current_value then
table.insert(result_pack, "0/0")
elseif current_value == math.huge then
table.insert(result_pack, "math.huge")
elseif current_value == -math.huge then
table.insert(result_pack, "-math.huge")
else
return tostring(v)
table.insert(result_pack, tostring(current_value))
end
elseif t == "string" then
return string.format("%q", v):gsub("\\\n","\\n")
elseif t == "table" and pretty and getmetatable(v) and getmetatable(v).__tostring then
return tostring(v)
table.insert(result_pack, (string.format("%q", current_value):gsub("\\\n","\\n")))
elseif t == "table" and pretty and getmetatable(current_value) and getmetatable(current_value).__tostring then
table.insert(result_pack, tostring(current_value))
elseif t == "table" then
if ts[v] then
if ts[current_value] then
if pretty then
return "recursion"
table.insert(result_pack, "recursion")
return
else
error("tables with cycles are not supported")
end
end
ts[v] = true
local i, r = 1, nil
ts[current_value] = true
local f
if pretty then
local ks, sks, oks = {}, {}, {}
for k in local_pairs(v) do
for k in local_pairs(current_value) do
if type(k) == "number" then
table.insert(ks, k)
elseif type(k) == "string" then
@ -72,44 +73,53 @@ function serialization.serialize(value, pretty)
n = n + 1
local k = ks[n]
if k ~= nil then
return k, v[k]
return k, current_value[k]
else
return nil
end
end)
else
f = table.pack(local_pairs(v))
f = table.pack(local_pairs(current_value))
end
local i = 1
local first = true
table.insert(result_pack, "{")
for k, v in table.unpack(f) do
if r then
r = r .. "," .. (pretty and ("\n" .. string.rep(" ", l)) or "")
else
r = "{"
if not first then
table.insert(result_pack, ",")
if pretty then
table.insert(result_pack, "\n" .. string.rep(" ", depth))
end
end
first = nil
local tk = type(k)
if tk == "number" and k == i then
i = i + 1
r = r .. s(v, l + 1)
recurse(v, depth + 1)
else
if tk == "string" and not kw[k] and string.match(k, id) then
r = r .. k
table.insert(result_pack, k)
else
r = r .. "[" .. s(k, l + 1) .. "]"
table.insert(result_pack, "[")
recurse(k, depth + 1)
table.insert(result_pack, "]")
end
r = r .. "=" .. s(v, l + 1)
table.insert(result_pack, "=")
recurse(v, depth + 1)
end
end
ts[v] = nil -- allow writing same table more than once
return (r or "{") .. "}"
ts[current_value] = nil -- allow writing same table more than once
table.insert(result_pack, "}")
else
if pretty then
return tostring(v)
table.insert(result_pack, tostring(current_value))
else
error("unsupported type: " .. t)
end
end
end
local result = s(value, 1)
recurse(value, 1)
local result = table.concat(result_pack)
local limit = type(pretty) == "number" and pretty or 10
if pretty then
local truncate = 0