From 2ff2190b6293966f76633d810dfbe2d232ff5973 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 1 Oct 2013 00:55:43 -0700 Subject: [PATCH] Issue #18594: Fix the fast path for collections.Counter(). The path wasn't being taken due to an over-restrictive type check. --- 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 index 387cadb4e4793b..20c4780e0c9fac 100644 --- a/Include/object.h +++ b/Include/object.h @@ -482,6 +482,7 @@ PyAPI_FUNC(PyObject *) PyType_GenericNew(PyTypeObject *, 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 index c787537857ada2..7898b9b592c59b 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -74,6 +74,9 @@ Library - 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 index 34a1a903afa9ec..cb1674898b3358 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1689,10 +1689,16 @@ Count elements in the iterable, updating the mappping"); 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 @@ _count_elements(PyObject *self, PyObject *args) 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 index a55d9775ded5be..3dcbc86080a98e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -49,9 +49,6 @@ _Py_IDENTIFIER(__module__); _Py_IDENTIFIER(__name__); _Py_IDENTIFIER(__new__); -static PyObject * -_PyType_LookupId(PyTypeObject *type, struct _Py_Identifier *name); - static PyObject * slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds); @@ -2589,7 +2586,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) return res; } -static PyObject * +PyObject * _PyType_LookupId(PyTypeObject *type, struct _Py_Identifier *name) { PyObject *oname;