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

Lines changed: 6 additions & 0 deletions
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

Lines changed: 3 additions & 0 deletions
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

Lines changed: 29 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 40 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy