There should be a HashLength argument for table.create
which would preallocate the hash part of the table returned.
My use case: Creating a new table with all value from another table (with known size)
Example code which would use the extra argument
local tbl = {
a = function()
-- ...
end,
b = function()
-- ...
end,
c = function()
-- ...
end,
d = function()
-- ...
end,
e = function()
-- ...
end
}
local len = 0
for _ in pairs(tbl) do len = len + 1 end
local function newtbl(...)
local ntbl = table.create(0,nil,len)
for i,v in pairs(tbl) do ntbl[i] = v end
-- some more logic with ntbl
return ntbl
end
Metatables could be used, but this isn’t faster once you consider slower access (must check the main table, and the the metatables __index metamethod), and you couldn’t override the field with nil
since its part of the metatable.
Example code which uses metatables
local tbl = {
a = function()
-- ...
end,
b = function()
-- ...
end,
c = function()
-- ...
end,
d = function()
-- ...
end,
e = function()
-- ...
end
}
local mtbl = {__index=tbl}
local function newtbl(...)
local ntbl = {}
-- some logic with ntbl
return setmetatable(ntbl,mtbl)
end
The benefit for this use case would be pretty massive:
In the default lua interpreter with my extra functions added when I run this code
Code
local time = time
local pairs = pairs
local setmetatable = setmetatable
local create = table.create
local test1 = time()
do
local tbl = {
a=1,
b=2,
c=3,
d=4,
e=5
}
for _=1,100000 do
local newtbl = {}
for i,v in pairs(newtbl) do
newtbl[i] = v
end
local _ = newtbl.a,newtbl.b,newtbl.c,newtbl.d,newtbl.e
end
end
print(time()-test1)
local test2 = time()
do
local tbl = {
a=1,
b=2,
c=3,
d=4,
e=5
}
local mtbl = {__index=tbl}
for _=1,100000 do
local newtbl = setmetatable({},mtbl)
local _ = newtbl.a,newtbl.b,newtbl.c,newtbl.d,newtbl.e
end
end
print(time()-test2)
local test3 = time()
do
local tbl = {
a=1,
b=2,
c=3,
d=4,
e=5
}
local len = 0
for _ in pairs(tbl) do
len = len + 1
end
for _=1,10000 do
local newtbl = create(0,len)
for i,v in pairs(newtbl) do
newtbl[i] = v
end
local _ = newtbl.a,newtbl.b,newtbl.c,newtbl.d,newtbl.e
end
end
print(time()-test3)
(My table.create function just creates a table using the C api lua_createtable, and time gets the time using GetSystemTimeAsFileTime)
int table_create(lua_State*L){ /* table.create */
lua_Integer narray = luaL_optinteger(L,1,0);
lua_Integer nrec = luaL_optinteger(L,2,0);
lua_createtable(L,narray,nrec);
return 1;
}
lua_Integer gettime(void){
FILETIME f;
GetSystemTimeAsFileTime(&f);
return (lua_Integer)f.dwLowDateTime+((lua_Integer)f.dwHighDateTime<<32LL);
}
int ltime(lua_State*L){ /* time */
lua_pushnumber(L,(lua_Number)gettime()/10000000.0);
return 1;
}
I get:
0.05004490073770284653
0.05104629974812269211
0.0100092003121972084
I presume in Luau a similar benefit could be achieved by adding a HashLength argument to table.create
.