diff options
author | Victor Stinner <victor.stinner@gmail.com> | 2016-08-24 22:29:32 (GMT) |
---|---|---|
committer | Victor Stinner <victor.stinner@gmail.com> | 2016-08-24 22:29:32 (GMT) |
commit | 577e1f8cb41b76ea763910a47abf42a1952ddec3 (patch) | |
tree | c813887a0af4c5b7312b2e835677546584c067ea /Objects/abstract.c | |
parent | 53868aaabb154c11bf666b31662bb4ae8bc6ec79 (diff) | |
download | cpython-577e1f8cb41b76ea763910a47abf42a1952ddec3.zip cpython-577e1f8cb41b76ea763910a47abf42a1952ddec3.tar.gz cpython-577e1f8cb41b76ea763910a47abf42a1952ddec3.tar.bz2 |
Add _PyObject_FastCallKeywords()
Issue #27830: Similar to _PyObject_FastCallDict(), but keyword arguments are
also passed in the same C array than positional arguments, rather than being
passed as a Python dict.
Diffstat (limited to 'Objects/abstract.c')
-rw-r--r-- | Objects/abstract.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c index f302281..d271d94 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2309,6 +2309,85 @@ exit: return result; } +static PyObject * +_PyStack_AsDict(PyObject **stack, Py_ssize_t nkwargs, PyObject *func) +{ + PyObject *kwdict; + + kwdict = PyDict_New(); + if (kwdict == NULL) { + return NULL; + } + + while (--nkwargs >= 0) { + int err; + PyObject *key = *stack++; + PyObject *value = *stack++; + if (PyDict_GetItem(kwdict, key) != NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s%s got multiple values " + "for keyword argument '%U'", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + key); + Py_DECREF(kwdict); + return NULL; + } + + err = PyDict_SetItem(kwdict, key, value); + if (err) { + Py_DECREF(kwdict); + return NULL; + } + } + return kwdict; +} + +PyObject * +_PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, + Py_ssize_t nkwargs) +{ + PyObject *args, *kwdict, *result; + + /* _PyObject_FastCallKeywords() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + + assert(func != NULL); + assert(nargs >= 0); + assert(nkwargs >= 0); + assert((nargs == 0 && nkwargs == 0) || stack != NULL); + + if (PyFunction_Check(func)) { + /* Fast-path: avoid temporary tuple or dict */ + return _PyFunction_FastCallKeywords(func, stack, nargs, nkwargs); + } + + if (PyCFunction_Check(func) && nkwargs == 0) { + return _PyCFunction_FastCallDict(func, args, nargs, NULL); + } + + /* Slow-path: build temporary tuple and/or dict */ + args = _PyStack_AsTuple(stack, nargs); + + if (nkwargs > 0) { + kwdict = _PyStack_AsDict(stack + nargs, nkwargs, func); + if (kwdict == NULL) { + Py_DECREF(args); + return NULL; + } + } + else { + kwdict = NULL; + } + + result = PyObject_Call(func, args, kwdict); + Py_DECREF(args); + Py_XDECREF(kwdict); + return result; +} + static PyObject* call_function_tail(PyObject *callable, PyObject *args) { |