| # Copyright (C) 2011 Google Inc. All rights reserved. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are |
| # met: |
| # |
| # * Redistributions of source code must retain the above copyright |
| # notice, this list of conditions and the following disclaimer. |
| # * Redistributions in binary form must reproduce the above |
| # copyright notice, this list of conditions and the following disclaimer |
| # in the documentation and/or other materials provided with the |
| # distribution. |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| |
| class Node(): |
| def __init__(self, key, value): |
| self.key = key |
| self.value = value |
| self.prev = None |
| self.next = None |
| |
| |
| class LRUCache(): |
| """An implementation of Least Recently Used (LRU) Cache.""" |
| |
| def __init__(self, capacity): |
| """Initializes a lru cache with the given capacity. |
| |
| Args: |
| capacity: The capacity of the cache. |
| """ |
| assert capacity > 0, "capacity (%s) must be greater than zero." % capacity |
| self._first = None |
| self._last = None |
| self._dict = {} |
| self._capacity = capacity |
| |
| def __setitem__(self, key, value): |
| if key in self._dict: |
| self.__delitem__(key) |
| if not self._first: |
| self._one_node(key, value) |
| return |
| if len(self._dict) >= self._capacity: |
| del self._dict[self._last.key] |
| if self._capacity == 1: |
| self._one_node(key, value) |
| return |
| self._last = self._last.next |
| self._last.prev = None |
| node = Node(key, value) |
| node.prev = self._first |
| self._first.next = node |
| self._first = node |
| self._dict[key] = node |
| |
| def _one_node(self, key, value): |
| node = Node(key, value) |
| self._dict[key] = node |
| self._first = node |
| self._last = node |
| |
| def __getitem__(self, key): |
| if not self._first: |
| raise KeyError(str(key)) |
| if self._first.key == key: |
| return self._first.value |
| |
| if self._last.key == key: |
| next_last = self._last.next |
| next_last.prev = None |
| next_first = self._last |
| next_first.prev = self._first |
| next_first.next = None |
| self._first.next = next_first |
| self._first = next_first |
| self._last = next_last |
| return self._first.value |
| |
| node = self._dict[key] |
| node.next.prev = node.prev |
| node.prev.next = node.next |
| node.prev = self._first |
| node.next = None |
| self._first.next = node |
| self._first = node |
| return self._first.value |
| |
| def __delitem__(self, key): |
| node = self._dict[key] |
| del self._dict[key] |
| if self._first is self._last: |
| self._last = None |
| self._first = None |
| return |
| if self._first is node: |
| self._first = node.prev |
| self._first.next = None |
| return |
| if self._last is node: |
| self._last = node.next |
| self._last.prev = None |
| return |
| node.next.prev = node.prev |
| node.prev.next = node.next |
| |
| def __len__(self): |
| return len(self._dict) |
| |
| def __contains__(self, key): |
| return key in self._dict |
| |
| def __iter__(self): |
| return iter(self._dict) |
| |
| def items(self): |
| return [(key, node.value) for key, node in self._dict.items()] |
| |
| def values(self): |
| return [node.value for node in self._dict.values()] |
| |
| def keys(self): |
| return self._dict.keys() |