• Subject: Re: Memoizing Functions - yet another attempt
• From: Petite Abeille <petite.abeille@...>
• Date: Sat, 14 Dec 2013 13:21:45 +0100

```On Dec 14, 2013, at 12:45 PM, Sir Pogsalot <sir.pogsalot@gmail.com> wrote:

> Writing this because I have seen a lot of inflexible attempts at memoizing function calls out there. :>

Yes! Here is another half-backed one for your entertainment! Hurray!

local function Key( ... )
local aBuffer = {}

for anIndex = 1, select( '#', ... ) do
local aValue = select( anIndex, ... )

aBuffer[ #aBuffer + 1 ] = tostring( aValue or '' ) or ''
aBuffer[ #aBuffer + 1 ] = type( aValue ):sub( 1, 2 )
end

return table.concat( aBuffer )
end

local function Memoize( aFunction )
local aCache = {}

assert
(
( ( type( aFunction ) == 'function' ) or ( getmetatable( aFunction ) and getmetatable( aFunction ).__call ) ),
( 'bad argument #1 to %q (callable expected, got %s)' ):format( debug.getinfo( 1, 'n' ).name, type( aFunction ) )
)

return function( ... )
local aKey = Key( ... )
local aValue = aCache[ aKey ] or table.pack( aFunction( ... ) )

aCache[ aKey ] = aValue

return table.unpack( aValue, 1, aValue.n )
end
end

Usage examples:

local open = Memoize( io.open )
local gsub = Memoize( string.gsub )
local modf = Memoize( math.modf )
local concat = Memoize( table.concat )
local pack = Memoize( table.pack )
local unpack = Memoize( table.unpack )
local none = Memoize( function() return {} end )
local void = Memoize( function() end )

print( 'open', 1, open( 'TestMemoize.lua', 'rb' ) )
print( 'open', 2, open( 'TestMemoize.lua', 'rb' ) )
print( 'open', 3, open( 'TestMemoize.lua', 'rb' ) )
print( 'open', 4, open( 'TestMemoize.lua', 'r' ) )
print( 'open', 5, open( 'TestMemoize.lua', 'r' ) )
print( 'open', 6, open( 'TestMemoize.lua', 'r' ) )

print( 'gsub', 1, gsub( '1 2 3', '%d+', '%1!' ) )
print( 'gsub', 2, gsub( '1 2 3', '%d+', '%1!' ) )
print( 'gsub', 3, gsub( '1 2 3', '%d+', '%1!' ) )

print( 'modf', 1, modf( 1.2 ) )
print( 'modf', 2, modf( 1.2 ) )
print( 'modf', 3, modf( 1.2 ) )
print( 'modf', 4, modf( 3.4 ) )
print( 'modf', 5, modf( 3.4 ) )
print( 'modf', 6, modf( 3.4 ) )

local aTable = {  1, 2, 3, 4, 5, 6 }
print( 'concat', 1, concat( aTable ) )
print( 'concat', 2, concat( aTable ) )
print( 'concat', 3, concat( { 1, 2, 3, 4, 5, 6 } ) )
print( 'concat', 4, concat( aTable, '.' ) )
print( 'concat', 5, concat( aTable, '.' ) )
print( 'concat', 6, concat( aTable, ':' ) )
print( 'concat', 7, concat( aTable, ':' ) )
print( 'concat', 8, concat( aTable, ';' ) )
print( 'concat', 9, concat( aTable, ';' ) )

print( 'pack', 1, pack( 1, 2, 3, 4, 5, 6 ) )
print( 'pack', 2, pack( 1, 2, 3, 4, 5, 6 ) )
print( 'pack', 3, pack( nil, nil, nil, 1, 2, 3, 4, 5, 6, nil, nil, nil ) )
print( 'pack', 4, pack( nil, nil, nil, 1, 2, 3, 4, 5, 6, nil, nil, nil, true, 0, false ) )
print( 'pack', 5, pack( '1', '23' ) )
print( 'pack', 6, pack( '12', '3' ) )

print( 'unpack', 1, unpack( aTable ) )
print( 'unpack', 2, unpack( aTable, 1, 3 ) )
print( 'unpack', 3, unpack( { 1, 2, 3 } ) )

print( 'none', 1, none() )
print( 'none', 2, none() )
print( 'none', 3, none() )

print( 'void', 1, void() )
print( 'void', 2, void() )
print( 'void', 3, void( true, false, nil ) )
print( 'void', 4, void( true, nil, false ) )
print( 'void', 5, void( 1 ) )
print( 'void', 6, void( '1' ) )

```