+import itertools
+
+class LRUDict(object):
+ def __init__(self, n):
+ self.n = n
+ self.inner = {}
+ self.counter = itertools.count()
+ def get(self, key, default=None):
+ if key in self.inner:
+ x, value = self.inner[key]
+ self.inner[key] = self.counter.next(), value
+ return value
+ return default
+ def __setitem__(self, key, value):
+ self.inner[key] = self.counter.next(), value
+ while len(self.inner) > self.n:
+ self.inner.pop(min(self.inner, key=lambda k: self.inner[k][0]))
+
_nothing = object()
-def memoize_with_backing(backing, inverse_of=None):
+def memoize_with_backing(backing, has_inverses=set()):
def a(f):
def b(*args):
res = backing.get((f, args), _nothing)
res = f(*args)
backing[(f, args)] = res
- if inverse_of is not None:
- if len(args) != 1:
- raise ValueError('inverse_of can only be used for functions taking one argument')
- backing[(inverse_of, (res,))] = args[0]
+ for inverse in has_inverses:
+ backing[(inverse, args[:-1] + (res,))] = args[-1]
return res
return b
def memoize(f):
return memoize_with_backing({})(f)
+
+
+class cdict(dict):
+ def __init__(self, func):
+ dict.__init__(self)
+ self._func = func
+
+ def __missing__(self, key):
+ value = self._func(key)
+ self[key] = value
+ return value
+
+def fast_memoize_single_arg(func):
+ return cdict(func).__getitem__
+
+class cdict2(dict):
+ def __init__(self, func):
+ dict.__init__(self)
+ self._func = func
+
+ def __missing__(self, key):
+ value = self._func(*key)
+ self[key] = value
+ return value
+
+def fast_memoize_multiple_args(func):
+ f = cdict2(func).__getitem__
+ return lambda *args: f(args)