[Python-checkins] cpython (3.3): Issue #18594: Fix the fast path for collections.Counter().

raymond.hettinger python-checkins at python.org
Tue Oct 1 10:01:15 CEST 2013


http://hg.python.org/cpython/rev/6aef095fdb30
changeset:   85909:6aef095fdb30
branch:      3.3
parent:      85907:0e204fbb0b08
user:        Raymond Hettinger <python at rcn.com>
date:        Tue Oct 01 00:55:43 2013 -0700
summary:
  Issue #18594: Fix the fast path for collections.Counter().

The path wasn't being taken due to an over-restrictive type check.

files:
  Include/object.h             |   1 +
  Misc/NEWS                    |   3 +++
  Modules/_collectionsmodule.c |  16 +++++++++++++++-
  Objects/typeobject.c         |   5 +----
  4 files changed, 20 insertions(+), 5 deletions(-)


diff --git a/Include/object.h b/Include/object.h
--- a/Include/object.h
+++ b/Include/object.h
@@ -482,6 +482,7 @@
                                                PyObject *, PyObject *);
 #ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
+PyAPI_FUNC(PyObject *) _PyType_LookupId(PyTypeObject *, _Py_Identifier *);
 PyAPI_FUNC(PyObject *) _PyObject_LookupSpecial(PyObject *, _Py_Identifier *);
 PyAPI_FUNC(PyTypeObject *) _PyType_CalculateMetaclass(PyTypeObject *, PyObject *);
 #endif
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -74,6 +74,9 @@
 - Issue #12641: Avoid passing "-mno-cygwin" to the mingw32 compiler, except
   when necessary.  Patch by Oscar Benjamin.
 
+- Issue #18594: The fast path for collections.Counter() was never taken
+  due to an over-restrictive type check.
+
 - Properly initialize all fields of a SSL object after allocation.
 
 - Issue #4366: Fix building extensions on all platforms when --enable-shared
diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c
--- a/Modules/_collectionsmodule.c
+++ b/Modules/_collectionsmodule.c
@@ -1689,10 +1689,16 @@
 static PyObject *
 _count_elements(PyObject *self, PyObject *args)
 {
+    _Py_IDENTIFIER(__getitem__);
+    _Py_IDENTIFIER(__setitem__);
     PyObject *it, *iterable, *mapping, *oldval;
     PyObject *newval = NULL;
     PyObject *key = NULL;
     PyObject *one = NULL;
+    PyObject *mapping_getitem;
+    PyObject *mapping_setitem;
+    PyObject *dict_getitem;
+    PyObject *dict_setitem;
 
     if (!PyArg_UnpackTuple(args, "_count_elements", 2, 2, &mapping, &iterable))
         return NULL;
@@ -1707,7 +1713,15 @@
         return NULL;
     }
 
-    if (PyDict_CheckExact(mapping)) {
+    mapping_getitem = _PyType_LookupId(Py_TYPE(mapping), &PyId___getitem__);
+    dict_getitem = _PyType_LookupId(&PyDict_Type, &PyId___getitem__);
+    mapping_setitem = _PyType_LookupId(Py_TYPE(mapping), &PyId___setitem__);
+    dict_setitem = _PyType_LookupId(&PyDict_Type, &PyId___setitem__);
+
+    if (mapping_getitem != NULL &&
+        mapping_getitem == dict_getitem &&
+        mapping_setitem != NULL &&
+        mapping_setitem == dict_setitem) {
         while (1) {
             key = PyIter_Next(it);
             if (key == NULL)
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -50,9 +50,6 @@
 _Py_IDENTIFIER(__new__);
 
 static PyObject *
-_PyType_LookupId(PyTypeObject *type, struct _Py_Identifier *name);
-
-static PyObject *
 slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
 
 unsigned int
@@ -2589,7 +2586,7 @@
     return res;
 }
 
-static PyObject *
+PyObject *
 _PyType_LookupId(PyTypeObject *type, struct _Py_Identifier *name)
 {
     PyObject *oname;

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list