]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #21101: Eliminate double hashing in the C code for collections.Counter().
authorRaymond Hettinger <python@rcn.com>
Sat, 3 May 2014 23:41:19 +0000 (16:41 -0700)
committerRaymond Hettinger <python@rcn.com>
Sat, 3 May 2014 23:41:19 +0000 (16:41 -0700)
Misc/NEWS
Modules/_collectionsmodule.c

index a50ae07fe536e265f232fb0577ddf1320fe94f61..18c943e720d58c627d8049ff43c57a28a15e005c 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -73,6 +73,9 @@ Library
   Decimal.quantize() method in the Python version.  It had never been
   present in the C version.
 
+- Issue #21101: Eliminate double hashing in the C speed-up code for
+  collections.Counter().
+
 - Issue #21321: itertools.islice() now releases the reference to the source
   iterator when the slice is exhausted.  Patch by Anton Afanasyev.
 
index 0ab4156a2476003e54dca9eee6a472a5f5e37d5c..c6c8666d81344d41e539309522c74e537571a3aa 100644 (file)
@@ -1831,18 +1831,29 @@ _count_elements(PyObject *self, PyObject *args)
     if (mapping_get != NULL && mapping_get == dict_get &&
         mapping_setitem != NULL && mapping_setitem == dict_setitem) {
         while (1) {
+            Py_hash_t hash;
+
             key = PyIter_Next(it);
             if (key == NULL)
                 break;
-            oldval = PyDict_GetItem(mapping, key);
+
+            if (!PyUnicode_CheckExact(key) ||
+                (hash = ((PyASCIIObject *) key)->hash) == -1)
+            {
+                hash = PyObject_Hash(key);
+                if (hash == -1) 
+                    goto done;
+            }
+
+            oldval = _PyDict_GetItem_KnownHash(mapping, key, hash);
             if (oldval == NULL) {
-                if (PyDict_SetItem(mapping, key, one) == -1)
+                if (_PyDict_SetItem_KnownHash(mapping, key, one, hash) == -1)
                     break;
             } else {
                 newval = PyNumber_Add(oldval, one);
                 if (newval == NULL)
                     break;
-                if (PyDict_SetItem(mapping, key, newval) == -1)
+                if (_PyDict_SetItem_KnownHash(mapping, key, newval, hash) == -1)
                     break;
                 Py_CLEAR(newval);
             }