From bf43f8af3500dfd98a46551942bf4a7ae4dad976 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 4 Jan 2003 00:37:53 +0000 Subject: SF Patch #661440: Refactor and streamline PyCFunction_Call Refactor code in PyCFunction_Call giving a modest (tiny) speed boost, a slight improvement in semantics (now detects invalid flag combinations), and (arguably) improved clarity (making it blindingly clear which flag combinations are allowed). All this comes at a cost of a few lines of code duplication. * Folded test for METH_KEYWORDS into the switch/case. * Deferred testing for an empty dictionary until when and where needed. * Make a similar deferral for filling the "size" variable. * Inverted the dictionary test so that the common case falls though instead of making a jump. --- Objects/methodobject.c | 72 ++++++++++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 0cb4fd8..7acd220 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -62,48 +62,58 @@ PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) PyCFunctionObject* f = (PyCFunctionObject*)func; PyCFunction meth = PyCFunction_GET_FUNCTION(func); PyObject *self = PyCFunction_GET_SELF(func); - int flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC); - int size = PyTuple_GET_SIZE(arg); + int size; - if (flags & METH_KEYWORDS) { - return (*(PyCFunctionWithKeywords)meth)(self, arg, kw); - } - if (kw != NULL && PyDict_Size(kw) != 0) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes no keyword arguments", - f->m_ml->ml_name); - return NULL; - } - - switch (flags) { + switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC)) { case METH_VARARGS: - return (*meth)(self, arg); + if (kw == NULL || PyDict_Size(kw) == 0) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)meth)(self, arg, kw); case METH_NOARGS: - if (size == 0) - return (*meth)(self, NULL); - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%d given)", - f->m_ml->ml_name, size); - return NULL; + if (kw == NULL || PyDict_Size(kw) == 0) { + size = PyTuple_GET_SIZE(arg); + if (size == 0) + return (*meth)(self, NULL); + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%d given)", + f->m_ml->ml_name, size); + return NULL; + } + break; case METH_O: - if (size == 1) - return (*meth)(self, PyTuple_GET_ITEM(arg, 0)); - PyErr_Format(PyExc_TypeError, - "%.200s() takes exactly one argument (%d given)", - f->m_ml->ml_name, size); - return NULL; + if (kw == NULL || PyDict_Size(kw) == 0) { + size = PyTuple_GET_SIZE(arg); + if (size == 1) + return (*meth)(self, PyTuple_GET_ITEM(arg, 0)); + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%d given)", + f->m_ml->ml_name, size); + return NULL; + } + break; case METH_OLDARGS: /* the really old style */ - if (size == 1) - arg = PyTuple_GET_ITEM(arg, 0); - else if (size == 0) - arg = NULL; - return (*meth)(self, arg); + if (kw == NULL || PyDict_Size(kw) == 0) { + size = PyTuple_GET_SIZE(arg); + if (size == 1) + arg = PyTuple_GET_ITEM(arg, 0); + else if (size == 0) + arg = NULL; + return (*meth)(self, arg); + } + break; + case METH_OLDARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)meth)(self, arg, kw); default: /* should never get here ??? */ PyErr_BadInternalCall(); return NULL; } + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); + return NULL; } /* Methods (the standard built-in methods, that is) */ -- cgit v0.12