Skip to content

Commit

Permalink
Patch #1649190: Adding support for _Bool to ctypes as c_bool, by Davi…
Browse files Browse the repository at this point in the history
…d Remahl.
  • Loading branch information
Thomas Heller committed Mar 13, 2007
1 parent 8441f15 commit 5dc4fe0
Show file tree
Hide file tree
Showing 10 changed files with 656 additions and 50 deletions.
6 changes: 6 additions & 0 deletions Doc/lib/libctypes.tex
Original file line number Diff line number Diff line change
Expand Up @@ -2294,6 +2294,12 @@ \subsubsection{Fundamental data types\label{ctypes-fundamental-data-types}}
an integer address, or a string.
\end{classdesc*}
\begin{classdesc*}{c_bool}
Represent the C \code{bool} datatype (more accurately, _Bool from C99).
Its value can be True or False, and the constructor accepts any object that
has a truth value.
\end{classdesc*}
\begin{classdesc*}{HRESULT}
Windows only: Represents a \class{HRESULT} value, which contains success
or error information for a function or method call.
Expand Down
3 changes: 3 additions & 0 deletions Lib/ctypes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ class c_void_p(_SimpleCData):
c_voidp = c_void_p # backwards compatibility (to a bug)
_check_size(c_void_p)

class c_bool(_SimpleCData):
_type_ = "t"

# This cache maps types to pointers to them.
_pointer_type_cache = {}

Expand Down
31 changes: 29 additions & 2 deletions Lib/ctypes/test/test_numbers.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ def valid_ranges(*types):
unsigned_types = [c_ubyte, c_ushort, c_uint, c_ulong]
signed_types = [c_byte, c_short, c_int, c_long, c_longlong]

bool_types = []

float_types = [c_double, c_float]

try:
Expand All @@ -35,8 +37,16 @@ def valid_ranges(*types):
unsigned_types.append(c_ulonglong)
signed_types.append(c_longlong)

try:
c_bool
except NameError:
pass
else:
bool_types.append(c_bool)

unsigned_ranges = valid_ranges(*unsigned_types)
signed_ranges = valid_ranges(*signed_types)
bool_values = [True, False, 0, 1, -1, 5000, 'test', [], [1]]

################################################################

Expand All @@ -59,6 +69,11 @@ def test_signed_values(self):
for t, (l, h) in zip(signed_types, signed_ranges):
self.failUnlessEqual(t(l).value, l)
self.failUnlessEqual(t(h).value, h)

def test_bool_values(self):
from operator import truth
for t, v in zip(bool_types, bool_values):
self.failUnlessEqual(t(v).value, truth(v))

def test_typeerror(self):
# Only numbers are allowed in the contructor,
Expand All @@ -82,7 +97,7 @@ def test_from_param(self):

def test_byref(self):
# calling byref returns also a PyCArgObject instance
for t in signed_types + unsigned_types + float_types:
for t in signed_types + unsigned_types + float_types + bool_types:
parm = byref(t())
self.failUnlessEqual(ArgType, type(parm))

Expand All @@ -101,7 +116,7 @@ def test_integers(self):
self.assertRaises(TypeError, t, 3.14)

def test_sizes(self):
for t in signed_types + unsigned_types + float_types:
for t in signed_types + unsigned_types + float_types + bool_types:
size = struct.calcsize(t._type_)
# sizeof of the type...
self.failUnlessEqual(sizeof(t), size)
Expand Down Expand Up @@ -163,6 +178,18 @@ def test_char_from_address(self):

a[0] = '?'
self.failUnlessEqual(v.value, a[0])

# array does not support c_bool / 't'
# def test_bool_from_address(self):
# from ctypes import c_bool
# from array import array
# a = array(c_bool._type_, [True])
# v = t.from_address(a.buffer_info()[0])
# self.failUnlessEqual(v.value, a[0])
# self.failUnlessEqual(type(v) is t)
# a[0] = False
# self.failUnlessEqual(v.value, a[0])
# self.failUnlessEqual(type(v) is t)

def test_init(self):
# c_int() can be initialized from Python's int, and c_int.
Expand Down
2 changes: 1 addition & 1 deletion Lib/ctypes/test/test_repr.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
subclasses = []
for base in [c_byte, c_short, c_int, c_long, c_longlong,
c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong,
c_float, c_double]:
c_float, c_double, c_bool]:
class X(base):
pass
subclasses.append(X)
Expand Down
2 changes: 2 additions & 0 deletions Misc/NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ Core and builtins
Library
-------

- Patch #1649190: Adding support for _Bool to ctypes as c_bool.

- Patch #1530482: add pydoc.render_doc() which returns the documentation
for a thing instead of paging it to stdout, which pydoc.doc() does.

Expand Down
2 changes: 1 addition & 1 deletion Modules/_ctypes/_ctypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1101,7 +1101,7 @@ _type_ attribute.
*/

static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOv";
static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOvt";

static PyObject *
c_wchar_p_from_param(PyObject *type, PyObject *value)
Expand Down
40 changes: 40 additions & 0 deletions Modules/_ctypes/cfield.c
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,35 @@ vBOOL_get(void *ptr, unsigned size)
}
#endif

#ifdef HAVE_C99_BOOL
#define BOOL_TYPE _Bool
#else
#define BOOL_TYPE char
#undef SIZEOF__BOOL
#define SIZEOF__BOOL 1
#endif

static PyObject *
t_set(void *ptr, PyObject *value, unsigned size)
{
switch (PyObject_IsTrue(value)) {
case -1:
return NULL;
case 0:
*(BOOL_TYPE *)ptr = 0;
_RET(value);
default:
*(BOOL_TYPE *)ptr = 1;
_RET(value);
}
}

static PyObject *
t_get(void *ptr, unsigned size)
{
return PyBool_FromLong((long)*(BOOL_TYPE *)ptr);
}

static PyObject *
I_set(void *ptr, PyObject *value, unsigned size)
{
Expand Down Expand Up @@ -1585,6 +1614,17 @@ static struct fielddesc formattable[] = {
{ 'X', BSTR_set, BSTR_get, &ffi_type_pointer},
{ 'v', vBOOL_set, vBOOL_get, &ffi_type_sshort},
#endif
#if SIZEOF__BOOL == 1
{ 't', t_set, t_get, &ffi_type_uchar}, /* Also fallback for no native _Bool support */
#elif SIZEOF__BOOL == SIZEOF_SHORT
{ 't', t_set, t_get, &ffi_type_ushort},
#elif SIZEOF__BOOL == SIZEOF_INT
{ 't', t_set, t_get, &ffi_type_uint, I_set_sw, I_get_sw},
#elif SIZEOF__BOOL == SIZEOF_LONG
{ 't', t_set, t_get, &ffi_type_ulong, L_set_sw, L_get_sw},
#elif SIZEOF__BOOL == SIZEOF_LONG_LONG
{ 't', t_set, t_get, &ffi_type_ulong, Q_set_sw, Q_get_sw},
#endif /* SIZEOF__BOOL */
{ 'O', O_set, O_get, &ffi_type_pointer},
{ 0, NULL, NULL, NULL},
};
Expand Down

0 comments on commit 5dc4fe0

Please sign in to comment.