diff --git a/README.rst b/README.rst index c669adb..58e074e 100644 --- a/README.rst +++ b/README.rst @@ -16,11 +16,18 @@ This can be used to build a LRU cache. Usage is almost like a dict. from lru import LRU l = LRU(5) # Create an LRU container that can hold 5 items + + print l.peek_first_item(), l.peek_last_item() #return the MRU key and LRU key + # Would print None None + for i in range(5): l[i] = str(i) print l.items() # Prints items in MRU order # Would print [(4, '4'), (3, '3'), (2, '2'), (1, '1'), (0, '0')] + print l.peek_first_item(), l.peek_last_item() #return the MRU key and LRU key + # Would print (4, '4') (0, '0') + l[5] = '5' # Inserting one more item should evict the old item print l.items() # Would print [(5, '5'), (4, '4'), (3, '3'), (2, '2'), (1, '1')] @@ -87,4 +94,3 @@ be similar with other python implementations as well). Time : 3.31 s, Memory : 453672 Kb $ python bench.py lru.LRU Time : 0.23 s, Memory : 124328 Kb - diff --git a/lru.c b/lru.c index 962b31e..13fbfa4 100644 --- a/lru.c +++ b/lru.c @@ -167,7 +167,7 @@ static void lru_delete_last(LRU *self) { Node* n = self->last; - + if (!self->last) return; @@ -238,7 +238,7 @@ LRU_get(LRU *self, PyObject *args) if (!PyArg_ParseTuple(args, "O|O", &key, &instead)) return NULL; - + result = lru_subscript(self, key); PyErr_Clear(); /* GET_NODE sets an exception on miss. Shut it up. */ if (result) @@ -332,6 +332,34 @@ get_key(Node *node) return node->key; } +static PyObject * +LRU_peek_first_item(LRU *self) +{ + if (self->first) { + PyObject *tuple = PyTuple_New(2); + Py_INCREF(self->first->key); + PyTuple_SET_ITEM(tuple, 0, self->first->key); + Py_INCREF(self->first->value); + PyTuple_SET_ITEM(tuple, 1, self->first->value); + return tuple; + } + else Py_RETURN_NONE; +} + +static PyObject * +LRU_peek_last_item(LRU *self) +{ + if (self->last) { + PyObject *tuple = PyTuple_New(2); + Py_INCREF(self->last->key); + PyTuple_SET_ITEM(tuple, 0, self->last->key); + Py_INCREF(self->last->value); + PyTuple_SET_ITEM(tuple, 1, self->last->value); + return tuple; + } + else Py_RETURN_NONE; +} + static PyObject * LRU_keys(LRU *self) { return collect(self, get_key); @@ -451,6 +479,10 @@ static PyMethodDef LRU_methods[] = { PyDoc_STR("L.clear() -> clear LRU")}, {"get_stats", (PyCFunction)LRU_get_stats, METH_NOARGS, PyDoc_STR("L.get_stats() -> returns a tuple with cache hits and misses")}, + {"peek_first_item", (PyCFunction)LRU_peek_first_item, METH_NOARGS, + PyDoc_STR("L.peek_first_item() -> returns the MRU item (key,value) without changing key order")}, + {"peek_last_item", (PyCFunction)LRU_peek_last_item, METH_NOARGS, + PyDoc_STR("L.peek_last_item() -> returns the LRU item (key,value) without changing key order")}, {NULL, NULL}, }; diff --git a/test/test_lru.py b/test/test_lru.py index 0e7d965..3a2f9fd 100644 --- a/test/test_lru.py +++ b/test/test_lru.py @@ -106,6 +106,20 @@ def test_access(self): self.assertEqual(l[i], str(i)) self.assertEqual(l.get(i,None), str(i)) + def test_peek_first_item(self): + l = LRU(2) + self.assertEqual(None, l.peek_first_item()) + l[1] = '1' + l[2] = '2' + self.assertEqual((2, '2'), l.peek_first_item()) + + def test_peek_last_item(self): + l = LRU(2) + self.assertEqual(None, l.peek_last_item()) + l[1] = '1' + l[2] = '2' + self.assertEqual((1, '1'), l.peek_last_item()) + def test_overwrite(self): l = LRU(1) l[1] = '2'