summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2017-05-29 20:37:10 +0200
committerArmin Rigo <arigo@tunes.org>2017-05-29 20:37:10 +0200
commiteb4e72344dcadb7f4381bccabe6b7e825613f548 (patch)
treeec4be4bb459be7e410c2b38562539bd4dffdea7f
parent59a7c77ee28ac6ef2c89423a7e1a0d3864ef0836 (diff)
downloadcffi-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.c9
-rw-r--r--c/parse_c_type.c2
-rw-r--r--cffi/_cffi_include.h24
-rw-r--r--cffi/model.py6
-rw-r--r--cffi/recompiler.py10
-rw-r--r--testing/cffi0/test_verify.py10
-rw-r--r--testing/cffi1/test_realize_c_type.py9
-rw-r--r--testing/cffi1/test_recompiler.py38
-rw-r--r--testing/cffi1/test_verify1.py7
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: