Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r2104:e756b0b13434 Date: 2015-05-26 13:15 +0200 http://bitbucket.org/cffi/cffi/changeset/e756b0b13434/
Log: Performance: no real need to call PyArg_ParseTuple() here diff --git a/cffi/_cffi_include.h b/cffi/_cffi_include.h --- a/cffi/_cffi_include.h +++ b/cffi/_cffi_include.h @@ -51,6 +51,11 @@ # endif #endif +#ifdef __GNUC__ +# define _CFFI_UNUSED_FN __attribute__((unused)) +#else +# define _CFFI_UNUSED_FN /* nothing */ +#endif /********** CPython-specific section **********/ #ifndef PYPY_VERSION @@ -182,6 +187,20 @@ return NULL; } +_CFFI_UNUSED_FN +static PyObject **_cffi_unpack_args(PyObject *args_tuple, Py_ssize_t expected, + const char *fnname) +{ + if (PyTuple_GET_SIZE(args_tuple) != expected) { + PyErr_Format(PyExc_TypeError, + "%.150s() takes exactly %zd arguments (%zd given)", + fnname, expected, PyTuple_GET_SIZE(args_tuple)); + return NULL; + } + return &PyTuple_GET_ITEM(args_tuple, 0); /* pointer to the first item, + the others follow */ +} + #endif /********** end CPython-specific section **********/ @@ -201,12 +220,6 @@ ((got_nonpos) == (expected <= 0) && \ (got) == (unsigned long long)expected) -#ifdef __GNUC__ -# define _CFFI_UNUSED_FN __attribute__((unused)) -#else -# define _CFFI_UNUSED_FN /* nothing */ -#endif - #ifdef __cplusplus } #endif diff --git a/cffi/recompiler.py b/cffi/recompiler.py --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -632,10 +632,13 @@ rng = range(len(tp.args)) for i in rng: prnt(' PyObject *arg%d;' % i) + prnt(' PyObject **aa;') prnt() - prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % ( - 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng]))) + prnt(' aa = _cffi_unpack_args(args, %d, "%s");' % (len(rng), name)) + prnt(' if (aa == NULL)') prnt(' return NULL;') + for i in rng: + prnt(' arg%d = aa[%d];' % (i, i)) prnt() # for i, type in enumerate(tp.args): diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py --- a/testing/cffi1/test_recompiler.py +++ b/testing/cffi1/test_recompiler.py @@ -776,3 +776,32 @@ #endif """) assert lib.CORRECT == 1 + +def test_unpack_args(): + ffi = FFI() + ffi.cdef("void foo0(void); void foo1(int); void foo2(int, int);") + lib = verify(ffi, "test_unpack_args", """ + void foo0(void) { } + void foo1(int x) { } + void foo2(int x, int y) { } + """) + assert 'foo0' in repr(lib.foo0) + assert 'foo1' in repr(lib.foo1) + assert 'foo2' in repr(lib.foo2) + lib.foo0() + lib.foo1(42) + lib.foo2(43, 44) + e1 = py.test.raises(TypeError, lib.foo0, 42) + e2 = py.test.raises(TypeError, lib.foo0, 43, 44) + e3 = py.test.raises(TypeError, lib.foo1) + e4 = py.test.raises(TypeError, lib.foo1, 43, 44) + e5 = py.test.raises(TypeError, lib.foo2) + e6 = py.test.raises(TypeError, lib.foo2, 42) + e7 = py.test.raises(TypeError, lib.foo2, 45, 46, 47) + assert str(e1.value) == "foo0() takes no arguments (1 given)" + assert str(e2.value) == "foo0() takes no arguments (2 given)" + assert str(e3.value) == "foo1() takes exactly one argument (0 given)" + assert str(e4.value) == "foo1() takes exactly one argument (2 given)" + assert str(e5.value) == "foo2() takes exactly 2 arguments (0 given)" + assert str(e6.value) == "foo2() takes exactly 2 arguments (1 given)" + assert str(e7.value) == "foo2() takes exactly 2 arguments (3 given)" _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit