Skip to content

Commit 7b7a856

Browse files
committed
Fix stringify performance scaling
1 parent e4b381d commit 7b7a856

1 file changed

Lines changed: 28 additions & 17 deletions

File tree

src/Modules/Utils.lua

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,30 @@ local M = {}
44

55
---@alias StringifyTypes string | number | boolean | nil | table<StringifyTypes, StringifyTypes>
66

7-
-- Converts a table to a string which will be valid Lua. The result will ipairs to utilise the array
8-
-- syntax when applicable, and will sort other keys.
9-
--- @param value StringifyTypes
10-
--- @param allowNewlines boolean? Determines if multi-line strings should be allowed. By default newlines are converted to spaces.
11-
--- @return string
12-
function M.stringify(value, allowNewlines, tabs)
7+
local function writeStringify(buf, value, allowNewlines, tabs)
138
local valType = type(value)
149
if not tabs then
1510
tabs = 0
1611
end
1712
if valType == "string" then
1813
if allowNewlines and value:find("\n") then
19-
return '[['..value..']]'
14+
buf[#buf + 1] = '[[' .. value .. ']]'
2015
else
2116
local s = value:gsub("\n", " ")
22-
return '"'..s..'"'
17+
buf[#buf + 1] = '"' .. s .. '"'
2318
end
2419
elseif valType == "boolean" or valType == "nil" or valType == "number" then
25-
return tostring(value)
20+
buf[#buf + 1] = tostring(value)
2621
elseif valType == "table" then
27-
local s = "{\n";
22+
buf[#buf + 1] = "{\n"
2823
-- ipairs compatible keys are done first so we can use the array syntax for them
2924
local arrayKeys = {}
3025
local indent = string.rep("\t", tabs)
3126
for k, v in ipairs(value) do
3227
arrayKeys[k] = true
33-
s = s..indent..M.stringify(v, allowNewlines, tabs + 1) ..",\n"
28+
buf[#buf + 1] = indent
29+
writeStringify(buf, v, allowNewlines, tabs + 1)
30+
buf[#buf + 1] = ",\n"
3431
end
3532

3633
local mapKeys = { }
@@ -41,21 +38,35 @@ function M.stringify(value, allowNewlines, tabs)
4138

4239
for _, k in ipairs(mapKeys) do
4340
if not arrayKeys[k] then
44-
local keyStr = M.stringify(k, allowNewlines)
45-
if keyStr:find("^%[") then
41+
if type(k) == "string" and k:find("\n") and allowNewlines then
4642
-- multiline strings as keys need the space around the key value to parse correctly
47-
s = s..indent.."[ "..keyStr.." ] = "
43+
buf[#buf + 1] = indent .. "[ "
44+
writeStringify(buf, k, allowNewlines, nil)
45+
buf[#buf + 1] = " ] = "
4846
else
49-
s = s..indent.."["..keyStr.."] = "
47+
buf[#buf + 1] = indent .. "["
48+
writeStringify(buf, k, allowNewlines, nil)
49+
buf[#buf + 1] = "] = "
5050
end
51-
s = s..M.stringify(value[k], allowNewlines, tabs + 1)..",\n"
51+
writeStringify(buf, value[k], allowNewlines, tabs + 1)
52+
buf[#buf + 1] = ",\n"
5253
end
5354
end
54-
return s..string.rep("\t", tabs-1).."}"
55+
buf[#buf + 1] = string.rep("\t", tabs - 1) .. "}"
5556
else
5657
error("Disallowed stringify type "..valType)
5758
end
5859
end
60+
-- Converts a table to a string which will be valid Lua. The result will ipairs to utilise the array
61+
-- syntax when applicable, and will sort other keys.
62+
--- @param value StringifyTypes
63+
--- @param allowNewlines boolean? Determines if multi-line strings should be allowed. By default newlines are converted to spaces.
64+
--- @return string
65+
function M.stringify(value, allowNewlines, tabs)
66+
local buf = {}
67+
writeStringify(buf, value, allowNewlines, tabs)
68+
return table.concat(buf)
69+
end
5970

6071
---@param fileName
6172
---@param table StringifyTypes

0 commit comments

Comments
 (0)