Skip to content
Snippets Groups Projects
lru_cache.py 4.16 KiB
Newer Older
  • Learn to ignore specific revisions
  • import operator
    import sys
    import itertools
    
    
    _IS_PY3 = sys.version_info[0] == 3
    
    class LRUCache(object):
        '''
        This LRU cache should be reasonable for short collections (until around 100 items), as it does a
        sort on the items if the collection would become too big (so, it is very fast for getting and
        setting but when its size would become higher than the max size it does one sort based on the
    
    Luke Campagnola's avatar
    Luke Campagnola committed
        internal time to decide which items should be removed -- which should be Ok if the resizeTo
        isn't too close to the maxSize so that it becomes an operation that doesn't happen all the
    
    Luke Campagnola's avatar
    Luke Campagnola committed
        def __init__(self, maxSize=100, resizeTo=70):
    
    Luke Campagnola's avatar
    Luke Campagnola committed
            ============== =========================================================
            **Arguments:**
            maxSize        (int) This is the maximum size of the cache. When some 
                           item is added and the cache would become bigger than 
                           this, it's resized to the value passed on resizeTo.
            resizeTo       (int) When a resize operation happens, this is the size 
                           of the final cache.
            ============== =========================================================
    
    Luke Campagnola's avatar
    Luke Campagnola committed
            assert resizeTo < maxSize
            self.maxSize = maxSize
            self.resizeTo = resizeTo
    
            self._counter = 0
            self._dict = {}
            if _IS_PY3:
    
    Luke Campagnola's avatar
    Luke Campagnola committed
                self._nextTime = itertools.count(0).__next__
    
    Luke Campagnola's avatar
    Luke Campagnola committed
                self._nextTime = itertools.count(0).next
    
    
        def __getitem__(self, key):
            item = self._dict[key]
    
    Luke Campagnola's avatar
    Luke Campagnola committed
            item[2] = self._nextTime()
    
            return item[1]
    
        def __len__(self):
            return len(self._dict)
    
        def __setitem__(self, key, value):
            item = self._dict.get(key)
            if item is None:
    
    Luke Campagnola's avatar
    Luke Campagnola committed
                if len(self._dict) + 1 > self.maxSize:
                    self._resizeTo()
    
    Luke Campagnola's avatar
    Luke Campagnola committed
                item = [key, value, self._nextTime()]
    
                self._dict[key] = item
            else:
                item[1] = value
    
    Luke Campagnola's avatar
    Luke Campagnola committed
                item[2] = self._nextTime()
    
                
        def __delitem__(self, key):
            del self._dict[key]
            
        def get(self, key, default=None):
            try:
                return self[key]
            except KeyError:
                return default
            
        def clear(self):
            self._dict.clear()
     
        if _IS_PY3:
            def values(self):
                return [i[1] for i in self._dict.values()]
            
            def keys(self):
                return [x[0] for x in self._dict.values()]
            
    
    Luke Campagnola's avatar
    Luke Campagnola committed
            def _resizeTo(self):
                ordered = sorted(self._dict.values(), key=operator.itemgetter(2))[:self.resizeTo]
    
                for i in ordered:
                    del self._dict[i[0]]
                    
    
    Luke Campagnola's avatar
    Luke Campagnola committed
            def iteritems(self, accessTime=False):
    
    Luke Campagnola's avatar
    Luke Campagnola committed
                :param bool accessTime:
    
                    If True sorts the returned items by the internal access time.
                '''
    
    Luke Campagnola's avatar
    Luke Campagnola committed
                if accessTime:
    
                    for x in sorted(self._dict.values(), key=operator.itemgetter(2)):
                        yield x[0], x[1]
                else:
                    for x in self._dict.items():
                        yield x[0], x[1]
                        
        else:
            def values(self):
                return [i[1] for i in self._dict.itervalues()]
            
            def keys(self):
                return [x[0] for x in self._dict.itervalues()]
                
            
    
    Luke Campagnola's avatar
    Luke Campagnola committed
            def _resizeTo(self):
                ordered = sorted(self._dict.itervalues(), key=operator.itemgetter(2))[:self.resizeTo]
    
                for i in ordered:
                    del self._dict[i[0]]
                    
    
    Luke Campagnola's avatar
    Luke Campagnola committed
            def iteritems(self, accessTime=False):
    
    Luke Campagnola's avatar
    Luke Campagnola committed
                ============= ======================================================
                **Arguments**
                accessTime    (bool) If True sorts the returned items by the 
                              internal access time.
                ============= ======================================================
    
    Luke Campagnola's avatar
    Luke Campagnola committed
                if accessTime:
    
                    for x in sorted(self._dict.itervalues(), key=operator.itemgetter(2)):
                        yield x[0], x[1]
                else:
                    for x in self._dict.iteritems():
                        yield x[0], x[1]