Kaydet (Commit) aef4c6bc authored tarafından Martin v. Löwis's avatar Martin v. Löwis

Patch #1610575: Add support for _Bool to struct.

üst 71cd5515
...@@ -50,14 +50,15 @@ C and Python values should be obvious given their types: ...@@ -50,14 +50,15 @@ C and Python values should be obvious given their types:
\lineiv{c}{\ctype{char}}{string of length 1}{} \lineiv{c}{\ctype{char}}{string of length 1}{}
\lineiv{b}{\ctype{signed char}}{integer}{} \lineiv{b}{\ctype{signed char}}{integer}{}
\lineiv{B}{\ctype{unsigned char}}{integer}{} \lineiv{B}{\ctype{unsigned char}}{integer}{}
\lineiv{t}{\ctype{_Bool}}{bool}{(1)}
\lineiv{h}{\ctype{short}}{integer}{} \lineiv{h}{\ctype{short}}{integer}{}
\lineiv{H}{\ctype{unsigned short}}{integer}{} \lineiv{H}{\ctype{unsigned short}}{integer}{}
\lineiv{i}{\ctype{int}}{integer}{} \lineiv{i}{\ctype{int}}{integer}{}
\lineiv{I}{\ctype{unsigned int}}{long}{} \lineiv{I}{\ctype{unsigned int}}{long}{}
\lineiv{l}{\ctype{long}}{integer}{} \lineiv{l}{\ctype{long}}{integer}{}
\lineiv{L}{\ctype{unsigned long}}{long}{} \lineiv{L}{\ctype{unsigned long}}{long}{}
\lineiv{q}{\ctype{long long}}{long}{(1)} \lineiv{q}{\ctype{long long}}{long}{(2)}
\lineiv{Q}{\ctype{unsigned long long}}{long}{(1)} \lineiv{Q}{\ctype{unsigned long long}}{long}{(2)}
\lineiv{f}{\ctype{float}}{float}{} \lineiv{f}{\ctype{float}}{float}{}
\lineiv{d}{\ctype{double}}{float}{} \lineiv{d}{\ctype{double}}{float}{}
\lineiv{s}{\ctype{char[]}}{string}{} \lineiv{s}{\ctype{char[]}}{string}{}
...@@ -70,6 +71,11 @@ Notes: ...@@ -70,6 +71,11 @@ Notes:
\begin{description} \begin{description}
\item[(1)] \item[(1)]
The \character{t} conversion code corresponds to the \ctype{_Bool} type
defined by C99. If this type is not available, it is simulated using a
\ctype{char}. In standard mode, it is always represented by one byte.
\versionadded{2.6}
\item[(2)]
The \character{q} and \character{Q} conversion codes are available in The \character{q} and \character{Q} conversion codes are available in
native mode only if the platform C compiler supports C \ctype{long long}, native mode only if the platform C compiler supports C \ctype{long long},
or, on Windows, \ctype{__int64}. They are always available in standard or, on Windows, \ctype{__int64}. They are always available in standard
...@@ -118,6 +124,12 @@ example, the Alpha and Merced processors use 64-bit pointer values, ...@@ -118,6 +124,12 @@ example, the Alpha and Merced processors use 64-bit pointer values,
meaning a Python long integer will be used to hold the pointer; other meaning a Python long integer will be used to hold the pointer; other
platforms use 32-bit pointers and will use a Python integer. platforms use 32-bit pointers and will use a Python integer.
For the \character{t} format character, the return value is either
\constant{True} or \constant{False}. When packing, the truth value
of the argument object is used. Either 0 or 1 in the native or standard
bool representation will be packed, and any non-zero value will be True
when unpacking.
By default, C numbers are represented in the machine's native format By default, C numbers are represented in the machine's native format
and byte order, and properly aligned by skipping pad bytes if and byte order, and properly aligned by skipping pad bytes if
necessary (according to the rules used by the C compiler). necessary (according to the rules used by the C compiler).
...@@ -151,6 +163,7 @@ for any type (so you have to use pad bytes); ...@@ -151,6 +163,7 @@ for any type (so you have to use pad bytes);
\ctype{long long} (\ctype{__int64} on Windows) is 8 bytes; \ctype{long long} (\ctype{__int64} on Windows) is 8 bytes;
\ctype{float} and \ctype{double} are 32-bit and 64-bit \ctype{float} and \ctype{double} are 32-bit and 64-bit
IEEE floating point numbers, respectively. IEEE floating point numbers, respectively.
\ctype{_Bool} is 1 byte.
Note the difference between \character{@} and \character{=}: both use Note the difference between \character{@} and \character{=}: both use
native byte order, but the size and alignment of the latter is native byte order, but the size and alignment of the latter is
......
...@@ -84,8 +84,8 @@ sz = struct.calcsize('i') ...@@ -84,8 +84,8 @@ sz = struct.calcsize('i')
if sz * 3 != struct.calcsize('iii'): if sz * 3 != struct.calcsize('iii'):
raise TestFailed, 'inconsistent sizes' raise TestFailed, 'inconsistent sizes'
fmt = 'cbxxxxxxhhhhiillffd' fmt = 'cbxxxxxxhhhhiillffdt'
fmt3 = '3c3b18x12h6i6l6f3d' fmt3 = '3c3b18x12h6i6l6f3d3t'
sz = struct.calcsize(fmt) sz = struct.calcsize(fmt)
sz3 = struct.calcsize(fmt3) sz3 = struct.calcsize(fmt3)
if sz * 3 != sz3: if sz * 3 != sz3:
...@@ -108,19 +108,21 @@ i = 65535 ...@@ -108,19 +108,21 @@ i = 65535
l = 65536 l = 65536
f = 3.1415 f = 3.1415
d = 3.1415 d = 3.1415
t = True
for prefix in ('', '@', '<', '>', '=', '!'): for prefix in ('', '@', '<', '>', '=', '!'):
for format in ('xcbhilfd', 'xcBHILfd'): for format in ('xcbhilfdt', 'xcBHILfdt'):
format = prefix + format format = prefix + format
if verbose: if verbose:
print "trying:", format print "trying:", format
s = struct.pack(format, c, b, h, i, l, f, d) s = struct.pack(format, c, b, h, i, l, f, d, t)
cp, bp, hp, ip, lp, fp, dp = struct.unpack(format, s) cp, bp, hp, ip, lp, fp, dp, tp = struct.unpack(format, s)
if (cp != c or bp != b or hp != h or ip != i or lp != l or if (cp != c or bp != b or hp != h or ip != i or lp != l or
int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d)): int(100 * fp) != int(100 * f) or int(100 * dp) != int(100 * d) or
tp != t):
# ^^^ calculate only to two decimal places # ^^^ calculate only to two decimal places
raise TestFailed, "unpack/pack not transitive (%s, %s)" % ( raise TestFailed, "unpack/pack not transitive (%s, %s)" % (
str(format), str((cp, bp, hp, ip, lp, fp, dp))) str(format), str((cp, bp, hp, ip, lp, fp, dp, tp)))
# Test some of the new features in detail # Test some of the new features in detail
...@@ -158,6 +160,11 @@ tests = [ ...@@ -158,6 +160,11 @@ tests = [
('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0), ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0),
('d', -2.0, '\300\000\000\000\000\000\000\000', ('d', -2.0, '\300\000\000\000\000\000\000\000',
'\000\000\000\000\000\000\000\300', 0), '\000\000\000\000\000\000\000\300', 0),
('t', 0, '\0', '\0', 0),
('t', 3, '\1', '\1', 1),
('t', True, '\1', '\1', 0),
('t', [], '\0', '\0', 1),
('t', (1,), '\1', '\1', 1),
] ]
for fmt, arg, big, lil, asy in tests: for fmt, arg, big, lil, asy in tests:
...@@ -612,3 +619,50 @@ def test_pack_into_fn(): ...@@ -612,3 +619,50 @@ def test_pack_into_fn():
test_unpack_from() test_unpack_from()
test_pack_into() test_pack_into()
test_pack_into_fn() test_pack_into_fn()
def test_bool():
for prefix in tuple("<>!=")+('',):
false = (), [], [], '', 0
true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2
falseFormat = prefix + 't' * len(false)
if verbose:
print 'trying bool pack/unpack on', false, 'using format', falseFormat
packedFalse = struct.pack(falseFormat, *false)
unpackedFalse = struct.unpack(falseFormat, packedFalse)
trueFormat = prefix + 't' * len(true)
if verbose:
print 'trying bool pack/unpack on', true, 'using format', trueFormat
packedTrue = struct.pack(trueFormat, *true)
unpackedTrue = struct.unpack(trueFormat, packedTrue)
if len(true) != len(unpackedTrue):
raise TestFailed('unpacked true array is not of same size as input')
if len(false) != len(unpackedFalse):
raise TestFailed('unpacked false array is not of same size as input')
for t in unpackedFalse:
if t is not False:
raise TestFailed('%r did not unpack as False' % t)
for t in unpackedTrue:
if t is not True:
raise TestFailed('%r did not unpack as false' % t)
if prefix and verbose:
print 'trying size of bool with format %r' % (prefix+'t')
packed = struct.pack(prefix+'t', 1)
if len(packed) != struct.calcsize(prefix+'t'):
raise TestFailed('packed length is not equal to calculated size')
if len(packed) != 1 and prefix:
raise TestFailed('encoded bool is not one byte: %r' % packed)
elif not prefix and verbose:
print 'size of bool in native format is %i' % (len(packed))
for c in '\x01\x7f\xff\x0f\xf0':
if struct.unpack('>t', c)[0] is not True:
raise TestFailed('%c did not unpack as True' % c)
test_bool()
...@@ -313,6 +313,9 @@ Library ...@@ -313,6 +313,9 @@ Library
Extension Modules Extension Modules
----------------- -----------------
- Patch #1610575: The struct module now supports the 't' code, for
C99 _Bool.
- Patch #1635058: ensure that htonl and friends never accept or - Patch #1635058: ensure that htonl and friends never accept or
return negative numbers, per the underlying C implementation. return negative numbers, per the underlying C implementation.
......
...@@ -104,6 +104,15 @@ typedef struct { char c; PY_LONG_LONG x; } s_long_long; ...@@ -104,6 +104,15 @@ typedef struct { char c; PY_LONG_LONG x; } s_long_long;
#define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(PY_LONG_LONG)) #define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(PY_LONG_LONG))
#endif #endif
#ifdef HAVE_C99_BOOL
#define BOOL_TYPE _Bool
typedef struct { char c; _Bool x; } s_bool;
#define BOOL_ALIGN (sizeof(s_bool) - sizeof(BOOL_TYPE))
#else
#define BOOL_TYPE char
#define BOOL_ALIGN 0
#endif
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#ifdef __powerc #ifdef __powerc
...@@ -535,6 +544,15 @@ nu_ulonglong(const char *p, const formatdef *f) ...@@ -535,6 +544,15 @@ nu_ulonglong(const char *p, const formatdef *f)
#endif #endif
static PyObject *
nu_bool(const char *p, const formatdef *f)
{
BOOL_TYPE x;
memcpy((char *)&x, p, sizeof x);
return PyBool_FromLong(x != 0);
}
static PyObject * static PyObject *
nu_float(const char *p, const formatdef *f) nu_float(const char *p, const formatdef *f)
{ {
...@@ -711,6 +729,16 @@ np_ulonglong(char *p, PyObject *v, const formatdef *f) ...@@ -711,6 +729,16 @@ np_ulonglong(char *p, PyObject *v, const formatdef *f)
} }
#endif #endif
static int
np_bool(char *p, PyObject *v, const formatdef *f)
{
BOOL_TYPE y;
y = PyObject_IsTrue(v);
memcpy(p, (char *)&y, sizeof y);
return 0;
}
static int static int
np_float(char *p, PyObject *v, const formatdef *f) np_float(char *p, PyObject *v, const formatdef *f)
{ {
...@@ -771,6 +799,7 @@ static formatdef native_table[] = { ...@@ -771,6 +799,7 @@ static formatdef native_table[] = {
{'q', sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_longlong, np_longlong}, {'q', sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_longlong, np_longlong},
{'Q', sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_ulonglong,np_ulonglong}, {'Q', sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_ulonglong,np_ulonglong},
#endif #endif
{'t', sizeof(BOOL_TYPE), BOOL_ALIGN, nu_bool, np_bool},
{'f', sizeof(float), FLOAT_ALIGN, nu_float, np_float}, {'f', sizeof(float), FLOAT_ALIGN, nu_float, np_float},
{'d', sizeof(double), DOUBLE_ALIGN, nu_double, np_double}, {'d', sizeof(double), DOUBLE_ALIGN, nu_double, np_double},
{'P', sizeof(void *), VOID_P_ALIGN, nu_void_p, np_void_p}, {'P', sizeof(void *), VOID_P_ALIGN, nu_void_p, np_void_p},
...@@ -865,6 +894,14 @@ bu_double(const char *p, const formatdef *f) ...@@ -865,6 +894,14 @@ bu_double(const char *p, const formatdef *f)
return unpack_double(p, 0); return unpack_double(p, 0);
} }
static PyObject *
bu_bool(const char *p, const formatdef *f)
{
char x;
memcpy((char *)&x, p, sizeof x);
return PyBool_FromLong(x != 0);
}
static int static int
bp_int(char *p, PyObject *v, const formatdef *f) bp_int(char *p, PyObject *v, const formatdef *f)
{ {
...@@ -969,6 +1006,15 @@ bp_double(char *p, PyObject *v, const formatdef *f) ...@@ -969,6 +1006,15 @@ bp_double(char *p, PyObject *v, const formatdef *f)
return _PyFloat_Pack8(x, (unsigned char *)p, 0); return _PyFloat_Pack8(x, (unsigned char *)p, 0);
} }
static int
bp_bool(char *p, PyObject *v, const formatdef *f)
{
char y;
y = PyObject_IsTrue(v);
memcpy(p, (char *)&y, sizeof y);
return 0;
}
static formatdef bigendian_table[] = { static formatdef bigendian_table[] = {
{'x', 1, 0, NULL}, {'x', 1, 0, NULL},
#ifdef PY_STRUCT_OVERFLOW_MASKING #ifdef PY_STRUCT_OVERFLOW_MASKING
...@@ -990,6 +1036,7 @@ static formatdef bigendian_table[] = { ...@@ -990,6 +1036,7 @@ static formatdef bigendian_table[] = {
{'L', 4, 0, bu_uint, bp_uint}, {'L', 4, 0, bu_uint, bp_uint},
{'q', 8, 0, bu_longlong, bp_longlong}, {'q', 8, 0, bu_longlong, bp_longlong},
{'Q', 8, 0, bu_ulonglong, bp_ulonglong}, {'Q', 8, 0, bu_ulonglong, bp_ulonglong},
{'t', 1, 0, bu_bool, bp_bool},
{'f', 4, 0, bu_float, bp_float}, {'f', 4, 0, bu_float, bp_float},
{'d', 8, 0, bu_double, bp_double}, {'d', 8, 0, bu_double, bp_double},
{0} {0}
...@@ -1208,6 +1255,8 @@ static formatdef lilendian_table[] = { ...@@ -1208,6 +1255,8 @@ static formatdef lilendian_table[] = {
{'L', 4, 0, lu_uint, lp_uint}, {'L', 4, 0, lu_uint, lp_uint},
{'q', 8, 0, lu_longlong, lp_longlong}, {'q', 8, 0, lu_longlong, lp_longlong},
{'Q', 8, 0, lu_ulonglong, lp_ulonglong}, {'Q', 8, 0, lu_ulonglong, lp_ulonglong},
{'t', 1, 0, bu_bool, bp_bool}, /* Std rep not endian dep,
but potentially different from native rep -- reuse bx_bool funcs. */
{'f', 4, 0, lu_float, lp_float}, {'f', 4, 0, lu_float, lp_float},
{'d', 8, 0, lu_double, lp_double}, {'d', 8, 0, lu_double, lp_double},
{0} {0}
......
This diff is collapsed.
...@@ -1218,6 +1218,17 @@ if test "$have_long_long" = yes ; then ...@@ -1218,6 +1218,17 @@ if test "$have_long_long" = yes ; then
AC_CHECK_SIZEOF(long long, 8) AC_CHECK_SIZEOF(long long, 8)
fi fi
AC_MSG_CHECKING(for _Bool support)
have_c99_bool=no
AC_TRY_COMPILE([], [_Bool x; x = (_Bool)0;], [
AC_DEFINE(HAVE_C99_BOOL, 1, [Define this if you have the type _Bool.])
have_c99_bool=yes
])
AC_MSG_RESULT($have_c99_bool)
if test "$have_c99_bool" = yes ; then
AC_CHECK_SIZEOF(_Bool, 1)
fi
AC_CHECK_TYPES(uintptr_t, AC_CHECK_TYPES(uintptr_t,
[AC_CHECK_SIZEOF(uintptr_t, 4)], [AC_CHECK_SIZEOF(uintptr_t, 4)],
[], [#ifdef HAVE_STDINT_H [], [#ifdef HAVE_STDINT_H
......
...@@ -64,6 +64,9 @@ ...@@ -64,6 +64,9 @@
/* Define if pthread_sigmask() does not work on your system. */ /* Define if pthread_sigmask() does not work on your system. */
#undef HAVE_BROKEN_PTHREAD_SIGMASK #undef HAVE_BROKEN_PTHREAD_SIGMASK
/* Define this if you have the type _Bool. */
#undef HAVE_C99_BOOL
/* Define to 1 if you have the `chown' function. */ /* Define to 1 if you have the `chown' function. */
#undef HAVE_CHOWN #undef HAVE_CHOWN
...@@ -835,6 +838,9 @@ ...@@ -835,6 +838,9 @@
/* The size of a `wchar_t', as computed by sizeof. */ /* The size of a `wchar_t', as computed by sizeof. */
#undef SIZEOF_WCHAR_T #undef SIZEOF_WCHAR_T
/* The size of a `_Bool', as computed by sizeof. */
#undef SIZEOF__BOOL
/* Define to 1 if you have the ANSI C header files. */ /* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS #undef STDC_HEADERS
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment