Experimental/ModuleScripts/Memoize.lua

68 lines
2.4 KiB
Lua
Raw Permalink Normal View History

2024-11-30 05:37:05 +00:00
--[[
memoize creates a function as a wrapper that caches the last outputs of a function.
This is useful if you know that the function should return the same output every
time it is run with the same inputs. The function should only return an output, and
not have any side effects. These side effects are not cached.
Without memoize's caching, even though the function ouputs the same values, the
memory locations of the values are different; tables made in the function, even if
they have the same values, won't be the same tables.
memoize only caches the last set of inputs and ouputs. This means that it is only
helpful when the function is likely to be called with the same inputs multiple
times in a row. This is the case with most Roact use cases.
Note that memoize only does a ** shallow check on table inputs ** . This means
that if the same table is input but the elements of the table are different then
it will be assumed that the table has not changed.
In addition to all the previous warnings, memoize strips trailing nils. This means
that if foo is a memoized function and we call foo(), then foo(nil) will return a
cached value. This is opposed to how print handles input. print() only outputs a
new line, but print(nil) outputs "nil". This is because varargs can detect the
number of arguments passed in. So, be careful when using memoize with varargs.
Trailing nils will be stripped.
The wrapper can take any number of inputs and give any number of outputs.
Leading and interspersed nils are handled gracefully. Trailing nils on the input
are stripped.
]]
local function captureSize(...)
return {...}, select("#", ...)
end
local function memoize(func)
assert(type(func) == "function", "memoize requires a function to memoize")
local lastArgs
local lastNumArgs
local lastOutput
local lastNumOutput
return function(...)
local numArgs = select("#", ...)
while numArgs > 0 and select(numArgs, ...) == nil do
numArgs = numArgs - 1
end
if numArgs ~= lastNumArgs then
lastArgs = {...}
lastNumArgs = numArgs
lastOutput, lastNumOutput = captureSize(func(...))
return unpack(lastOutput, 1, lastNumOutput)
end
for i = 1, lastNumArgs do
if select(i, ...) ~= lastArgs[i] then
lastArgs = {...}
lastOutput, lastNumOutput = captureSize(func(...))
break
end
end
return unpack(lastOutput, 1, lastNumOutput)
end
end
return memoize