summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJay Hutchinson <jlhutch@gmail.com>2022-03-01 14:09:59 -0600
committerJay Hutchinson <jlhutch@gmail.com>2022-03-06 10:26:06 -0600
commit968a41a4094c20bb24fb1a604a44dd9bbc5aed33 (patch)
tree82ed31fea9b94fd2249d65b9dbe2baeca537c90b
parent605856ff6f5993e851032d7d64a945396a1ffb0c (diff)
downloadpylru-968a41a4094c20bb24fb1a604a44dd9bbc5aed33.tar.gz
Improved comments, removed whitespace, etc.
-rw-r--r--pylru.py33
-rw-r--r--test.py16
2 files changed, 25 insertions, 24 deletions
diff --git a/pylru.py b/pylru.py
index 67f3d7d..842c7bf 100644
--- a/pylru.py
+++ b/pylru.py
@@ -2,7 +2,7 @@
# Cache implementaion with a Least Recently Used (LRU) replacement policy and
# a basic dictionary interface.
-# Copyright (C) 2006-2019 Jay Hutchinson
+# Copyright (C) 2006-2022 Jay Hutchinson
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
@@ -46,7 +46,6 @@ class _dlnode(object):
class lrucache(object):
-
def __init__(self, size, callback=None):
self.callback = callback
@@ -99,7 +98,6 @@ class lrucache(object):
return node.value
def get(self, key, default=None):
- """Get an item - return default (None) if not present"""
if key not in self.table:
return default
@@ -317,11 +315,23 @@ class lrucache(object):
yield node
node = node.next
+ # The methods __getstate__() and __setstate__() are used to correctly
+ # support the copy and pickle modules from the standard library. In
+ # particular, the doubly linked list trips up the introspection machinery
+ # used by copy/pickle.
def __getstate__(self):
+ # Copy the instance attributes.
d = self.__dict__.copy()
+
+ # Remove those that we need to do by hand.
del d['table']
del d['head']
+ # Package up the key/value pairs from the doubly linked list into a
+ # normal list that can be copied/pickled correctly. We put the
+ # key/value pairs into the list in order, as returned by dli(), from
+ # most recently to least recently used, so that the copy can be
+ # restored with the same ordering.
elements = [(node.key, node.value) for node in self.dli()]
return (d, elements)
@@ -329,12 +339,19 @@ class lrucache(object):
d = state[0]
elements = state[1]
+ # Restore the instance attributes, except for the table and head.
self.__dict__.update(d)
+ # Rebuild the table and doubly linked list from the simple list of
+ # key/value pairs in 'elements'.
+ # The listSize is the size of the original cache. We want this cache
+ # to have the same size, but we need to reset it temporarily to set up
+ # table and head correctly, so save a copy of the size.
size = self.listSize
- # Create an empty hash table.
+ # Setup a table and double linked list. This is identical to the way
+ # __init__() does it.
self.table = {}
self.head = _dlnode()
@@ -346,7 +363,10 @@ class lrucache(object):
# Now adjust the list to the desired size.
self.size(size)
-
+ # Fill the cache with the keys/values. Because inserted items are
+ # moved to the top of the doubly linked list, we insert the key/value
+ # pairs in reverse order. This ensures that the order of the doubly
+ # linked list is identical to the original cache.
for key, value in reversed(elements):
self[key] = value
@@ -390,7 +410,6 @@ class WriteThroughCacheManager(object):
return value
def get(self, key, default=None):
- """Get an item - return default (None) if not present"""
try:
return self[key]
except KeyError:
@@ -426,7 +445,6 @@ class WriteThroughCacheManager(object):
return self.store.items()
-
class WriteBackCacheManager(object):
def __init__(self, store, size):
self.store = store
@@ -482,7 +500,6 @@ class WriteBackCacheManager(object):
return value
def get(self, key, default=None):
- """Get an item - return default (None) if not present"""
try:
return self[key]
except KeyError:
diff --git a/test.py b/test.py
index 7a4842f..6c0e6de 100644
--- a/test.py
+++ b/test.py
@@ -8,22 +8,18 @@ import random
class simplelrucache:
def __init__(self, size):
-
# Initialize the cache as empty.
self.cache = []
self.size = size
def __contains__(self, key):
-
for x in self.cache:
if x[0] == key:
return True
return False
-
def __getitem__(self, key):
-
for i in range(len(self.cache)):
x = self.cache[i]
if x[0] == key:
@@ -33,9 +29,7 @@ class simplelrucache:
raise KeyError
-
def __setitem__(self, key, value):
-
for i in range(len(self.cache)):
x = self.cache[i]
if x[0] == key:
@@ -49,9 +43,7 @@ class simplelrucache:
self.cache.append([key, value])
-
def __delitem__(self, key):
-
for i in range(len(self.cache)):
if self.cache[i][0] == key:
del self.cache[i]
@@ -67,7 +59,6 @@ class simplelrucache:
def test(a, b, c, d, verify):
-
for i in range(1000):
x = random.randint(0, 512)
y = random.randint(0, 512)
@@ -115,7 +106,6 @@ def testcache():
assert list(zip(a.keys(), a.values())) == q2
assert list(a.keys()) == list(a)
-
a = lrucache(128)
b = simplelrucache(128)
verify(a, b)
@@ -138,7 +128,6 @@ def testcache():
def wraptest():
-
def verify(p, x):
assert p == x.store
for key, value in x.cache.items():
@@ -159,9 +148,7 @@ def wraptest():
test(p, x, p, x, verify)
-
def wraptest2():
-
def verify(p, x):
for key, value in x.store.items():
if key not in x.dirty:
@@ -192,7 +179,6 @@ def wraptest2():
assert p == q
def wraptest3():
-
def verify(p, x):
for key, value in x.store.items():
if key not in x.dirty:
@@ -224,10 +210,8 @@ def testDecorator():
if __name__ == '__main__':
-
random.seed()
-
for i in range(20):
testcache()
wraptest()