summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2023-07-21 21:10:51 (GMT)
committerGitHub <noreply@github.com>2023-07-21 21:10:51 (GMT)
commit41ca16455188db806bfc7037058e8ecff2755e6c (patch)
tree925ab5df83f04657ea3b4be058c104556b094424 /Objects
parent0ba07b2108d4763273f3fb85544dde34c5acd40a (diff)
downloadcpython-41ca16455188db806bfc7037058e8ecff2755e6c.zip
cpython-41ca16455188db806bfc7037058e8ecff2755e6c.tar.gz
cpython-41ca16455188db806bfc7037058e8ecff2755e6c.tar.bz2
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.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/dictobject.c77
1 files changed, 61 insertions, 16 deletions
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 013c218..3f9297c 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -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;
}