}
+static PyObject *
+test_dict_capi(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
+{
+ assert(!PyErr_Occurred());
+
+ PyObject *dict= NULL, *key = NULL, *missing_key = NULL, *value = NULL;
+ PyObject *invalid_key = NULL;
+ int res;
+
+ // test PyDict_New()
+ dict = PyDict_New();
+ if (dict == NULL) {
+ goto error;
+ }
+
+ key = PyUnicode_FromString("key");
+ if (key == NULL) {
+ goto error;
+ }
+
+ missing_key = PyUnicode_FromString("missing_key");
+ if (missing_key == NULL) {
+ goto error;
+ }
+
+ value = PyUnicode_FromString("value");
+ if (value == NULL) {
+ goto error;
+ }
+
+ // test PyDict_SetItem()
+ Py_ssize_t key_refcnt = Py_REFCNT(key);
+ Py_ssize_t value_refcnt = Py_REFCNT(value);
+ res = PyDict_SetItem(dict, key, value);
+ if (res < 0) {
+ goto error;
+ }
+ assert(res == 0);
+ assert(Py_REFCNT(key) == (key_refcnt + 1));
+ assert(Py_REFCNT(value) == (value_refcnt + 1));
+
+ // test PyDict_SetItemString()
+ res = PyDict_SetItemString(dict, "key", value);
+ if (res < 0) {
+ goto error;
+ }
+ assert(res == 0);
+ assert(Py_REFCNT(key) == (key_refcnt + 1));
+ assert(Py_REFCNT(value) == (value_refcnt + 1));
+
+ // test PyDict_Size()
+ assert(PyDict_Size(dict) == 1);
+
+ // test PyDict_Contains(), key is present
+ assert(PyDict_Contains(dict, key) == 1);
+
+ // test PyDict_GetItem(), key is present
+ assert(PyDict_GetItem(dict, key) == value);
+
+ // test PyDict_GetItemString(), key is present
+ assert(PyDict_GetItemString(dict, "key") == value);
+
+ // test PyDict_GetItemWithError(), key is present
+ assert(PyDict_GetItemWithError(dict, key) == value);
+ assert(!PyErr_Occurred());
+
+ // test PyDict_GetItemRef(), key is present
+ PyObject *get_value = Py_Ellipsis; // marker value
+ assert(PyDict_GetItemRef(dict, key, &get_value) == 1);
+ assert(get_value == value);
+ Py_DECREF(get_value);
+
+ // test PyDict_GetItemStringRef(), key is present
+ get_value = Py_Ellipsis; // marker value
+ assert(PyDict_GetItemStringRef(dict, "key", &get_value) == 1);
+ assert(get_value == value);
+ Py_DECREF(get_value);
+
+ // test PyDict_Contains(), missing key
+ assert(PyDict_Contains(dict, missing_key) == 0);
+
+ // test PyDict_GetItem(), missing key
+ assert(PyDict_GetItem(dict, missing_key) == NULL);
+ assert(!PyErr_Occurred());
+
+ // test PyDict_GetItemString(), missing key
+ assert(PyDict_GetItemString(dict, "missing_key") == NULL);
+ assert(!PyErr_Occurred());
+
+ // test PyDict_GetItemWithError(), missing key
+ assert(PyDict_GetItem(dict, missing_key) == NULL);
+ assert(!PyErr_Occurred());
+
+ // test PyDict_GetItemRef(), missing key
+ get_value = Py_Ellipsis; // marker value
+ assert(PyDict_GetItemRef(dict, missing_key, &get_value) == 0);
+ assert(!PyErr_Occurred());
+ assert(get_value == NULL);
+
+ // test PyDict_GetItemStringRef(), missing key
+ get_value = Py_Ellipsis; // marker value
+ assert(PyDict_GetItemStringRef(dict, "missing_key", &get_value) == 0);
+ assert(!PyErr_Occurred());
+ assert(get_value == NULL);
+
+ // test PyDict_GetItem(), invalid dict
+ PyObject *invalid_dict = key; // borrowed reference
+ assert(PyDict_GetItem(invalid_dict, key) == NULL);
+ assert(!PyErr_Occurred());
+
+ // test PyDict_GetItemWithError(), invalid dict
+ assert(PyDict_GetItemWithError(invalid_dict, key) == NULL);
+ assert(PyErr_ExceptionMatches(PyExc_SystemError));
+ PyErr_Clear();
+
+ // test PyDict_GetItemRef(), invalid dict
+ get_value = Py_Ellipsis; // marker value
+ assert(PyDict_GetItemRef(invalid_dict, key, &get_value) == -1);
+ assert(PyErr_ExceptionMatches(PyExc_SystemError));
+ PyErr_Clear();
+ assert(get_value == NULL);
+
+ // test PyDict_GetItemStringRef(), invalid dict
+ get_value = Py_Ellipsis; // marker value
+ assert(PyDict_GetItemStringRef(invalid_dict, "key", &get_value) == -1);
+ assert(PyErr_ExceptionMatches(PyExc_SystemError));
+ PyErr_Clear();
+ assert(get_value == NULL);
+
+ invalid_key = PyList_New(0);
+ if (invalid_key == NULL) {
+ goto error;
+ }
+
+ // test PyDict_Contains(), invalid key
+ assert(PyDict_Contains(dict, invalid_key) == -1);
+ assert(PyErr_ExceptionMatches(PyExc_TypeError));
+ PyErr_Clear();
+
+ // test PyDict_GetItem(), invalid key
+ assert(PyDict_GetItem(dict, invalid_key) == NULL);
+ assert(!PyErr_Occurred());
+
+ // test PyDict_GetItemWithError(), invalid key
+ assert(PyDict_GetItemWithError(dict, invalid_key) == NULL);
+ assert(PyErr_ExceptionMatches(PyExc_TypeError));
+ PyErr_Clear();
+
+ // test PyDict_GetItemRef(), invalid key
+ get_value = Py_Ellipsis; // marker value
+ assert(PyDict_GetItemRef(dict, invalid_key, &get_value) == -1);
+ assert(PyErr_ExceptionMatches(PyExc_TypeError));
+ PyErr_Clear();
+ assert(get_value == NULL);
+
+ // test PyDict_DelItem(), key is present
+ assert(PyDict_DelItem(dict, key) == 0);
+ assert(PyDict_Size(dict) == 0);
+
+ // test PyDict_DelItem(), missing key
+ assert(PyDict_DelItem(dict, missing_key) == -1);
+ assert(PyErr_ExceptionMatches(PyExc_KeyError));
+ PyErr_Clear();
+
+ // test PyDict_DelItem(), invalid key
+ assert(PyDict_DelItem(dict, invalid_key) == -1);
+ assert(PyErr_ExceptionMatches(PyExc_TypeError));
+ PyErr_Clear();
+
+ // test PyDict_Clear()
+ PyDict_Clear(dict);
+
+ Py_DECREF(dict);
+ Py_DECREF(key);
+ Py_DECREF(missing_key);
+ Py_DECREF(value);
+ Py_DECREF(invalid_key);
+
+ Py_RETURN_NONE;
+
+error:
+ Py_XDECREF(dict);
+ Py_XDECREF(key);
+ Py_XDECREF(missing_key);
+ Py_XDECREF(value);
+ Py_XDECREF(invalid_key);
+ return NULL;
+}
+
+
static PyMethodDef TestMethods[] = {
{"set_errno", set_errno, METH_VARARGS},
{"test_config", test_config, METH_NOARGS},
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
{"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS},
{"test_weakref_capi", test_weakref_capi, METH_NOARGS},
+ {"test_dict_capi", test_dict_capi, METH_NOARGS},
{NULL, NULL} /* sentinel */
};
/* 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
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.
ix = _Py_dict_lookup(mp, key, hash, &value);
assert(ix >= 0 || value == NULL);
- return value;
+ return value; // borrowed reference
}
PyObject *
if (hash == -1) {
return NULL;
}
- return _PyDict_GetItem_KnownHash(dp, kv, hash);
+ return _PyDict_GetItem_KnownHash(dp, kv, hash); // borrowed reference
}
PyObject *
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 *
}
rv = PyDict_GetItemWithError(v, kv);
Py_DECREF(kv);
- return rv;
+ return rv; // borrowed reference
}
/* Fast version of global value lookup (LOAD_GLOBAL).
}
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
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;
}