Add utils.structures.TruncatableSet.

This commit is contained in:
Valentin Lorentz 2014-07-31 14:24:47 +02:00
parent 7057112d2d
commit 94fbea6266
2 changed files with 56 additions and 1 deletions

View File

@ -454,5 +454,40 @@ class CacheDict(collections.MutableMapping):
def __len__(self): def __len__(self):
return len(self.d) return len(self.d)
class TruncatableSet(collections.MutableSet):
"""A set that keeps track of the order of inserted elements so
the oldest can be removed."""
def __init__(self, iterable):
self._ordered_items = list(iterable)
self._items = set(self._ordered_items)
def __contains__(self, item):
return item in self._items
def __iter__(self):
return iter(self._items)
def __len__(self):
return len(self._items)
def add(self, item):
if item not in self._items:
self._items.add(item)
self._ordered_items.append(item)
def discard(self, item):
self._items.discard(item)
self._ordered_items.remove(item)
def truncate(self, size):
assert size >= 0
removed_size = len(self)-size
# I make two different cases depending on removed_size<size
# in order to make if faster if one is significantly bigger than the
# other.
if removed_size <= 0:
return
elif removed_size < size:
# If there are more kept items than removed items
for old_item in self._ordered_items[0:-size]:
self.discard(old_item)
self._ordered_items = self._ordered_items[-size:]
else:
self._ordered_items = self._ordered_items[-size:]
self._items = set(self._ordered_items)
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:

View File

@ -1133,6 +1133,26 @@ class TestCacheDict(SupyTestCase):
self.failUnless(i in d) self.failUnless(i in d)
self.failUnless(d[i] == i) self.failUnless(d[i] == i)
class TestTruncatableSet(SupyTestCase):
def testBasics(self):
s = TruncatableSet(['foo', 'bar', 'baz', 'qux'])
self.assertEqual(s, {'foo', 'bar', 'baz', 'qux'})
self.failUnless('foo' in s)
self.failUnless('bar' in s)
self.failIf('quux' in s)
s.discard('baz')
self.failUnless('foo' in s)
self.failIf('baz' in s)
s.add('quux')
self.failUnless('quux' in s)
def testTruncate(self):
s = TruncatableSet(['foo', 'bar'])
s.add('baz')
s.add('qux')
s.truncate(3)
self.assertEqual(s, {'bar', 'baz', 'qux'})
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: