gh-106004: Add PyDict_GetItemRef() function (#106005)

* Add PyDict_GetItemRef() and PyDict_GetItemStringRef() functions.
  Add these functions to the stable ABI version 3.13.
* Add unit tests on the PyDict C API in test_capi.
This commit is contained in:
Victor Stinner 2023-07-21 23:10:51 +02:00 committed by GitHub
parent 0ba07b2108
commit 41ca164551
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 308 additions and 18 deletions

View file

@ -1696,9 +1696,8 @@ PyDict_GetItem(PyObject *op, PyObject *key)
/* Ignore any exception raised by the lookup */
_PyErr_SetRaisedException(tstate, exc);
assert(ix >= 0 || value == NULL);
return value;
return value; // borrowed reference
}
Py_ssize_t
@ -1737,9 +1736,46 @@ _PyDict_GetItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash)
ix = _Py_dict_lookup(mp, key, hash, &value);
assert(ix >= 0 || value == NULL);
return value;
return value; // borrowed reference
}
int
PyDict_GetItemRef(PyObject *op, PyObject *key, PyObject **result)
{
if (!PyDict_Check(op)) {
PyErr_BadInternalCall();
*result = NULL;
return -1;
}
PyDictObject*mp = (PyDictObject *)op;
Py_hash_t hash;
if (!PyUnicode_CheckExact(key) || (hash = unicode_get_hash(key)) == -1)
{
hash = PyObject_Hash(key);
if (hash == -1) {
*result = NULL;
return -1;
}
}
PyObject *value;
Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &value);
assert(ix >= 0 || value == NULL);
if (ix == DKIX_ERROR) {
*result = NULL;
return -1;
}
if (value == NULL) {
*result = NULL;
return 0; // missing key
}
*result = Py_NewRef(value);
return 1; // key is present
}
/* Variant of PyDict_GetItem() that doesn't suppress exceptions.
This returns NULL *with* an exception set if an exception occurred.
It returns NULL *without* an exception set if the key wasn't present.
@ -1766,7 +1802,7 @@ PyDict_GetItemWithError(PyObject *op, PyObject *key)
ix = _Py_dict_lookup(mp, key, hash, &value);
assert(ix >= 0 || value == NULL);
return value;
return value; // borrowed reference
}
PyObject *
@ -1777,7 +1813,7 @@ _PyDict_GetItemWithError(PyObject *dp, PyObject *kv)
if (hash == -1) {
return NULL;
}
return _PyDict_GetItem_KnownHash(dp, kv, hash);
return _PyDict_GetItem_KnownHash(dp, kv, hash); // borrowed reference
}
PyObject *
@ -1789,7 +1825,7 @@ _PyDict_GetItemIdWithError(PyObject *dp, _Py_Identifier *key)
return NULL;
Py_hash_t hash = unicode_get_hash(kv);
assert (hash != -1); /* interned strings have their hash value initialised */
return _PyDict_GetItem_KnownHash(dp, kv, hash);
return _PyDict_GetItem_KnownHash(dp, kv, hash); // borrowed reference
}
PyObject *
@ -1802,7 +1838,7 @@ _PyDict_GetItemStringWithError(PyObject *v, const char *key)
}
rv = PyDict_GetItemWithError(v, kv);
Py_DECREF(kv);
return rv;
return rv; // borrowed reference
}
/* Fast version of global value lookup (LOAD_GLOBAL).
@ -3894,7 +3930,20 @@ PyDict_GetItemString(PyObject *v, const char *key)
}
rv = PyDict_GetItem(v, kv);
Py_DECREF(kv);
return rv;
return rv; // borrowed reference
}
int
PyDict_GetItemStringRef(PyObject *v, const char *key, PyObject **result)
{
PyObject *key_obj = PyUnicode_FromString(key);
if (key_obj == NULL) {
*result = NULL;
return -1;
}
int res = PyDict_GetItemRef(v, key_obj, result);
Py_DECREF(key_obj);
return res;
}
int
@ -5146,15 +5195,11 @@ dictitems_contains(_PyDictViewObject *dv, PyObject *obj)
return 0;
key = PyTuple_GET_ITEM(obj, 0);
value = PyTuple_GET_ITEM(obj, 1);
found = PyDict_GetItemWithError((PyObject *)dv->dv_dict, key);
if (found == NULL) {
if (PyErr_Occurred())
return -1;
return 0;
result = PyDict_GetItemRef((PyObject *)dv->dv_dict, key, &found);
if (result == 1) {
result = PyObject_RichCompareBool(found, value, Py_EQ);
Py_DECREF(found);
}
Py_INCREF(found);
result = PyObject_RichCompareBool(found, value, Py_EQ);
Py_DECREF(found);
return result;
}