]> granicus.if.org Git - python/commitdiff
Issue 23705: Improve the performance of __contains__ checks for deques.
authorRaymond Hettinger <python@rcn.com>
Fri, 20 Mar 2015 23:38:56 +0000 (16:38 -0700)
committerRaymond Hettinger <python@rcn.com>
Fri, 20 Mar 2015 23:38:56 +0000 (16:38 -0700)
Lib/test/test_deque.py
Modules/_collectionsmodule.c

index 0eebbff84127a2666aa8318ec99646ba92b8b5ff..7d694485852fa61840783cbeb1331410af602d27 100644 (file)
@@ -164,6 +164,26 @@ class TestBasic(unittest.TestCase):
                 self.assertEqual(x >  y, list(x) >  list(y), (x,y))
                 self.assertEqual(x >= y, list(x) >= list(y), (x,y))
 
+    def test_contains(self):
+        n = 200
+
+        d = deque(range(n))
+        for i in range(n):
+            self.assertTrue(i in d)
+        self.assertTrue((n+1) not in d)
+
+        # Test detection of mutation during iteration
+        d = deque(range(n))
+        d[n//2] = MutateCmp(d, False)
+        with self.assertRaises(RuntimeError):
+            n in d
+
+        # Test detection of comparison exceptions
+        d = deque(range(n))
+        d[n//2] = BadCmp()
+        with self.assertRaises(RuntimeError):
+            n in d
+
     def test_extend(self):
         d = deque('a')
         self.assertRaises(TypeError, d.extend, 1)
index d4794be08fef47f5cd0cce60111616ee1c8535ff..26a0c8ff6c860adf7a8b15a3a1ff1539b81d1b10 100644 (file)
@@ -724,6 +724,38 @@ deque_count(dequeobject *deque, PyObject *v)
 PyDoc_STRVAR(count_doc,
 "D.count(value) -> integer -- return number of occurrences of value");
 
+static int
+deque_contains(dequeobject *deque, PyObject *v)
+{
+    block *b = deque->leftblock;
+    Py_ssize_t index = deque->leftindex;
+    Py_ssize_t n = Py_SIZE(deque);
+    Py_ssize_t i;
+    size_t start_state = deque->state;
+    PyObject *item;
+    int cmp;
+
+    for (i=0 ; i<n ; i++) {
+        CHECK_NOT_END(b);
+        item = b->data[index];
+        cmp = PyObject_RichCompareBool(item, v, Py_EQ);
+        if (cmp) {
+            return cmp;
+        }
+        if (start_state != deque->state) {
+            PyErr_SetString(PyExc_RuntimeError,
+                            "deque mutated during iteration");
+            return -1;
+        }
+        index++;
+        if (index == BLOCKLEN) {
+            b = b->rightlink;
+            index = 0;
+        }
+    }
+    return 0;
+}
+
 static Py_ssize_t
 deque_len(dequeobject *deque)
 {
@@ -1154,7 +1186,7 @@ static PySequenceMethods deque_as_sequence = {
     0,                                  /* sq_slice */
     (ssizeobjargproc)deque_ass_item,    /* sq_ass_item */
     0,                                  /* sq_ass_slice */
-    0,                                  /* sq_contains */
+    (objobjproc)deque_contains,         /* sq_contains */
     (binaryfunc)deque_inplace_concat,   /* sq_inplace_concat */
     0,                                  /* sq_inplace_repeat */