summaryrefslogtreecommitdiffstats
path: root/Objects/abstract.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/abstract.c')
-rw-r--r--Objects/abstract.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c
index 9de6b83..f9e5009 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -2403,6 +2403,62 @@ _PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames,
return kwdict;
}
+PyObject **
+_PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs,
+ PyObject **p_kwnames, PyObject *func)
+{
+ PyObject **stack, **kwstack;
+ Py_ssize_t nkwargs;
+ Py_ssize_t pos, i;
+ PyObject *key, *value;
+ PyObject *kwnames;
+
+ assert(nargs >= 0);
+ assert(kwargs == NULL || PyDict_CheckExact(kwargs));
+
+ nkwargs = (kwargs != NULL) ? PyDict_Size(kwargs) : 0;
+ if (!nkwargs) {
+ *p_kwnames = NULL;
+ return args;
+ }
+
+ if ((size_t)nargs > PY_SSIZE_T_MAX / sizeof(stack[0]) - (size_t)nkwargs) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ stack = PyMem_Malloc((nargs + nkwargs) * sizeof(stack[0]));
+ if (stack == NULL) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+
+ kwnames = PyTuple_New(nkwargs);
+ if (kwnames == NULL) {
+ PyMem_Free(stack);
+ return NULL;
+ }
+
+ /* Copy position arguments (borrowed references) */
+ Py_MEMCPY(stack, args, nargs * sizeof(stack[0]));
+
+ kwstack = stack + nargs;
+ pos = i = 0;
+ /* This loop doesn't support lookup function mutating the dictionary
+ to change its size. It's a deliberate choice for speed, this function is
+ called in the performance critical hot code. */
+ while (PyDict_Next(kwargs, &pos, &key, &value)) {
+ Py_INCREF(key);
+ PyTuple_SET_ITEM(kwnames, i, key);
+ /* The stack contains borrowed references */
+ kwstack[i] = value;
+ i++;
+ }
+
+ *p_kwnames = kwnames;
+ return stack;
+}
+
PyObject *
_PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs,
PyObject *kwnames)