[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