diff options
author | Raymond Hettinger <python@rcn.com> | 2003-01-04 00:37:53 (GMT) |
---|---|---|
committer | Raymond Hettinger <python@rcn.com> | 2003-01-04 00:37:53 (GMT) |
commit | bf43f8af3500dfd98a46551942bf4a7ae4dad976 (patch) | |
tree | e2fc8a6e8453ba8aaffa236275bc6fd6c5865202 | |
parent | 3919571f82079cb92c7783ab74a1823f8fdbf3eb (diff) | |
download | cpython-bf43f8af3500dfd98a46551942bf4a7ae4dad976.zip cpython-bf43f8af3500dfd98a46551942bf4a7ae4dad976.tar.gz cpython-bf43f8af3500dfd98a46551942bf4a7ae4dad976.tar.bz2 |
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.
-rw-r--r-- | Objects/methodobject.c | 72 |
1 files 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) */ |