From aed8830af3bb5a79878cf0f603ebbd8a37f5b36e Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 19 Sep 2015 09:05:42 -0700 Subject: Add a fast path (no iterator creation) for a common case for repeating deques of size 1 --- Lib/test/test_deque.py | 9 +++++++++ Modules/_collectionsmodule.c | 15 +++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py index 8718716..c61e80b 100644 --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -654,6 +654,15 @@ class TestBasic(unittest.TestCase): self.assertNotEqual(id(d), id(e)) self.assertEqual(list(d), list(e)) + for i in range(5): + for maxlen in range(-1, 6): + s = [random.random() for j in range(i)] + d = deque(s) if maxlen == -1 else deque(s, maxlen) + e = d.copy() + self.assertEqual(d, e) + self.assertEqual(d.maxlen, e.maxlen) + self.assertTrue(all(x is y for x, y in zip(d, e))) + def test_copy_method(self): mut = [10] d = deque([mut]) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index dbe44e1..3e2c69f 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1211,6 +1211,7 @@ deque_traverse(dequeobject *deque, visitproc visit, void *arg) static PyObject * deque_copy(PyObject *deque) { + dequeobject *old_deque = (dequeobject *)deque; if (Py_TYPE(deque) == &deque_type) { dequeobject *new_deque; PyObject *rv; @@ -1218,8 +1219,14 @@ deque_copy(PyObject *deque) new_deque = (dequeobject *)deque_new(&deque_type, (PyObject *)NULL, (PyObject *)NULL); if (new_deque == NULL) return NULL; - new_deque->maxlen = ((dequeobject *)deque)->maxlen; - rv = deque_extend(new_deque, deque); + new_deque->maxlen = old_deque->maxlen; + /* Fast path for the deque_repeat() common case where len(deque) == 1 */ + if (Py_SIZE(deque) == 1 && new_deque->maxlen != 0) { + PyObject *item = old_deque->leftblock->data[old_deque->leftindex]; + rv = deque_append(new_deque, item); + } else { + rv = deque_extend(new_deque, deque); + } if (rv != NULL) { Py_DECREF(rv); return (PyObject *)new_deque; @@ -1227,11 +1234,11 @@ deque_copy(PyObject *deque) Py_DECREF(new_deque); return NULL; } - if (((dequeobject *)deque)->maxlen == -1) + if (old_deque->maxlen == -1) return PyObject_CallFunction((PyObject *)(Py_TYPE(deque)), "O", deque, NULL); else return PyObject_CallFunction((PyObject *)(Py_TYPE(deque)), "Oi", - deque, ((dequeobject *)deque)->maxlen, NULL); + deque, old_deque->maxlen, NULL); } PyDoc_STRVAR(copy_doc, "Return a shallow copy of a deque."); -- cgit v0.12