Author: Armin Rigo <[email protected]>
Branch: sirtom67/float_complex
Changeset: r2943:117488cc30fc
Date: 2017-05-29 20:37 +0200
http://bitbucket.org/cffi/cffi/changeset/117488cc30fc/

Log:    More tweaks, more tests, try harder to avoid including <complex.h>
        because it is not necessarily there

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- 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 @@
 #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 @@
     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
--- a/c/parse_c_type.c
+++ b/c/parse_c_type.c
@@ -798,7 +798,7 @@
     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
--- 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 @@
 #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
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -116,8 +116,8 @@
         '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 @@
         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
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -506,7 +506,7 @@
 
     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 @@
                                                     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 @@
                 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
--- a/testing/cffi0/test_verify.py
+++ b/testing/cffi0/test_verify.py
@@ -239,17 +239,19 @@
         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
--- a/testing/cffi1/test_realize_c_type.py
+++ b/testing/cffi1/test_realize_c_type.py
@@ -45,14 +45,7 @@
 
 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
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -2002,28 +2002,58 @@
     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
--- a/testing/cffi1/test_verify1.py
+++ b/testing/cffi1/test_verify1.py
@@ -219,15 +219,18 @@
         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:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to