Skip to content

Instantly share code, notes, and snippets.

@loosechainsaw
Last active December 21, 2015 01:38
Show Gist options
  • Save loosechainsaw/6228586 to your computer and use it in GitHub Desktop.
Save loosechainsaw/6228586 to your computer and use it in GitHub Desktop.
Proof of concept Memoization support for C# - With Expiration
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
public interface IMemoizationPolicy
{
bool ShouldFlushCache(int records);
void Purge(dynamic dictionary);
}
public class NeverMemoizationPolicy : IMemoizationPolicy
{
public bool ShouldFlushCache(int records)
{
return false;
}
public void Purge(dynamic dictionary)
{
}
}
public class AtRecordCountFlushMemoizationPolicy : IMemoizationPolicy
{
public AtRecordCountFlushMemoizationPolicy(int count)
{
_count = count;
}
public bool ShouldFlushCache(int records)
{
return records >= _count;
}
public void Purge(dynamic dictionary)
{
dictionary.Clear();
}
private readonly int _count;
}
public static class MemoiseFuncExtensions
{
public static Func<TArg1, TResult> Memoise<TArg1, TResult>(this Func<TArg1, TResult> func)
{
return Memoise(func, new AtRecordCountFlushMemoizationPolicy(1000));
}
public static Func<TArg1, TResult> Memoise<TArg1, TResult>(this Func<TArg1, TResult> func, IMemoizationPolicy policy)
{
var lookup = new Dictionary<TArg1, TResult>();
return arg1 =>
{
EnforcePolicy(policy, lookup);
if (!lookup.ContainsKey(arg1))
EvaluateAndRecord(func, arg1, lookup);
return lookup[arg1];
};
}
private static void EvaluateAndRecord<TArg1, TResult>(Func<TArg1, TResult> func, TArg1 arg1, Dictionary<TArg1, TResult> lookup)
{
var result = func(arg1);
lookup[arg1] = result;
}
private static void EnforcePolicy<TArg1, TResult>(IMemoizationPolicy policy, Dictionary<TArg1, TResult> lookup)
{
if (policy.ShouldFlushCache(lookup.Count))
policy.Purge(lookup);
}
public static Func<TArg1, TArg2, TResult> Memoise<TArg1, TArg2, TResult>(this Func<TArg1, TArg2, TResult> func)
{
return Memoise(func, new AtRecordCountFlushMemoizationPolicy(1000));
}
public static Func<TArg1, TArg2, TResult> Memoise<TArg1, TArg2, TResult>(this Func<TArg1, TArg2, TResult> func, IMemoizationPolicy policy)
{
var lookup = new Dictionary<Tuple<TArg1, TArg2>, TResult>();
return (arg1, arg2) =>
{
EnforcePolicy(policy, lookup);
if (!lookup.ContainsKey(Tuple.Create(arg1,arg2)))
EvaluateAndRecord(func, arg1,arg2, lookup);
return lookup[Tuple.Create(arg1, arg2)];
};
}
private static void EvaluateAndRecord<TArg1, TArg2, TResult>(Func<TArg1, TArg2, TResult> func, TArg1 arg1, TArg2 arg2, Dictionary<Tuple<TArg1, TArg2>,TResult> lookup)
{
var result = func(arg1,arg2);
lookup[Tuple.Create(arg1,arg2)] = result;
}
private static void EnforcePolicy<TArg1,TArg2, TResult>(IMemoizationPolicy policy, Dictionary<Tuple<TArg1,TArg2>, TResult> lookup)
{
if (policy.ShouldFlushCache(lookup.Count))
policy.Purge(lookup);
}
public static Func<TArg1, TArg2, TArg3, TResult> Memoise<TArg1, TArg2,TArg3, TResult>(this Func<TArg1, TArg2,TArg3, TResult> func)
{
return Memoise(func, new AtRecordCountFlushMemoizationPolicy(1000));
}
public static Func<TArg1, TArg2, TArg3, TResult> Memoise<TArg1, TArg2,TArg3, TResult>(this Func<TArg1, TArg2,TArg3, TResult> func, IMemoizationPolicy policy)
{
var lookup = new Dictionary<Tuple<TArg1, TArg2, TArg3>, TResult>();
return (arg1, arg2, arg3) =>
{
EnforcePolicy(policy, lookup);
if (!lookup.ContainsKey(Tuple.Create(arg1, arg2, arg3)))
EvaluateAndRecord(func, arg1, arg2, arg3, lookup);
return lookup[Tuple.Create(arg1, arg2, arg3)];
};
}
private static void EvaluateAndRecord<TArg1, TArg2, TArg3, TResult>(Func<TArg1, TArg2, TArg3, TResult> func, TArg1 arg1, TArg2 arg2, TArg3 arg3, Dictionary<Tuple<TArg1, TArg2, TArg3>, TResult> lookup)
{
var result = func(arg1, arg2, arg3);
lookup[Tuple.Create(arg1, arg2, arg3)] = result;
}
private static void EnforcePolicy<TArg1, TArg2, TArg3, TResult>(IMemoizationPolicy policy, Dictionary<Tuple<TArg1, TArg2, TArg3>, TResult> lookup)
{
if (policy.ShouldFlushCache(lookup.Count))
policy.Purge(lookup);
}
}
class Program
{
static void Main()
{
Func<int, int, int> increment = (x,y) => x + y + 1;
var memoised = increment.Memoise();
var r1 = memoised(1, 1);
var r2 = memoised(1, 1);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment