Commit f4d86ed0 authored by Raymond Hettinger's avatar Raymond Hettinger

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.
parent b8d6d913
...@@ -62,48 +62,58 @@ PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) ...@@ -62,48 +62,58 @@ PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw)
PyCFunctionObject* f = (PyCFunctionObject*)func; PyCFunctionObject* f = (PyCFunctionObject*)func;
PyCFunction meth = PyCFunction_GET_FUNCTION(func); PyCFunction meth = PyCFunction_GET_FUNCTION(func);
PyObject *self = PyCFunction_GET_SELF(func); PyObject *self = PyCFunction_GET_SELF(func);
int flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC); int size;
int size = PyTuple_GET_SIZE(arg);
if (flags & METH_KEYWORDS) { switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC)) {
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) {
case METH_VARARGS: case METH_VARARGS:
if (kw == NULL || PyDict_Size(kw) == 0)
return (*meth)(self, arg); return (*meth)(self, arg);
break;
case METH_VARARGS | METH_KEYWORDS:
return (*(PyCFunctionWithKeywords)meth)(self, arg, kw);
case METH_NOARGS: case METH_NOARGS:
if (kw == NULL || PyDict_Size(kw) == 0) {
size = PyTuple_GET_SIZE(arg);
if (size == 0) if (size == 0)
return (*meth)(self, NULL); return (*meth)(self, NULL);
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%.200s() takes no arguments (%d given)", "%.200s() takes no arguments (%d given)",
f->m_ml->ml_name, size); f->m_ml->ml_name, size);
return NULL; return NULL;
}
break;
case METH_O: case METH_O:
if (kw == NULL || PyDict_Size(kw) == 0) {
size = PyTuple_GET_SIZE(arg);
if (size == 1) if (size == 1)
return (*meth)(self, PyTuple_GET_ITEM(arg, 0)); return (*meth)(self, PyTuple_GET_ITEM(arg, 0));
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%.200s() takes exactly one argument (%d given)", "%.200s() takes exactly one argument (%d given)",
f->m_ml->ml_name, size); f->m_ml->ml_name, size);
return NULL; return NULL;
}
break;
case METH_OLDARGS: case METH_OLDARGS:
/* the really old style */ /* the really old style */
if (kw == NULL || PyDict_Size(kw) == 0) {
size = PyTuple_GET_SIZE(arg);
if (size == 1) if (size == 1)
arg = PyTuple_GET_ITEM(arg, 0); arg = PyTuple_GET_ITEM(arg, 0);
else if (size == 0) else if (size == 0)
arg = NULL; arg = NULL;
return (*meth)(self, arg); return (*meth)(self, arg);
}
break;
case METH_OLDARGS | METH_KEYWORDS:
return (*(PyCFunctionWithKeywords)meth)(self, arg, kw);
default: default:
/* should never get here ??? */ /* should never get here ??? */
PyErr_BadInternalCall(); PyErr_BadInternalCall();
return NULL; 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) */ /* Methods (the standard built-in methods, that is) */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment