diff --git a/Include/setobject.h b/Include/setobject.h --- a/Include/setobject.h +++ b/Include/setobject.h @@ -99,6 +99,7 @@ PyAPI_FUNC(int) PySet_Discard(PyObject * PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key); #ifndef Py_LIMITED_API PyAPI_FUNC(int) _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash); +PyAPI_FUNC(PyObject *) _PySet_GetItem(PyObject *set, PyObject *key); #endif PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set); #ifndef Py_LIMITED_API diff --git a/Objects/setobject.c b/Objects/setobject.c --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -651,7 +651,7 @@ set_merge(PySetObject *so, PyObject *oth } static int -set_contains_key(PySetObject *so, PyObject *key) +set_contains_key(PySetObject *so, PyObject *key, PyObject **lookup_result) { Py_hash_t hash; setentry *entry; @@ -666,7 +666,13 @@ set_contains_key(PySetObject *so, PyObje if (entry == NULL) return -1; key = entry->key; - return key != NULL && key != dummy; + if (key != NULL && key != dummy) { + if (lookup_result != NULL) + *lookup_result = key; + return 1; + } + else + return 0; } static int @@ -1853,7 +1859,7 @@ set_contains(PySetObject *so, PyObject * PyObject *tmpkey; int rv; - rv = set_contains_key(so, key); + rv = set_contains_key(so, key, NULL); if (rv == -1) { if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) return -1; @@ -1861,7 +1867,7 @@ set_contains(PySetObject *so, PyObject * tmpkey = make_new_set(&PyFrozenSet_Type, key); if (tmpkey == NULL) return -1; - rv = set_contains_key(so, tmpkey); + rv = set_contains_key(so, tmpkey, NULL); Py_DECREF(tmpkey); } return rv; @@ -2285,7 +2291,19 @@ PySet_Contains(PyObject *anyset, PyObjec PyErr_BadInternalCall(); return -1; } - return set_contains_key((PySetObject *)anyset, key); + return set_contains_key((PySetObject *)anyset, key, NULL); +} + +PyObject * +_PySet_GetItem(PyObject *set, PyObject *key) +{ + PyObject *lookup = NULL; + if (!PySet_Check(set)) { + PyErr_BadInternalCall(); + return NULL; + } + set_contains_key((PySetObject *)set, key, &lookup); + return lookup; } int diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1564,9 +1564,9 @@ unicode_dealloc(PyObject *unicode) break; case SSTATE_INTERNED_MORTAL: - /* revive dead object temporarily for DelItem */ - Py_REFCNT(unicode) = 3; - if (PyDict_DelItem(interned, unicode) != 0) + /* revive dead object temporarily for PySet_Discard */ + Py_REFCNT(unicode) = 2; + if (PySet_Discard(interned, unicode) <= 0) Py_FatalError( "deletion of interned string failed"); break; @@ -14635,7 +14635,7 @@ PyUnicode_InternInPlace(PyObject **p) if (PyUnicode_CHECK_INTERNED(s)) return; if (interned == NULL) { - interned = PyDict_New(); + interned = PySet_New(NULL); if (interned == NULL) { PyErr_Clear(); /* Don't leave an exception */ return; @@ -14645,7 +14645,7 @@ PyUnicode_InternInPlace(PyObject **p) though the key is present in the dictionary, namely when this happens during a stack overflow. */ Py_ALLOW_RECURSION - t = PyDict_GetItem(interned, s); + t = _PySet_GetItem(interned, s); Py_END_ALLOW_RECURSION if (t) { @@ -14654,17 +14654,19 @@ PyUnicode_InternInPlace(PyObject **p) *p = t; return; } + if (_PyErr_OCCURRED()) + PyErr_Clear(); PyThreadState_GET()->recursion_critical = 1; - if (PyDict_SetItem(interned, s, s) < 0) { + if (PySet_Add(interned, s) < 0) { PyErr_Clear(); PyThreadState_GET()->recursion_critical = 0; return; } PyThreadState_GET()->recursion_critical = 0; - /* The two references in interned are not counted by refcnt. + /* The reference in interned is not counted by refcnt. The deallocator will take care of this */ - Py_REFCNT(s) -= 2; + Py_REFCNT(s) -= 1; _PyUnicode_STATE(s).interned = SSTATE_INTERNED_MORTAL; } @@ -14692,17 +14694,25 @@ void _Py_ReleaseInternedUnicodeStrings(void) { PyObject *keys; - PyObject *s; + PyObject *s, *res; Py_ssize_t i, n; Py_ssize_t immortal_size = 0, mortal_size = 0; - if (interned == NULL || !PyDict_Check(interned)) + if (interned == NULL || !PySet_Check(interned)) return; - keys = PyDict_Keys(interned); - if (keys == NULL || !PyList_Check(keys)) { + keys = PyList_New(PySet_GET_SIZE(interned)); + if (keys == NULL) { PyErr_Clear(); return; } + res = _PyList_Extend((PyListObject *) keys, interned); + if (res == NULL) { + PyErr_Clear(); + Py_DECREF(keys); + return; + } + else + Py_DECREF(res); /* Since _Py_ReleaseInternedUnicodeStrings() is intended to help a leak detector, interned unicode strings are not forcibly deallocated; @@ -14723,11 +14733,11 @@ void /* XXX Shouldn't happen */ break; case SSTATE_INTERNED_IMMORTAL: - Py_REFCNT(s) += 1; + Py_REFCNT(s) += 0; immortal_size += PyUnicode_GET_LENGTH(s); break; case SSTATE_INTERNED_MORTAL: - Py_REFCNT(s) += 2; + Py_REFCNT(s) += 1; mortal_size += PyUnicode_GET_LENGTH(s); break; default: @@ -14739,7 +14749,7 @@ void "%" PY_FORMAT_SIZE_T "d/%" PY_FORMAT_SIZE_T "d " "mortal/immortal\n", mortal_size, immortal_size); Py_DECREF(keys); - PyDict_Clear(interned); + PySet_Clear(interned); Py_CLEAR(interned); }