Generic multi-argument memoize (was: Problem with implicit template instantiation)
Clemens Hofreither
clemens.hofreither at gmx.net
Mon Jul 7 04:58:58 PDT 2008
For what it's worth, I have circumvented my original problem by making
the templated type in question a class. Since the code seems to work
nicely now, I figured I could as well post it; it's a generic memoize function
which works (type-safely) on functions with any return type and any
number and type of arguments (well, as long as they can be AA indices). I
would be interested in any improvement suggestions. Also, I'd really like to
know why I have to use "inout" for the AA argument in store(); I thought
AAs had reference semantics, but without inout it doesn't work as
expected.
Well, here's the code:
/*****************************************/
import tango.io.Stdout;
class MultiMap(S, T...)
{
private template MultiMapT(R, Q...)
{
static if (Q.length <= 1)
alias R[Q[0]] MultiMapT;
else
alias MultiMapT!(R,Q[1..length])[Q[0]] MultiMapT;
}
private alias MultiMapT!(S,T) M;
private M map;
private static S *lookup(R, Q...)(R[Q[0]] map, Q key)
{
static if (key.length <= 1)
return key[0] in map;
else {
auto inner = key[0] in map;
if (inner != null)
return lookup!(typeof(R[Q[0]]), Q[1..length])(*inner, key[1..length]);
else
return null;
}
}
private static void store(R, Q...)(inout R[Q[0]] map, S value, Q key)
{
static if (key.length <= 1)
map[key[0]] = value;
else
store!(typeof(R[Q[0]]), Q[1..length])(map[key[0]], value, key[1..length]);
}
S *get(T key) {
return lookup!(typeof(M[T[0]]), T)(map, key);
}
void set(S value, T key) {
store!(typeof(M[T[0]]), T)(map, value, key);
}
}
class Memo(R, P...)
{
private R function(P) func;
private MultiMap!(R,P) values;
this(R function(P) f)
{
func = f;
values = new MultiMap!(R,P);
}
R opCall(P args)
{
R *val = values.get(args);
if (val != null)
return *val;
else {
R v = func(args);
values.set(v, args);
return v;
}
}
}
Memo!(R, P) memoize(R, P...)(R function(P) myfunc)
{
return new Memo!(R,P)(myfunc);
}
float foo(float x, float y)
{
Stdout.format("foo called.\n");
return x / y;
}
void main()
{
auto f = memoize(&foo);
Stdout.format("{}\n", f(3f, 4f));
Stdout.format("{}\n", f(3f, 4f));
}
/*****************************************/
-Clemens
More information about the Digitalmars-d-learn
mailing list