diff options
author | Armin Rigo <arigo@tunes.org> | 2017-05-29 20:37:10 +0200 |
---|---|---|
committer | Armin Rigo <arigo@tunes.org> | 2017-05-29 20:37:10 +0200 |
commit | eb4e72344dcadb7f4381bccabe6b7e825613f548 (patch) | |
tree | ec4be4bb459be7e410c2b38562539bd4dffdea7f | |
parent | 59a7c77ee28ac6ef2c89423a7e1a0d3864ef0836 (diff) | |
download | cffi-eb4e72344dcadb7f4381bccabe6b7e825613f548.tar.gz |
More tweaks, more tests, try harder to avoid including <complex.h>
because it is not necessarily there
-rw-r--r-- | c/_cffi_backend.c | 9 | ||||
-rw-r--r-- | c/parse_c_type.c | 2 | ||||
-rw-r--r-- | cffi/_cffi_include.h | 24 | ||||
-rw-r--r-- | cffi/model.py | 6 | ||||
-rw-r--r-- | cffi/recompiler.py | 10 | ||||
-rw-r--r-- | testing/cffi0/test_verify.py | 10 | ||||
-rw-r--r-- | testing/cffi1/test_realize_c_type.py | 9 | ||||
-rw-r--r-- | testing/cffi1/test_recompiler.py | 38 | ||||
-rw-r--r-- | testing/cffi1/test_verify1.py | 7 |
9 files changed, 62 insertions, 53 deletions
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c index 0d937f8..79c0d9a 100644 --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -7,8 +7,6 @@ #ifdef MS_WIN32 #include <windows.h> #include "misc_win32.h" -typedef float cffi_float_complex_t[2]; -typedef double cffi_double_complex_t[2]; #else #include <stddef.h> #include <stdint.h> @@ -16,8 +14,6 @@ typedef double cffi_double_complex_t[2]; #include <errno.h> #include <ffi.h> #include <sys/mman.h> -typedef float _Complex cffi_float_complex_t; /* use the def above if your C */ -typedef double _Complex cffi_double_complex_t; /* compiler complains here */ #endif /* this block of #ifs should be kept exactly identical between @@ -4082,6 +4078,11 @@ static PyObject *get_unique_type(CTypeDescrObject *x, return NULL; } +/* according to the C standard, these types should be equivalent to the + _Complex types for the purposes of storage (not arguments in calls!) */ +typedef float cffi_float_complex_t[2]; +typedef double cffi_double_complex_t[2]; + static PyObject *new_primitive_type(const char *name) { #define ENUM_PRIMITIVE_TYPES \ diff --git a/c/parse_c_type.c b/c/parse_c_type.c index 1ea711c..75c5746 100644 --- a/c/parse_c_type.c +++ b/c/parse_c_type.c @@ -798,7 +798,7 @@ static int parse_complete(token_t *tok) if (tok->kind == TOK__COMPLEX) { if (t1complex == 0) - return parse_error(tok,"_Complex type combination unsupported"); + return parse_error(tok, "_Complex type combination unsupported"); t1 = t1complex; next_token(tok); } diff --git a/cffi/_cffi_include.h b/cffi/_cffi_include.h index 842d9c1..9ec8e31 100644 --- a/cffi/_cffi_include.h +++ b/cffi/_cffi_include.h @@ -16,7 +16,6 @@ #endif #include <Python.h> -#include <complex.h> #ifdef __cplusplus extern "C" { #endif @@ -100,29 +99,6 @@ extern "C" { #define _cffi_to_c_double PyFloat_AsDouble #define _cffi_to_c_float PyFloat_AsDouble -#define _cffi_from_c_float__Complex(x) PyComplex_FromDoubles(crealf(x), cimagf(x)) -#define _cffi_from_c_double__Complex(x) PyComplex_FromDoubles(creal(x), cimag(x)) - -/* inefficient - converts twice! */ -#define _cffi_to_c_float__Complex(op) \ - ( ((float)(PyComplex_AsCComplex(op).real)) + \ - I*((float)(PyComplex_AsCComplex(op).imag)) ) -/* not safe! -//#define _cffi_to_c_float__Complex(op) \ -// ( ((float)((PyComplexObject *)(op))->cval.real) + \ -// I*((float)((PyComplexObject *)(op))->cval.imag) ) -*/ - -/* inefficient - converts twice! */ -#define _cffi_to_c_double__Complex(op) \ - ( (PyComplex_AsCComplex(op).real) + \ - I*(PyComplex_AsCComplex(op).imag) ) -/* not safe! -//#define _cffi_to_c_double__Complex(op) \ -// ( (((PyComplexObject *)(op))->cval.real) + \ -// I*(((PyComplexObject *)(op))->cval.imag) ) -*/ - #define _cffi_from_c_int(x, type) \ (((type)-1) > 0 ? /* unsigned */ \ (sizeof(type) < sizeof(long) ? \ diff --git a/cffi/model.py b/cffi/model.py index ab67b31..82a6758 100644 --- a/cffi/model.py +++ b/cffi/model.py @@ -116,8 +116,8 @@ class PrimitiveType(BasePrimitiveType): 'float': 'f', 'double': 'f', 'long double': 'f', - 'float _Complex': 'f', - 'double _Complex': 'f', + 'float _Complex': 'j', + 'double _Complex': 'j', '_Bool': 'i', # the following types are not primitive in the C sense 'wchar_t': 'c', @@ -165,6 +165,8 @@ class PrimitiveType(BasePrimitiveType): return self.ALL_PRIMITIVE_TYPES[self.name] == 'i' def is_float_type(self): return self.ALL_PRIMITIVE_TYPES[self.name] == 'f' + def is_complex_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'j' def build_backend_type(self, ffi, finishlist): return global_cache(self, ffi, 'new_primitive_type', self.name) diff --git a/cffi/recompiler.py b/cffi/recompiler.py index aa16cb6..b25b3e1 100644 --- a/cffi/recompiler.py +++ b/cffi/recompiler.py @@ -506,7 +506,7 @@ class Recompiler: def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): extraarg = '' - if isinstance(tp, model.BasePrimitiveType): + if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): if tp.is_integer_type() and tp.name != '_Bool': converter = '_cffi_to_c_int' extraarg = ', %s' % tp.name @@ -524,8 +524,10 @@ class Recompiler: tovar, errcode) return # - elif isinstance(tp, model.StructOrUnionOrEnum): - # a struct (not a struct pointer) as a function argument + elif (isinstance(tp, model.StructOrUnionOrEnum) or + isinstance(tp, model.BasePrimitiveType)): + # a struct (not a struct pointer) as a function argument; + # or, a complex (the same code works) self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' % (tovar, self._gettypenum(tp), fromvar)) self._prnt(' %s;' % errcode) @@ -570,7 +572,7 @@ class Recompiler: return '_cffi_from_c_int(%s, %s)' % (var, tp.name) elif isinstance(tp, model.UnknownFloatType): return '_cffi_from_c_double(%s)' % (var,) - elif tp.name != 'long double': + elif tp.name != 'long double' and not tp.is_complex_type(): return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) else: return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py index 53c3f3f..4b9e6d9 100644 --- a/testing/cffi0/test_verify.py +++ b/testing/cffi0/test_verify.py @@ -239,17 +239,19 @@ def test_primitive_category(): tp = model.PrimitiveType(typename) C = tp.is_char_type() F = tp.is_float_type() + X = tp.is_complex_type() I = tp.is_integer_type() assert C == (typename in ('char', 'wchar_t')) - assert F == (typename in ('float', 'double', 'long double', 'float _Complex', 'double _Complex')) - assert I + F + C == 1 # one and only one of them is true + assert F == (typename in ('float', 'double', 'long double')) + assert X == (typename in ('float _Complex', 'double _Complex')) + assert I + F + C + X == 1 # one and only one of them is true def test_all_integer_and_float_types(): typenames = [] for typename in all_primitive_types: if (all_primitive_types[typename] == 'c' or - typename == '_Bool' or typename == 'long double' - or '_Complex' in typename): # omit _Complex since ffi does not yet support + all_primitive_types[typename] == 'j' or # complex + typename == '_Bool' or typename == 'long double'): pass else: typenames.append(typename) diff --git a/testing/cffi1/test_realize_c_type.py b/testing/cffi1/test_realize_c_type.py index bddb38c..a1f31e6 100644 --- a/testing/cffi1/test_realize_c_type.py +++ b/testing/cffi1/test_realize_c_type.py @@ -45,14 +45,7 @@ def test_funcptr_rewrite_args(): def test_all_primitives(): for name in cffi_opcode.PRIMITIVE_TO_INDEX: - if '_Complex' not in name: - check(name, name) - -def test_complex_primitives(): - py.test.xfail("ffi does not support complex yet") - for name in cffi_opcode.PRIMITIVE_TO_INDEX: - if '_Complex' in name: - check(name, name) + check(name, name) def check_func(input, expected_output=None): import _cffi_backend diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py index b749088..1ee05db 100644 --- a/testing/cffi1/test_recompiler.py +++ b/testing/cffi1/test_recompiler.py @@ -2002,28 +2002,58 @@ def test_function_returns_partial_struct(): assert lib.f1(52).a == 52 def test_function_returns_float_complex(): + if sys.platform == 'win32': + py.test.skip("MSVC may not support _Complex") ffi = FFI() ffi.cdef("float _Complex f1(float a, float b);"); lib = verify(ffi, "test_function_returns_float_complex", """ #include <complex.h> - static float _Complex f1 (float a, float b) { return a + I*2.0*b; } + static float _Complex f1(float a, float b) { return a + I*2.0*b; } """) result = lib.f1(1.25, 5.1) assert type(result) == complex assert result.real == 1.25 # exact - assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact + assert (result.imag != 2*5.1) and (abs(result.imag - 2*5.1) < 1e-5) # inexact def test_function_returns_double_complex(): + if sys.platform == 'win32': + py.test.skip("MSVC may not support _Complex") ffi = FFI() ffi.cdef("double _Complex f1(double a, double b);"); lib = verify(ffi, "test_function_returns_double_complex", """ #include <complex.h> - static double _Complex f1 (double a, double b) { return a + I*2.0*b; } + static double _Complex f1(double a, double b) { return a + I*2.0*b; } """) result = lib.f1(1.25, 5.1) assert type(result) == complex assert result.real == 1.25 # exact - assert result.imag == 2*5.1 # exact + assert result.imag == 2*5.1 # exact + +def test_function_argument_float_complex(): + if sys.platform == 'win32': + py.test.skip("MSVC may not support _Complex") + ffi = FFI() + ffi.cdef("float f1(float _Complex x);"); + lib = verify(ffi, "test_function_argument_float_complex", """ + #include <complex.h> + static float f1(float _Complex x) { return cabsf(x); } + """) + x = complex(12.34, 56.78) + result = lib.f1(x) + assert abs(result - abs(x)) < 1e-5 + +def test_function_argument_double_complex(): + if sys.platform == 'win32': + py.test.skip("MSVC may not support _Complex") + ffi = FFI() + ffi.cdef("double f1(double _Complex);"); + lib = verify(ffi, "test_function_argument_double_complex", """ + #include <complex.h> + static double f1(double _Complex x) { return cabs(x); } + """) + x = complex(12.34, 56.78) + result = lib.f1(x) + assert abs(result - abs(x)) < 1e-11 def test_typedef_array_dotdotdot(): ffi = FFI() diff --git a/testing/cffi1/test_verify1.py b/testing/cffi1/test_verify1.py index 72ddc49..0137802 100644 --- a/testing/cffi1/test_verify1.py +++ b/testing/cffi1/test_verify1.py @@ -219,15 +219,18 @@ def test_primitive_category(): tp = model.PrimitiveType(typename) C = tp.is_char_type() F = tp.is_float_type() + X = tp.is_complex_type() I = tp.is_integer_type() assert C == (typename in ('char', 'wchar_t')) - assert F == (typename in ('float', 'double', 'long double', 'float _Complex', 'double _Complex')) - assert I + F + C == 1 # one and only one of them is true + assert F == (typename in ('float', 'double', 'long double')) + assert X == (typename in ('float _Complex', 'double _Complex')) + assert I + F + C + X == 1 # one and only one of them is true def test_all_integer_and_float_types(): typenames = [] for typename in all_primitive_types: if (all_primitive_types[typename] == 'c' or + all_primitive_types[typename] == 'j' or # complex typename == '_Bool' or typename == 'long double'): pass else: |