Skip to content

Instantly share code, notes, and snippets.

@wgross
Created June 6, 2014 08:23
Show Gist options
  • Save wgross/7470ace5904326b15b51 to your computer and use it in GitHub Desktop.
Save wgross/7470ace5904326b15b51 to your computer and use it in GitHub Desktop.
Memoization of delegates calculation result using strong or weak references. Extension to multiple parameters with partial application. The memoization container can be changed by implementing a custom memoization container factory.
using System;
using System.Collections.Generic;
namespace Memoization
{
public static class Memoize
{
#region Create memoization containers
public interface IContainerFactory
{
IDictionary<K, V> CreateNew<K, V>(IEqualityComparer<K> withEqualityComparer = null);
}
private class ContainerAsDictionaryFactory : IContainerFactory
{
public IDictionary<K, V> CreateNew<K, V>(IEqualityComparer<K> withEqualityComparer = null)
{
return new Dictionary<K, V>(withEqualityComparer ?? EqualityComparer<K>.Default);
}
}
public static readonly IContainerFactory ContainerAsDictionary = new ContainerAsDictionaryFactory();
#endregion Create memoization containers
#region Partial memoization results to delegates by using partial application: The function returns a function receiving one parameter less
public class Partial
{
public static Func<P1, Func<P2, Func<P3, R>>> Strong<P1, P2, P3, R>(Func<P1, P2, P3, R> toMemoize, IContainerFactory useContainerFactory = null)
{
return Memoize.Strong<P1, Func<P2, Func<P3, R>>>((p1) => Memoize.Partial.Strong<P2, P3, R>((p2, p3) => toMemoize(p1, p2, p3), useContainerFactory), useContainerFactory);
}
public static Func<P1, Func<P2, R>> Strong<P1, P2, R>(Func<P1, P2, R> toMemoize, IContainerFactory useContainerFactory = null)
{
return Memoize.Strong<P1, Func<P2, R>>((p1) => Memoize.Strong<P2, R>(p2 => toMemoize(p1, p2), useContainerFactory), useContainerFactory);
}
}
#endregion Partial memoization results to delegates by using partial application: The function returns a function receiving one parameter less
#region Full memoization results to delegates receiving the same number of parameters as the memoized function
public class Full
{
public static Func<P1, P2, P3, R> Strong<P1, P2, P3, R>(Func<P1, P2, P3, R> toMemoize, IContainerFactory useContainerFactory = null)
{
var tmp = Partial.Strong<P1, P2, P3, R>(toMemoize, useContainerFactory);
return (p1, p2, p3) => tmp(p1)(p2)(p3);
}
public static Func<P1, P2, R> Strong<P1, P2, R>(Func<P1, P2, R> toMemoize, IContainerFactory useContainerFactory = null)
{
var tmp = Partial.Strong<P1, P2, R>(toMemoize, useContainerFactory);
return (p1, p2) => tmp(p1)(p2);
}
}
#endregion Full memoization results to delegates receiving the same number of parameters as the memoized function
#region Base memoization factory method: No separation of partial application and full memoization for one parameter
public static Func<P, R> Strong<P, R>(this Func<P, R> toMemoize, IContainerFactory useContainerFactory = null)
{
var tmp = (useContainerFactory ?? ContainerAsDictionary).CreateNew<P, R>();
return p =>
{
R value;
if (!tmp.TryGetValue(p, out value))
{
value = toMemoize(p);
tmp.Add(p, value);
}
return value;
};
}
public static Func<P, R> Weak<P, R>(Func<P, R> toMemoize, IContainerFactory useContainerFactory = null)
where R : class
{
var tmp = (useContainerFactory ?? ContainerAsDictionary).CreateNew<P, WeakReference<R>>();
return p =>
{
WeakReference<R> weakReference;
R weakTarget;
if (!tmp.TryGetValue(p, out weakReference) || !weakReference.TryGetTarget(out weakTarget))
{
weakTarget = toMemoize(p);
weakReference = new WeakReference<R>(weakTarget);
tmp.Add(p, weakReference);
}
return weakTarget;
};
}
#endregion Base memoization factory method: No separation of partial application and full memoization for one parameter
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment