[pypy-commit] cffi default: Performance: no real need to call PyArg_ParseTuple() here
arigo
noreply at buildbot.pypy.org
Tue May 26 13:15:07 CEST 2015
Author: Armin Rigo <arigo at 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)"
More information about the pypy-commit
mailing list