mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-121249: unconditionally support complex
types in struct
(GH-132864)
Co-authored-by: Lisandro Dalcin <dalcinl@gmail.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
This commit is contained in:
parent
e6c518d2eb
commit
f425509349
5 changed files with 21 additions and 89 deletions
|
@ -260,6 +260,10 @@ platform-dependent.
|
|||
+--------+--------------------------+--------------------+----------------+------------+
|
||||
| ``d`` | :c:expr:`double` | float | 8 | \(4) |
|
||||
+--------+--------------------------+--------------------+----------------+------------+
|
||||
| ``F`` | :c:expr:`float complex` | complex | 8 | \(10) |
|
||||
+--------+--------------------------+--------------------+----------------+------------+
|
||||
| ``D`` | :c:expr:`double complex` | complex | 16 | \(10) |
|
||||
+--------+--------------------------+--------------------+----------------+------------+
|
||||
| ``s`` | :c:expr:`char[]` | bytes | | \(9) |
|
||||
+--------+--------------------------+--------------------+----------------+------------+
|
||||
| ``p`` | :c:expr:`char[]` | bytes | | \(8) |
|
||||
|
@ -267,17 +271,6 @@ platform-dependent.
|
|||
| ``P`` | :c:expr:`void \*` | integer | | \(5) |
|
||||
+--------+--------------------------+--------------------+----------------+------------+
|
||||
|
||||
Additionally, if IEC 60559 compatible complex arithmetic (Annex G of the
|
||||
C11 standard) is supported, the following format characters are available:
|
||||
|
||||
+--------+--------------------------+--------------------+----------------+------------+
|
||||
| Format | C Type | Python type | Standard size | Notes |
|
||||
+========+==========================+====================+================+============+
|
||||
| ``F`` | :c:expr:`float complex` | complex | 8 | \(10) |
|
||||
+--------+--------------------------+--------------------+----------------+------------+
|
||||
| ``D`` | :c:expr:`double complex` | complex | 16 | \(10) |
|
||||
+--------+--------------------------+--------------------+----------------+------------+
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
Added support for the ``'n'`` and ``'N'`` formats.
|
||||
|
||||
|
@ -367,6 +360,11 @@ Notes:
|
|||
For the ``'E'`` and ``'C'`` format characters, the packed representation uses
|
||||
the IEEE 754 binary32 and binary64 format for components of the complex
|
||||
number, regardless of the floating-point format used by the platform.
|
||||
Note that complex types (``F`` and ``D``) are available unconditionally,
|
||||
despite complex types being an optional feature in C.
|
||||
As specified in the C11 standard, each complex type is represented by a
|
||||
two-element C array containing, respectively, the real and imaginary parts.
|
||||
|
||||
|
||||
A format character may be preceded by an integral repeat count. For example,
|
||||
the format string ``'4h'`` means exactly the same as ``'hhhh'``.
|
||||
|
|
|
@ -1313,8 +1313,8 @@ struct
|
|||
------
|
||||
|
||||
* Support the :c:expr:`float complex` and :c:expr:`double complex` C types in
|
||||
the :mod:`struct` module (formatting characters ``'F'`` and ``'D'``,
|
||||
respectively) if the compiler has C11 complex arithmetic.
|
||||
the :mod:`struct` module (formatting characters ``'F'`` and ``'D'``
|
||||
respectively).
|
||||
(Contributed by Sergey B Kirpichev in :gh:`121249`.)
|
||||
|
||||
|
||||
|
|
|
@ -22,12 +22,6 @@ byteorders = '', '@', '=', '<', '>', '!'
|
|||
INF = float('inf')
|
||||
NAN = float('nan')
|
||||
|
||||
try:
|
||||
struct.pack('D', 1j)
|
||||
have_c_complex = True
|
||||
except struct.error:
|
||||
have_c_complex = False
|
||||
|
||||
def iter_integer_formats(byteorders=byteorders):
|
||||
for code in integer_codes:
|
||||
for byteorder in byteorders:
|
||||
|
@ -796,7 +790,6 @@ class StructTest(ComplexesAreIdenticalMixin, unittest.TestCase):
|
|||
s = struct.Struct('=i2H')
|
||||
self.assertEqual(repr(s), f'Struct({s.format!r})')
|
||||
|
||||
@unittest.skipUnless(have_c_complex, "requires C11 complex type support")
|
||||
def test_c_complex_round_trip(self):
|
||||
values = [complex(*_) for _ in combinations([1, -1, 0.0, -0.0, 2,
|
||||
-3, INF, -INF, NAN], 2)]
|
||||
|
@ -806,19 +799,6 @@ class StructTest(ComplexesAreIdenticalMixin, unittest.TestCase):
|
|||
round_trip = struct.unpack(f, struct.pack(f, z))[0]
|
||||
self.assertComplexesAreIdentical(z, round_trip)
|
||||
|
||||
@unittest.skipIf(have_c_complex, "requires no C11 complex type support")
|
||||
def test_c_complex_error(self):
|
||||
msg1 = "'F' format not supported on this system"
|
||||
msg2 = "'D' format not supported on this system"
|
||||
with self.assertRaisesRegex(struct.error, msg1):
|
||||
struct.pack('F', 1j)
|
||||
with self.assertRaisesRegex(struct.error, msg1):
|
||||
struct.unpack('F', b'1')
|
||||
with self.assertRaisesRegex(struct.error, msg2):
|
||||
struct.pack('D', 1j)
|
||||
with self.assertRaisesRegex(struct.error, msg2):
|
||||
struct.unpack('D', b'1')
|
||||
|
||||
|
||||
class UnpackIteratorTest(unittest.TestCase):
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Always support the :c:expr:`float complex` and :c:expr:`double complex` C types in
|
||||
the :mod:`struct` module. Patch by Sergey B Kirpichev.
|
|
@ -12,9 +12,6 @@
|
|||
#include "pycore_long.h" // _PyLong_AsByteArray()
|
||||
#include "pycore_moduleobject.h" // _PyModule_GetState()
|
||||
|
||||
#ifdef Py_HAVE_C_COMPLEX
|
||||
# include "_complex.h" // complex
|
||||
#endif
|
||||
#include <stddef.h> // offsetof()
|
||||
|
||||
/*[clinic input]
|
||||
|
@ -495,25 +492,23 @@ nu_double(_structmodulestate *state, const char *p, const formatdef *f)
|
|||
return PyFloat_FromDouble(x);
|
||||
}
|
||||
|
||||
#ifdef Py_HAVE_C_COMPLEX
|
||||
static PyObject *
|
||||
nu_float_complex(_structmodulestate *state, const char *p, const formatdef *f)
|
||||
{
|
||||
float complex x;
|
||||
float x[2];
|
||||
|
||||
memcpy(&x, p, sizeof(x));
|
||||
return PyComplex_FromDoubles(creal(x), cimag(x));
|
||||
return PyComplex_FromDoubles(x[0], x[1]);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
nu_double_complex(_structmodulestate *state, const char *p, const formatdef *f)
|
||||
{
|
||||
double complex x;
|
||||
double x[2];
|
||||
|
||||
memcpy(&x, p, sizeof(x));
|
||||
return PyComplex_FromDoubles(creal(x), cimag(x));
|
||||
return PyComplex_FromDoubles(x[0], x[1]);
|
||||
}
|
||||
#endif
|
||||
|
||||
static PyObject *
|
||||
nu_void_p(_structmodulestate *state, const char *p, const formatdef *f)
|
||||
|
@ -788,13 +783,12 @@ np_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef Py_HAVE_C_COMPLEX
|
||||
static int
|
||||
np_float_complex(_structmodulestate *state, char *p, PyObject *v,
|
||||
const formatdef *f)
|
||||
{
|
||||
Py_complex c = PyComplex_AsCComplex(v);
|
||||
float complex x = CMPLXF((float)c.real, (float)c.imag);
|
||||
float x[2] = {(float)c.real, (float)c.imag};
|
||||
|
||||
if (c.real == -1 && PyErr_Occurred()) {
|
||||
PyErr_SetString(state->StructError,
|
||||
|
@ -810,7 +804,7 @@ np_double_complex(_structmodulestate *state, char *p, PyObject *v,
|
|||
const formatdef *f)
|
||||
{
|
||||
Py_complex c = PyComplex_AsCComplex(v);
|
||||
double complex x = CMPLX(c.real, c.imag);
|
||||
double x[2] = {c.real, c.imag};
|
||||
|
||||
if (c.real == -1 && PyErr_Occurred()) {
|
||||
PyErr_SetString(state->StructError,
|
||||
|
@ -820,25 +814,6 @@ np_double_complex(_structmodulestate *state, char *p, PyObject *v,
|
|||
memcpy(p, &x, sizeof(x));
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int
|
||||
np_complex_stub(_structmodulestate *state, char *p, PyObject *v,
|
||||
const formatdef *f)
|
||||
{
|
||||
PyErr_Format(state->StructError,
|
||||
"'%c' format not supported on this system",
|
||||
f->format);
|
||||
return -1;
|
||||
}
|
||||
static PyObject *
|
||||
nu_complex_stub(_structmodulestate *state, const char *p, const formatdef *f)
|
||||
{
|
||||
PyErr_Format(state->StructError,
|
||||
"'%c' format not supported on this system",
|
||||
f->format);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
np_void_p(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
|
||||
|
@ -878,13 +853,8 @@ static const formatdef native_table[] = {
|
|||
{'e', sizeof(short), _Alignof(short), nu_halffloat, np_halffloat},
|
||||
{'f', sizeof(float), _Alignof(float), nu_float, np_float},
|
||||
{'d', sizeof(double), _Alignof(double), nu_double, np_double},
|
||||
#ifdef Py_HAVE_C_COMPLEX
|
||||
{'F', sizeof(float complex), _Alignof(float complex), nu_float_complex, np_float_complex},
|
||||
{'D', sizeof(double complex), _Alignof(double complex), nu_double_complex, np_double_complex},
|
||||
#else
|
||||
{'F', 1, 0, nu_complex_stub, np_complex_stub},
|
||||
{'D', 1, 0, nu_complex_stub, np_complex_stub},
|
||||
#endif
|
||||
{'F', 2*sizeof(float), _Alignof(float[2]), nu_float_complex, np_float_complex},
|
||||
{'D', 2*sizeof(double), _Alignof(double[2]), nu_double_complex, np_double_complex},
|
||||
{'P', sizeof(void *), _Alignof(void *), nu_void_p, np_void_p},
|
||||
{0}
|
||||
};
|
||||
|
@ -985,7 +955,6 @@ bu_double(_structmodulestate *state, const char *p, const formatdef *f)
|
|||
return unpack_double(p, 0);
|
||||
}
|
||||
|
||||
#ifdef Py_HAVE_C_COMPLEX
|
||||
static PyObject *
|
||||
bu_float_complex(_structmodulestate *state, const char *p, const formatdef *f)
|
||||
{
|
||||
|
@ -1015,7 +984,6 @@ bu_double_complex(_structmodulestate *state, const char *p, const formatdef *f)
|
|||
}
|
||||
return PyComplex_FromDoubles(x, y);
|
||||
}
|
||||
#endif
|
||||
|
||||
static PyObject *
|
||||
bu_bool(_structmodulestate *state, const char *p, const formatdef *f)
|
||||
|
@ -1156,7 +1124,6 @@ bp_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
|
|||
return PyFloat_Pack8(x, p, 0);
|
||||
}
|
||||
|
||||
#ifdef Py_HAVE_C_COMPLEX
|
||||
static int
|
||||
bp_float_complex(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
|
||||
{
|
||||
|
@ -1186,7 +1153,6 @@ bp_double_complex(_structmodulestate *state, char *p, PyObject *v, const formatd
|
|||
}
|
||||
return PyFloat_Pack8(x.imag, p + 8, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
bp_bool(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
|
||||
|
@ -1218,13 +1184,8 @@ static formatdef bigendian_table[] = {
|
|||
{'e', 2, 0, bu_halffloat, bp_halffloat},
|
||||
{'f', 4, 0, bu_float, bp_float},
|
||||
{'d', 8, 0, bu_double, bp_double},
|
||||
#ifdef Py_HAVE_C_COMPLEX
|
||||
{'F', 8, 0, bu_float_complex, bp_float_complex},
|
||||
{'D', 16, 0, bu_double_complex, bp_double_complex},
|
||||
#else
|
||||
{'F', 1, 0, nu_complex_stub, np_complex_stub},
|
||||
{'D', 1, 0, nu_complex_stub, np_complex_stub},
|
||||
#endif
|
||||
{0}
|
||||
};
|
||||
|
||||
|
@ -1324,7 +1285,6 @@ lu_double(_structmodulestate *state, const char *p, const formatdef *f)
|
|||
return unpack_double(p, 1);
|
||||
}
|
||||
|
||||
#ifdef Py_HAVE_C_COMPLEX
|
||||
static PyObject *
|
||||
lu_float_complex(_structmodulestate *state, const char *p, const formatdef *f)
|
||||
{
|
||||
|
@ -1354,7 +1314,6 @@ lu_double_complex(_structmodulestate *state, const char *p, const formatdef *f)
|
|||
}
|
||||
return PyComplex_FromDoubles(x, y);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
lp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
|
||||
|
@ -1489,7 +1448,6 @@ lp_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
|
|||
return PyFloat_Pack8(x, p, 1);
|
||||
}
|
||||
|
||||
#ifdef Py_HAVE_C_COMPLEX
|
||||
static int
|
||||
lp_float_complex(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
|
||||
{
|
||||
|
@ -1520,7 +1478,6 @@ lp_double_complex(_structmodulestate *state, char *p, PyObject *v, const formatd
|
|||
}
|
||||
return PyFloat_Pack8(x.imag, p + 8, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static formatdef lilendian_table[] = {
|
||||
{'x', 1, 0, NULL},
|
||||
|
@ -1542,13 +1499,8 @@ static formatdef lilendian_table[] = {
|
|||
{'e', 2, 0, lu_halffloat, lp_halffloat},
|
||||
{'f', 4, 0, lu_float, lp_float},
|
||||
{'d', 8, 0, lu_double, lp_double},
|
||||
#ifdef Py_HAVE_C_COMPLEX
|
||||
{'F', 8, 0, lu_float_complex, lp_float_complex},
|
||||
{'D', 16, 0, lu_double_complex, lp_double_complex},
|
||||
#else
|
||||
{'F', 1, 0, nu_complex_stub, np_complex_stub},
|
||||
{'D', 1, 0, nu_complex_stub, np_complex_stub},
|
||||
#endif
|
||||
{0}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue