From 0bbbfc4c0b0cf84a23d2644080d09fb8af5324d2 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 20 Mar 2007 21:27:24 +0000 Subject: [PATCH] Extend work on rev 52962 and 53829 eliminating redundant PyObject_Hash() calls and fixing set/dict interoperability. --- Include/setobject.h | 3 ++- Lib/test/test_set.py | 4 ++++ Objects/dictobject.c | 18 ++++++++++++++++++ Objects/setobject.c | 20 ++++++++++++++++++-- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/Include/setobject.h b/Include/setobject.h index a16c2f7cdcf..750a2a8a21f 100644 --- a/Include/setobject.h +++ b/Include/setobject.h @@ -82,7 +82,8 @@ PyAPI_FUNC(int) PySet_Clear(PyObject *set); PyAPI_FUNC(int) PySet_Contains(PyObject *anyset, PyObject *key); PyAPI_FUNC(int) PySet_Discard(PyObject *set, PyObject *key); PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key); -PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **entry); +PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **key); +PyAPI_FUNC(int) _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, long *hash); PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set); PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable); diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py index 28924d49dd2..e6e0ba6b5b1 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -288,6 +288,10 @@ class TestJointOps(unittest.TestCase): self.assertEqual(sum(elem.hash_count for elem in d), n) if hasattr(s, 'symmetric_difference_update'): s.symmetric_difference_update(d) + self.assertEqual(sum(elem.hash_count for elem in d), n) + d2 = dict.fromkeys(set(d)) + self.assertEqual(sum(elem.hash_count for elem in d), n) + d3 = dict.fromkeys(frozenset(d)) self.assertEqual(sum(elem.hash_count for elem in d), n) class TestSet(TestJointOps): diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 587dad390e6..06cc4a8bd9f 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1175,6 +1175,24 @@ dict_fromkeys(PyObject *cls, PyObject *args) if (d == NULL) return NULL; + if (PyDict_CheckExact(d) && PyAnySet_CheckExact(seq)) { + dictobject *mp = (dictobject *)d; + Py_ssize_t pos = 0; + PyObject *key; + long hash; + + if (dictresize(mp, PySet_GET_SIZE(seq))) + return NULL; + + while (_PySet_NextEntry(seq, &pos, &key, &hash)) { + Py_INCREF(key); + Py_INCREF(Py_None); + if (insertdict(mp, key, hash, Py_None)) + return NULL; + } + return d; + } + it = PyObject_GetIter(seq); if (it == NULL){ Py_DECREF(d); diff --git a/Objects/setobject.c b/Objects/setobject.c index 07ba99641c3..a896d937fae 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -2137,7 +2137,7 @@ PySet_Add(PyObject *set, PyObject *key) } int -_PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **entry) +_PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **key) { setentry *entry_ptr; @@ -2147,7 +2147,23 @@ _PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **entry) } if (set_next((PySetObject *)set, pos, &entry_ptr) == 0) return 0; - *entry = entry_ptr->key; + *key = entry_ptr->key; + return 1; +} + +int +_PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, long *hash) +{ + setentry *entry; + + if (!PyAnySet_Check(set)) { + PyErr_BadInternalCall(); + return -1; + } + if (set_next((PySetObject *)set, pos, &entry) == 0) + return 0; + *key = entry->key; + *hash = entry->hash; return 1; }