if Debug then Debug.beginFile "LookupTable" end
do
--[[
=============================================================================================================================================================
Lookup Table
by Antares
=============================================================================================================================================================
Lookup Table adds a convenient way to store data returned from functions that need to do complex calculations, but it can also be used in a simple way to make
natives that always return the same result for the same input arguments faster.
Adding a lookup table to a function overwrites the function call with a table lookup. The function is only executed on the first call with a given combination
of input arguments. This increases the speed of every subsequent function call. A native with a lookup table will be approximately 10x faster when called.
With a lookup table added to a function, you can call that function just like you would normally, but you can also treat it as a table, making it even faster.
To add a lookup table to a global function, do AddLookupTable("functionName"). This will overwrite the global. The overwritten function is stored as <Name>Func.
To add a lookup table to any function, do AddLookupTable(whichFunction). This will not overwrite the function and return the table instead.
You can add a lookup table to functions with up to three arguments, but you need to specify how many arguments the function takes if it's not one:
AddLookupTable("functionName", numArgs)
Example:
AddLookupTable("FourCC")
AddLookupTable("BlzGetAbilityTooltip", 2)
print( BlzGetAbilityTooltip[FourCC.AHbz][0] ) -> "Blizzard - [|cffffcc00Level 1|r]"
Another Example:
function ComplicatedMath(a, b, c)
--100 more lines of code
return 12*a + 16*b + 5*c
end
local complicatedMathTable = AddLookupTable(ComplicatedMath, 3)
print( complicatedMathTable(4, 3, 7) ) -> 131
=============================================================================================================================================================
Limitations:
-You should be able to directly call AddLookupTable from the Lua root for your own functions as long as those functions and the Lookup Table library are above
the call, but it won't work for natives.
-You can overwrite a function that takes an object as an argument, for example GetUnitTypeId (if you don't have morphing units). This will leak ~100-200
bytes per object (which is usually negligible), but you can clean-up manually if necessary.
-Overwriting a global will make it incompatible with Hook.
=============================================================================================================================================================
]]
local callMethods = {}
local function CreateIndexMethod(lookupTable, whichFunction, N)
local iterateKeys
iterateKeys = function(whichTable, i, ...)
local args = table.pack(...)
if i > 1 then
setmetatable(whichTable, {__index = function(newTable, newKey)
newTable[newKey] = {}
iterateKeys(newTable[newKey], i-1, newKey, table.unpack(args))
return newTable[newKey]
end})
else
setmetatable(whichTable, {__index = function(newTable, newKey)
args[#args + 1] = newKey
newTable[newKey] = whichFunction(table.unpack(args))
return newTable[newKey]
end})
end
end
iterateKeys(lookupTable, N)
return lookupTable
end
local function CreateCallMethod(N)
local code = "return function(self, "
for i = 1, N - 1 do
code = code .. "arg" .. i .. ", "
end
code = code .. "arg" .. N .. ")\nreturn self"
for i = 1, N do
code = code .. "[arg" .. i .. "]"
end
code = code .. "\nend"
callMethods[N] = load(code)()
return callMethods[N]
end
---@param whichFunction string | function
---@param numArgs? integer
function AddLookupTable(whichFunction, numArgs)
local isGlobalFunc = type(whichFunction) == "string"
numArgs = numArgs or 1
local func
if isGlobalFunc then
_G[whichFunction .. "Func"] = _G[whichFunction]
func = _G[whichFunction]
else
func = whichFunction
end
local lookupTable = {}
CreateIndexMethod(lookupTable, func, numArgs)
getmetatable(lookupTable).__call = (callMethods[numArgs] or CreateCallMethod(numArgs))
if isGlobalFunc then
_G[whichFunction] = lookupTable
else
return lookupTable
end
end
end