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