Skip to content

Instantly share code, notes, and snippets.

@sboisson
Created May 23, 2014 15:25
Show Gist options
  • Save sboisson/2f6f34a4a3421b0c79df to your computer and use it in GitHub Desktop.
Save sboisson/2f6f34a4a3421b0c79df to your computer and use it in GitHub Desktop.
Adaptive Replacement Cache in python (Python recipe)
class Cache(object):
"""
>>> dec_cache = Cache(10)
>>> @dec_cache
... def identity(f):
... return f
>>> dummy = [identity(x) for x in range(20) + range(11,15) + range(20) +
... range(11,40) + [39, 38, 37, 36, 35, 34, 33, 32, 16, 17, 11, 41]]
>>> dec_cache.t1
deque([(41,)])
>>> dec_cache.t2
deque([(11,), (17,), (16,), (32,), (33,), (34,), (35,), (36,), (37,)])
>>> dec_cache.b1
deque([(31,), (30,)])
>>> dec_cache.b2
deque([(38,), (39,), (19,), (18,), (15,), (14,), (13,), (12,)])
>>> dec_cache.p
5
"""
def __init__(self, size):
self.cached = {}
self.c = size
self.p = 0
self.t1 = deque()
self.t2 = deque()
self.b1 = deque()
self.b2 = deque()
def replace(self, args):
if self.t1 and (
(args in self.b2 and len(self.t1) == self.p) or
(len(self.t1) > self.p)):
old = self.t1.pop()
self.b1.appendleft(old)
else:
old = self.t2.pop()
self.b2.appendleft(old)
del(self.cached[old])
def __call__(self, func):
def wrapper(*orig_args):
"""decorator function wrapper"""
args = orig_args[:]
if args in self.t1:
self.t1.remove(args)
self.t2.appendleft(args)
return self.cached[args]
if args in self.t2:
self.t2.remove(args)
self.t2.appendleft(args)
return self.cached[args]
result = func(*orig_args)
self.cached[args] = result
if args in self.b1:
self.p = min(
self.c, self.p + max(len(self.b2) / len(self.b1) , 1))
self.replace(args)
self.b1.remove(args)
self.t2.appendleft(args)
#print "%s:: t1:%s b1:%s t2:%s b2:%s p:%s" % (
# repr(func)[10:30], len(self.t1),len(self.b1),len(self.t2),
# len(self.b2), self.p)
return result
if args in self.b2:
self.p = max(0, self.p - max(len(self.b1)/len(self.b2) , 1))
self.replace(args)
self.b2.remove(args)
self.t2.appendleft(args)
#print "%s:: t1:%s b1:%s t2:%s b2:%s p:%s" % (
# repr(func)[10:30], len(self.t1),len(self.b1),len(self.t2),
# len(self.b2), self.p)
return result
if len(self.t1) + len(self.b1) == self.c:
if len(self.t1) < self.c:
self.b1.pop()
self.replace(args)
else:
del(self.cached[self.t1.pop()])
else:
total = len(self.t1) + len(self.b1) + len(
self.t2) + len(self.b2)
if total >= self.c:
if total == (2 * self.c):
self.b2.pop()
self.replace(args)
self.t1.appendleft(args)
return result
return wrapper
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment