Skip to content

Commit 5dc4fe0

Browse files
author
Thomas Heller
committed
Patch #1649190: Adding support for _Bool to ctypes as c_bool, by David Remahl.
1 parent 8441f15 commit 5dc4fe0

File tree

10 files changed

+656
-50
lines changed

10 files changed

+656
-50
lines changed

Doc/lib/libctypes.tex

+6
Original file line numberDiff line numberDiff line change
@@ -2294,6 +2294,12 @@ \subsubsection{Fundamental data types\label{ctypes-fundamental-data-types}}
22942294
an integer address, or a string.
22952295
\end{classdesc*}
22962296
2297+
\begin{classdesc*}{c_bool}
2298+
Represent the C \code{bool} datatype (more accurately, _Bool from C99).
2299+
Its value can be True or False, and the constructor accepts any object that
2300+
has a truth value.
2301+
\end{classdesc*}
2302+
22972303
\begin{classdesc*}{HRESULT}
22982304
Windows only: Represents a \class{HRESULT} value, which contains success
22992305
or error information for a function or method call.

Lib/ctypes/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,9 @@ class c_void_p(_SimpleCData):
233233
c_voidp = c_void_p # backwards compatibility (to a bug)
234234
_check_size(c_void_p)
235235

236+
class c_bool(_SimpleCData):
237+
_type_ = "t"
238+
236239
# This cache maps types to pointers to them.
237240
_pointer_type_cache = {}
238241

Lib/ctypes/test/test_numbers.py

+29-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ def valid_ranges(*types):
2424
unsigned_types = [c_ubyte, c_ushort, c_uint, c_ulong]
2525
signed_types = [c_byte, c_short, c_int, c_long, c_longlong]
2626

27+
bool_types = []
28+
2729
float_types = [c_double, c_float]
2830

2931
try:
@@ -35,8 +37,16 @@ def valid_ranges(*types):
3537
unsigned_types.append(c_ulonglong)
3638
signed_types.append(c_longlong)
3739

40+
try:
41+
c_bool
42+
except NameError:
43+
pass
44+
else:
45+
bool_types.append(c_bool)
46+
3847
unsigned_ranges = valid_ranges(*unsigned_types)
3948
signed_ranges = valid_ranges(*signed_types)
49+
bool_values = [True, False, 0, 1, -1, 5000, 'test', [], [1]]
4050

4151
################################################################
4252

@@ -59,6 +69,11 @@ def test_signed_values(self):
5969
for t, (l, h) in zip(signed_types, signed_ranges):
6070
self.failUnlessEqual(t(l).value, l)
6171
self.failUnlessEqual(t(h).value, h)
72+
73+
def test_bool_values(self):
74+
from operator import truth
75+
for t, v in zip(bool_types, bool_values):
76+
self.failUnlessEqual(t(v).value, truth(v))
6277

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

8398
def test_byref(self):
8499
# calling byref returns also a PyCArgObject instance
85-
for t in signed_types + unsigned_types + float_types:
100+
for t in signed_types + unsigned_types + float_types + bool_types:
86101
parm = byref(t())
87102
self.failUnlessEqual(ArgType, type(parm))
88103

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

103118
def test_sizes(self):
104-
for t in signed_types + unsigned_types + float_types:
119+
for t in signed_types + unsigned_types + float_types + bool_types:
105120
size = struct.calcsize(t._type_)
106121
# sizeof of the type...
107122
self.failUnlessEqual(sizeof(t), size)
@@ -163,6 +178,18 @@ def test_char_from_address(self):
163178

164179
a[0] = '?'
165180
self.failUnlessEqual(v.value, a[0])
181+
182+
# array does not support c_bool / 't'
183+
# def test_bool_from_address(self):
184+
# from ctypes import c_bool
185+
# from array import array
186+
# a = array(c_bool._type_, [True])
187+
# v = t.from_address(a.buffer_info()[0])
188+
# self.failUnlessEqual(v.value, a[0])
189+
# self.failUnlessEqual(type(v) is t)
190+
# a[0] = False
191+
# self.failUnlessEqual(v.value, a[0])
192+
# self.failUnlessEqual(type(v) is t)
166193

167194
def test_init(self):
168195
# c_int() can be initialized from Python's int, and c_int.

Lib/ctypes/test/test_repr.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
subclasses = []
55
for base in [c_byte, c_short, c_int, c_long, c_longlong,
66
c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong,
7-
c_float, c_double]:
7+
c_float, c_double, c_bool]:
88
class X(base):
99
pass
1010
subclasses.append(X)

Misc/NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ Core and builtins
168168
Library
169169
-------
170170

171+
- Patch #1649190: Adding support for _Bool to ctypes as c_bool.
172+
171173
- Patch #1530482: add pydoc.render_doc() which returns the documentation
172174
for a thing instead of paging it to stdout, which pydoc.doc() does.
173175

Modules/_ctypes/_ctypes.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1101,7 +1101,7 @@ _type_ attribute.
11011101
11021102
*/
11031103

1104-
static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOv";
1104+
static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOvt";
11051105

11061106
static PyObject *
11071107
c_wchar_p_from_param(PyObject *type, PyObject *value)

Modules/_ctypes/cfield.c

+40
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,35 @@ vBOOL_get(void *ptr, unsigned size)
725725
}
726726
#endif
727727

728+
#ifdef HAVE_C99_BOOL
729+
#define BOOL_TYPE _Bool
730+
#else
731+
#define BOOL_TYPE char
732+
#undef SIZEOF__BOOL
733+
#define SIZEOF__BOOL 1
734+
#endif
735+
736+
static PyObject *
737+
t_set(void *ptr, PyObject *value, unsigned size)
738+
{
739+
switch (PyObject_IsTrue(value)) {
740+
case -1:
741+
return NULL;
742+
case 0:
743+
*(BOOL_TYPE *)ptr = 0;
744+
_RET(value);
745+
default:
746+
*(BOOL_TYPE *)ptr = 1;
747+
_RET(value);
748+
}
749+
}
750+
751+
static PyObject *
752+
t_get(void *ptr, unsigned size)
753+
{
754+
return PyBool_FromLong((long)*(BOOL_TYPE *)ptr);
755+
}
756+
728757
static PyObject *
729758
I_set(void *ptr, PyObject *value, unsigned size)
730759
{
@@ -1585,6 +1614,17 @@ static struct fielddesc formattable[] = {
15851614
{ 'X', BSTR_set, BSTR_get, &ffi_type_pointer},
15861615
{ 'v', vBOOL_set, vBOOL_get, &ffi_type_sshort},
15871616
#endif
1617+
#if SIZEOF__BOOL == 1
1618+
{ 't', t_set, t_get, &ffi_type_uchar}, /* Also fallback for no native _Bool support */
1619+
#elif SIZEOF__BOOL == SIZEOF_SHORT
1620+
{ 't', t_set, t_get, &ffi_type_ushort},
1621+
#elif SIZEOF__BOOL == SIZEOF_INT
1622+
{ 't', t_set, t_get, &ffi_type_uint, I_set_sw, I_get_sw},
1623+
#elif SIZEOF__BOOL == SIZEOF_LONG
1624+
{ 't', t_set, t_get, &ffi_type_ulong, L_set_sw, L_get_sw},
1625+
#elif SIZEOF__BOOL == SIZEOF_LONG_LONG
1626+
{ 't', t_set, t_get, &ffi_type_ulong, Q_set_sw, Q_get_sw},
1627+
#endif /* SIZEOF__BOOL */
15881628
{ 'O', O_set, O_get, &ffi_type_pointer},
15891629
{ 0, NULL, NULL, NULL},
15901630
};

0 commit comments

Comments
 (0)