From 3f9afd816de4067b8277bfe0241cf15d34b13e47 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Thu, 10 Dec 2009 03:03:02 +0000 Subject: [PATCH] Fix variants of deque.extend: d.extend(d) d+=d d.extendleft(d) --- Lib/test/test_deque.py | 11 ++++++++++ Misc/NEWS | 2 ++ Modules/_collectionsmodule.c | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py index cdb0dab0f04..8120e8b7835 100644 --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -136,12 +136,23 @@ class TestBasic(unittest.TestCase): self.assertRaises(TypeError, d.extend, 1) d.extend('bcd') self.assertEqual(list(d), list('abcd')) + d.extend(d) + self.assertEqual(list(d), list('abcdabcd')) + + def test_iadd(self): + d = deque('a') + d += 'bcd' + self.assertEqual(list(d), list('abcd')) + d += d + self.assertEqual(list(d), list('abcdabcd')) def test_extendleft(self): d = deque('a') self.assertRaises(TypeError, d.extendleft, 1) d.extendleft('bcd') self.assertEqual(list(d), list(reversed('abcd'))) + d.extendleft(d) + self.assertEqual(list(d), list('abcddcba')) d = deque() d.extendleft(range(1000)) self.assertEqual(list(d), list(reversed(range(1000)))) diff --git a/Misc/NEWS b/Misc/NEWS index b99dbeff8e8..8f051b74ea3 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -159,6 +159,8 @@ Library - Add a reverse() method to collections.deque(). +- Fix variations of extending deques: d.extend(d) d.extendleft(d) d+=d + - Issue #6986: Fix crash in the JSON C accelerator when called with the wrong parameter types. Patch by Victor Stinner. diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index cdcf4ef9884..ffb2a8066d9 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -298,6 +298,17 @@ deque_extend(dequeobject *deque, PyObject *iterable) { PyObject *it, *item; + /* Handle case where id(deque) == id(iterable) */ + if ((PyObject *)deque == iterable) { + PyObject *result; + PyObject *s = PySequence_List(iterable); + if (s == NULL) + return NULL; + result = deque_extend(deque, s); + Py_DECREF(s); + return result; + } + it = PyObject_GetIter(iterable); if (it == NULL) return NULL; @@ -339,6 +350,17 @@ deque_extendleft(dequeobject *deque, PyObject *iterable) { PyObject *it, *item; + /* Handle case where id(deque) == id(iterable) */ + if ((PyObject *)deque == iterable) { + PyObject *result; + PyObject *s = PySequence_List(iterable); + if (s == NULL) + return NULL; + result = deque_extendleft(deque, s); + Py_DECREF(s); + return result; + } + it = PyObject_GetIter(iterable); if (it == NULL) return NULL; @@ -375,6 +397,19 @@ deque_extendleft(dequeobject *deque, PyObject *iterable) PyDoc_STRVAR(extendleft_doc, "Extend the left side of the deque with elements from the iterable"); +static PyObject * +deque_inplace_concat(dequeobject *deque, PyObject *other) +{ + PyObject *result; + + result = deque_extend(deque, other); + if (result == NULL) + return result; + Py_DECREF(result); + Py_INCREF(deque); + return (PyObject *)deque; +} + static int _deque_rotate(dequeobject *deque, Py_ssize_t n) { @@ -875,6 +910,11 @@ static PySequenceMethods deque_as_sequence = { (ssizeargfunc)deque_item, /* sq_item */ 0, /* sq_slice */ (ssizeobjargproc)deque_ass_item, /* sq_ass_item */ + 0, /* sq_ass_slice */ + 0, /* sq_contains */ + (binaryfunc)deque_inplace_concat, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ + }; /* deque object ********************************************************/