[pypy-commit] cffi default: _Bool.

arigo noreply at buildbot.pypy.org
Thu Sep 13 14:49:43 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r928:8d20ed19befe
Date: 2012-09-13 14:34 +0200
http://bitbucket.org/cffi/cffi/changeset/8d20ed19befe/

Log:	_Bool.

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -84,6 +84,7 @@
 #define CT_IS_PTR_TO_OWNED      16384
 #define CT_CUSTOM_FIELD_POS     32768
 #define CT_IS_LONGDOUBLE        65536
+#define CT_IS_BOOL             131072
 #define CT_PRIMITIVE_ANY  (CT_PRIMITIVE_SIGNED |        \
                            CT_PRIMITIVE_UNSIGNED |      \
                            CT_PRIMITIVE_CHAR |          \
@@ -205,6 +206,10 @@
 # include "wchar_helper.h"
 #endif
 
+#ifndef HAVE_C99_BOOL
+typedef unsigned char _Bool;
+#endif
+
 /************************************************************/
 
 static CTypeDescrObject *
@@ -977,6 +982,9 @@
         unsigned PY_LONG_LONG value = _my_PyLong_AsUnsignedLongLong(init, 1);
         if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
             return -1;
+        if (ct->ct_flags & CT_IS_BOOL)
+            if (value & ~1)      /* value != 0 && value != 1 */
+                goto overflow;
         write_raw_integer_data(buf, value, ct->ct_size);
         if (value != read_raw_unsigned_data(buf, ct->ct_size))
             goto overflow;
@@ -2330,7 +2338,14 @@
         value = _my_PyLong_AsUnsignedLongLong(ob, 0);
         if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
             return NULL;
+        if (ct->ct_flags & CT_IS_BOOL) {
+            value = PyObject_IsTrue(ob);
+            if (value < 0)
+                return NULL;
+        }
     }
+    if (ct->ct_flags & CT_IS_BOOL)
+        value = !!value;
     cd = _new_casted_primitive(ct);
     if (cd != NULL)
         write_raw_integer_data(cd->c_data, value, ct->ct_size);
@@ -2679,7 +2694,10 @@
        EPTYPE(ull, unsigned long long, CT_PRIMITIVE_UNSIGNED )  \
        EPTYPE(f, float, CT_PRIMITIVE_FLOAT )                    \
        EPTYPE(d, double, CT_PRIMITIVE_FLOAT )                   \
-       EPTYPE(ld, long double, CT_PRIMITIVE_FLOAT | CT_IS_LONGDOUBLE )
+       EPTYPE(ld, long double, CT_PRIMITIVE_FLOAT | CT_IS_LONGDOUBLE ) \
+       ENUM_PRIMITIVE_TYPES_WCHAR                               \
+       EPTYPE(b, _Bool, CT_PRIMITIVE_UNSIGNED | CT_IS_BOOL )
+
 #ifdef HAVE_WCHAR_H
 # define ENUM_PRIMITIVE_TYPES_WCHAR                             \
        EPTYPE(wc, wchar_t, CT_PRIMITIVE_CHAR )
@@ -2690,7 +2708,6 @@
 #define EPTYPE(code, typename, flags)                   \
     struct aligncheck_##code { char x; typename y; };
     ENUM_PRIMITIVE_TYPES
-    ENUM_PRIMITIVE_TYPES_WCHAR
 #undef EPTYPE
 
     CTypeDescrObject *td;
@@ -2704,7 +2721,6 @@
           flags                                         \
         },
     ENUM_PRIMITIVE_TYPES
-    ENUM_PRIMITIVE_TYPES_WCHAR
 #undef EPTYPE
 #undef ENUM_PRIMITIVE_TYPES_WCHAR
 #undef ENUM_PRIMITIVE_TYPES
@@ -4026,6 +4042,9 @@
     else if (cd->c_type->ct_flags & CT_IS_ENUM) {
         return convert_to_object(cd->c_data, cd->c_type);
     }
+    else if (cd->c_type->ct_flags & CT_IS_BOOL) {
+        /* fall through to TypeError */
+    }
     else if (cd->c_type->ct_flags & (CT_PRIMITIVE_CHAR |
                                      CT_PRIMITIVE_SIGNED |
                                      CT_PRIMITIVE_UNSIGNED)) {
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -2080,3 +2080,28 @@
     assert not isinstance(nullchr, CType)
     assert not isinstance(chrref, CType)
     assert isinstance(BChar, CType)
+
+def test_bool():
+    BBool = new_primitive_type("_Bool")
+    BBoolP = new_pointer_type(BBool)
+    assert int(cast(BBool, False)) == 0
+    assert int(cast(BBool, True)) == 1
+    assert bool(cast(BBool, False)) is True    # warning!
+    assert int(cast(BBool, 3)) == 1
+    assert int(cast(BBool, -0.1)) == 1
+    assert int(cast(BBool, -0.0)) == 0
+    assert int(cast(BBool, '\x00')) == 0
+    assert int(cast(BBool, '\xff')) == 1
+    assert newp(BBoolP, False)[0] == 0
+    assert newp(BBoolP, True)[0] == 1
+    assert newp(BBoolP, 0)[0] == 0
+    assert newp(BBoolP, 1)[0] == 1
+    py.test.raises(TypeError, newp, BBoolP, 1.0)
+    py.test.raises(TypeError, newp, BBoolP, '\x00')
+    py.test.raises(OverflowError, newp, BBoolP, 2)
+    py.test.raises(OverflowError, newp, BBoolP, -1)
+    BCharP = new_pointer_type(new_primitive_type("char"))
+    p = newp(BCharP, 'X')
+    q = cast(BBoolP, p)
+    assert q[0] == ord('X')
+    py.test.raises(TypeError, string, cast(BBool, False))
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
--- a/cffi/backend_ctypes.py
+++ b/cffi/backend_ctypes.py
@@ -284,6 +284,7 @@
         'unsigned long long': ctypes.c_ulonglong,
         'float': ctypes.c_float,
         'double': ctypes.c_double,
+        '_Bool': ctypes.c_bool,
     }
 
     def set_ffi(self, ffi):
@@ -339,6 +340,8 @@
         else:
             if name in ('signed char', 'unsigned char'):
                 kind = 'byte'
+            elif name == '_Bool':
+                kind = 'bool'
             else:
                 kind = 'int'
             is_signed = (ctype(-1).value == -1)
@@ -380,6 +383,15 @@
                 def __int__(self):
                     return self._value
 
+            if kind == 'bool':
+                @classmethod
+                def _cast_from(cls, source):
+                    if not isinstance(source, (integer_types, float)):
+                        source = _cast_source_to_int(source)
+                    return cls(bool(source))
+                def __int__(self):
+                    return self._value
+
             if kind == 'char':
                 @classmethod
                 def _cast_from(cls, source):
@@ -410,7 +422,7 @@
 
             _cast_to_integer = __int__
 
-            if kind == 'int' or kind == 'byte':
+            if kind == 'int' or kind == 'byte' or kind == 'bool':
                 @staticmethod
                 def _to_ctypes(x):
                     if not isinstance(x, integer_types):
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -378,6 +378,16 @@
 
 * wchar_t (if supported by the backend)
 
+* _Bool (if unsupported by the C compiler, this is declared with the
+  size of ``unsigned char``).  *New in version 0.4.*  Note that the
+  effects of ``<stdbool.h>`` are not automatically included: you have
+  to say ``typedef _Bool bool;`` in your ``cdef()`` if you want to
+  use this ``_Bool`` with the more standard name ``bool``.  This is because
+  some headers declare a different type (e.g. an enum) and also call it
+  ``bool``.
+
+.. "versionadded:: 0.4": bool
+
 As we will see on `the verification step`_ below, the declarations can
 also contain "``...``" at various places; these are placeholders that will
 be completed by a call to ``verify()``.
@@ -1015,10 +1025,6 @@
 ----------------------
 
 All of the ANSI C declarations should be supported, and some of C99.
-Important missing features from C99:
-
-* The ``_Bool`` type, also known as ``bool`` from ``stdbool.h``.
-
 Known missing features that are GCC or MSVC extensions:
 
 * Any ``__attribute__`` or ``#pragma pack(n)``
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -1392,3 +1392,19 @@
         assert not isinstance(ffi.cast("int", 0), ffi.CType)
         assert not isinstance(ffi.new("int *"), ffi.CType)
         assert isinstance(ffi.typeof("int"), ffi.CType)
+
+    def test_bool(self):
+        ffi = FFI(backend=self.Backend())
+        assert int(ffi.cast("_Bool", 0.1)) == 1
+        assert int(ffi.cast("_Bool", -0.0)) == 0
+        assert int(ffi.cast("_Bool", '\x02')) == 1
+        assert int(ffi.cast("_Bool", '\x00')) == 0
+        assert int(ffi.cast("_Bool", '\x80')) == 1
+        assert ffi.new("_Bool *", False)[0] == 0
+        assert ffi.new("_Bool *", 1)[0] == 1
+        py.test.raises(OverflowError, ffi.new, "_Bool *", 2)
+        py.test.raises(TypeError, ffi.string, ffi.cast("_Bool", 2))
+
+    def test_use_own_bool(self):
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("""typedef int bool;""")


More information about the pypy-commit mailing list