summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2003-01-04 00:37:53 +0000
committerRaymond Hettinger <python@rcn.com>2003-01-04 00:37:53 +0000
commitf4d86ed05e9de1a5a68ddfe87a75b14a84b96b5e (patch)
tree220d0b21cbd36824e5240e6a839e308d28bbb9bd
parentb8d6d9138f9c7c433ca7cc15e1a12c054b87c479 (diff)
downloadcpython-f4d86ed05e9de1a5a68ddfe87a75b14a84b96b5e.tar.gz
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.c72
1 files changed, 41 insertions, 31 deletions
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index 0cb4fd8895..7acd2202c9 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) */