mirror of
https://github.com/python/cpython
synced 2026-09-29 12:10:30 +03:00
gh-111262: Add PyDict_Pop() function (#112028)
_PyDict_Pop_KnownHash(): remove the default value and the return type becomes an int. Co-authored-by: Stefan Behnel <stefan_ml@behnel.de> Co-authored-by: Antoine Pitrou <pitrou@free.fr>
This commit is contained in:
parent
f44d6ff6e0
commit
4f04172c92
15 changed files with 338 additions and 76 deletions
|
|
@ -1087,19 +1087,9 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
|
|||
The cache dict holds one reference to the link.
|
||||
We created one other reference when the link was created.
|
||||
The linked list only has borrowed references. */
|
||||
popresult = _PyDict_Pop_KnownHash(self->cache, link->key,
|
||||
link->hash, Py_None);
|
||||
if (popresult == Py_None) {
|
||||
/* Getting here means that the user function call or another
|
||||
thread has already removed the old key from the dictionary.
|
||||
This link is now an orphan. Since we don't want to leave the
|
||||
cache in an inconsistent state, we don't restore the link. */
|
||||
Py_DECREF(popresult);
|
||||
Py_DECREF(link);
|
||||
Py_DECREF(key);
|
||||
return result;
|
||||
}
|
||||
if (popresult == NULL) {
|
||||
int res = _PyDict_Pop_KnownHash((PyDictObject*)self->cache, link->key,
|
||||
link->hash, &popresult);
|
||||
if (res < 0) {
|
||||
/* An error arose while trying to remove the oldest key (the one
|
||||
being evicted) from the cache. We restore the link to its
|
||||
original position as the oldest link. Then we allow the
|
||||
|
|
@ -1110,10 +1100,22 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
|
|||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
if (res == 0) {
|
||||
/* Getting here means that the user function call or another
|
||||
thread has already removed the old key from the dictionary.
|
||||
This link is now an orphan. Since we don't want to leave the
|
||||
cache in an inconsistent state, we don't restore the link. */
|
||||
assert(popresult == NULL);
|
||||
Py_DECREF(link);
|
||||
Py_DECREF(key);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Keep a reference to the old key and old result to prevent their
|
||||
ref counts from going to zero during the update. That will
|
||||
prevent potentially arbitrary object clean-up code (i.e. __del__)
|
||||
from running while we're still adjusting the links. */
|
||||
assert(popresult != NULL);
|
||||
oldkey = link->key;
|
||||
oldresult = link->result;
|
||||
|
||||
|
|
|
|||
|
|
@ -331,6 +331,88 @@ dict_mergefromseq2(PyObject *self, PyObject *args)
|
|||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
dict_pop(PyObject *self, PyObject *args)
|
||||
{
|
||||
// Test PyDict_Pop(dict, key, &value)
|
||||
PyObject *dict, *key;
|
||||
if (!PyArg_ParseTuple(args, "OO", &dict, &key)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(dict);
|
||||
NULLABLE(key);
|
||||
PyObject *result = UNINITIALIZED_PTR;
|
||||
int res = PyDict_Pop(dict, key, &result);
|
||||
if (res < 0) {
|
||||
assert(result == NULL);
|
||||
return NULL;
|
||||
}
|
||||
if (res == 0) {
|
||||
assert(result == NULL);
|
||||
result = Py_NewRef(Py_None);
|
||||
}
|
||||
else {
|
||||
assert(result != NULL);
|
||||
}
|
||||
return Py_BuildValue("iN", res, result);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
dict_pop_null(PyObject *self, PyObject *args)
|
||||
{
|
||||
// Test PyDict_Pop(dict, key, NULL)
|
||||
PyObject *dict, *key;
|
||||
if (!PyArg_ParseTuple(args, "OO", &dict, &key)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(dict);
|
||||
NULLABLE(key);
|
||||
RETURN_INT(PyDict_Pop(dict, key, NULL));
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
dict_popstring(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *dict;
|
||||
const char *key;
|
||||
Py_ssize_t key_size;
|
||||
if (!PyArg_ParseTuple(args, "Oz#", &dict, &key, &key_size)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(dict);
|
||||
PyObject *result = UNINITIALIZED_PTR;
|
||||
int res = PyDict_PopString(dict, key, &result);
|
||||
if (res < 0) {
|
||||
assert(result == NULL);
|
||||
return NULL;
|
||||
}
|
||||
if (res == 0) {
|
||||
assert(result == NULL);
|
||||
result = Py_NewRef(Py_None);
|
||||
}
|
||||
else {
|
||||
assert(result != NULL);
|
||||
}
|
||||
return Py_BuildValue("iN", res, result);
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
dict_popstring_null(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *dict;
|
||||
const char *key;
|
||||
Py_ssize_t key_size;
|
||||
if (!PyArg_ParseTuple(args, "Oz#", &dict, &key, &key_size)) {
|
||||
return NULL;
|
||||
}
|
||||
NULLABLE(dict);
|
||||
RETURN_INT(PyDict_PopString(dict, key, NULL));
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
{"dict_check", dict_check, METH_O},
|
||||
{"dict_checkexact", dict_checkexact, METH_O},
|
||||
|
|
@ -358,7 +440,10 @@ static PyMethodDef test_methods[] = {
|
|||
{"dict_merge", dict_merge, METH_VARARGS},
|
||||
{"dict_update", dict_update, METH_VARARGS},
|
||||
{"dict_mergefromseq2", dict_mergefromseq2, METH_VARARGS},
|
||||
|
||||
{"dict_pop", dict_pop, METH_VARARGS},
|
||||
{"dict_pop_null", dict_pop_null, METH_VARARGS},
|
||||
{"dict_popstring", dict_popstring, METH_VARARGS},
|
||||
{"dict_popstring_null", dict_popstring_null, METH_VARARGS},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -967,11 +967,8 @@ local_clear(localobject *self)
|
|||
HEAD_UNLOCK(runtime);
|
||||
while (tstate) {
|
||||
if (tstate->dict) {
|
||||
PyObject *v = _PyDict_Pop(tstate->dict, self->key, Py_None);
|
||||
if (v != NULL) {
|
||||
Py_DECREF(v);
|
||||
}
|
||||
else {
|
||||
if (PyDict_Pop(tstate->dict, self->key, NULL) < 0) {
|
||||
// Silently ignore error
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -392,16 +392,10 @@ remove_unusable_flags(PyObject *m)
|
|||
break;
|
||||
}
|
||||
else {
|
||||
PyObject *flag_name = PyUnicode_FromString(win_runtime_flags[i].flag_name);
|
||||
if (flag_name == NULL) {
|
||||
if (PyDict_PopString(dict, win_runtime_flags[i].flag_name,
|
||||
NULL) < 0) {
|
||||
return -1;
|
||||
}
|
||||
PyObject *v = _PyDict_Pop(dict, flag_name, Py_None);
|
||||
Py_DECREF(flag_name);
|
||||
if (v == NULL) {
|
||||
return -1;
|
||||
}
|
||||
Py_DECREF(v);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue