summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergey B Kirpichev <skirpichev@gmail.com>2024-10-07 11:53:02 (GMT)
committerGitHub <noreply@github.com>2024-10-07 11:53:02 (GMT)
commit7487db4c7af629f0a81b2127a3ee0000a288cefc (patch)
tree1cc74f0158815fcbb263df22eaac3720ac43a64a
parentf55273b3b7124dc570911724107c2440f37905fc (diff)
downloadcpython-7487db4c7af629f0a81b2127a3ee0000a288cefc.zip
cpython-7487db4c7af629f0a81b2127a3ee0000a288cefc.tar.gz
cpython-7487db4c7af629f0a81b2127a3ee0000a288cefc.tar.bz2
gh-121249: Support _Complex types in the struct module (#121613)
Co-authored-by: Peter Bierma <zintensitydev@gmail.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Victor Stinner <vstinner@python.org>
-rw-r--r--Doc/library/struct.rst19
-rw-r--r--Lib/ctypes/__init__.py2
-rw-r--r--Lib/test/test_struct.py37
-rw-r--r--Misc/NEWS.d/next/Library/2024-07-10-08-13-34.gh-issue-121249.W9Gd09.rst3
-rw-r--r--Modules/_struct.c289
5 files changed, 321 insertions, 29 deletions
diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst
index 4769aff..3ea9e5b 100644
--- a/Doc/library/struct.rst
+++ b/Doc/library/struct.rst
@@ -267,12 +267,26 @@ 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 |
++========+==========================+====================+================+============+
+| ``E`` | :c:expr:`float complex` | complex | 8 | \(10) |
++--------+--------------------------+--------------------+----------------+------------+
+| ``C`` | :c:expr:`double complex` | complex | 16 | \(10) |
++--------+--------------------------+--------------------+----------------+------------+
+
.. versionchanged:: 3.3
Added support for the ``'n'`` and ``'N'`` formats.
.. versionchanged:: 3.6
Added support for the ``'e'`` format.
+.. versionchanged:: 3.14
+ Added support for the ``'E'`` and ``'C'`` formats.
+
Notes:
@@ -349,6 +363,11 @@ Notes:
of bytes. As a special case, ``'0s'`` means a single, empty string (while
``'0c'`` means 0 characters).
+(10)
+ 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.
+
A format character may be preceded by an integral repeat count. For example,
the format string ``'4h'`` means exactly the same as ``'hhhh'``.
diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py
index cb3a612..4a368f0 100644
--- a/Lib/ctypes/__init__.py
+++ b/Lib/ctypes/__init__.py
@@ -208,8 +208,10 @@ if sizeof(c_longdouble) == sizeof(c_double):
try:
class c_double_complex(_SimpleCData):
_type_ = "C"
+ _check_size(c_double_complex)
class c_float_complex(_SimpleCData):
_type_ = "E"
+ _check_size(c_float_complex)
class c_longdouble_complex(_SimpleCData):
_type_ = "F"
except AttributeError:
diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py
index bdbf880..e3193c7 100644
--- a/Lib/test/test_struct.py
+++ b/Lib/test/test_struct.py
@@ -1,4 +1,5 @@
from collections import abc
+from itertools import combinations
import array
import gc
import math
@@ -11,12 +12,22 @@ import weakref
from test import support
from test.support import import_helper, suppress_immortalization
from test.support.script_helper import assert_python_ok
+from test.support.testcase import ComplexesAreIdenticalMixin
ISBIGENDIAN = sys.byteorder == "big"
integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N'
byteorders = '', '@', '=', '<', '>', '!'
+INF = float('inf')
+NAN = float('nan')
+
+try:
+ struct.pack('C', 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:
@@ -33,7 +44,7 @@ def bigendian_to_native(value):
else:
return string_reverse(value)
-class StructTest(unittest.TestCase):
+class StructTest(ComplexesAreIdenticalMixin, unittest.TestCase):
def test_isbigendian(self):
self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
@@ -783,6 +794,30 @@ class StructTest(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)]
+ for z in values:
+ for f in ['E', 'C', '>E', '>C', '<E', '<C']:
+ with self.subTest(z=z, format=f):
+ 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 = "'E' format not supported on this system"
+ msg2 = "'C' format not supported on this system"
+ with self.assertRaisesRegex(struct.error, msg1):
+ struct.pack('E', 1j)
+ with self.assertRaisesRegex(struct.error, msg1):
+ struct.unpack('E', b'1')
+ with self.assertRaisesRegex(struct.error, msg2):
+ struct.pack('C', 1j)
+ with self.assertRaisesRegex(struct.error, msg2):
+ struct.unpack('C', b'1')
+
+
class UnpackIteratorTest(unittest.TestCase):
"""
Tests for iterative unpacking (struct.Struct.iter_unpack).
diff --git a/Misc/NEWS.d/next/Library/2024-07-10-08-13-34.gh-issue-121249.W9Gd09.rst b/Misc/NEWS.d/next/Library/2024-07-10-08-13-34.gh-issue-121249.W9Gd09.rst
new file mode 100644
index 0000000..2d41fca
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-07-10-08-13-34.gh-issue-121249.W9Gd09.rst
@@ -0,0 +1,3 @@
+Support the :c:expr:`float complex` and :c:expr:`double complex`
+C types in the :mod:`struct` module if the compiler has C11 complex
+arithmetic. Patch by Sergey B Kirpichev.
diff --git a/Modules/_struct.c b/Modules/_struct.c
index 2ae5060..4387c55 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -12,6 +12,9 @@
#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]
@@ -80,6 +83,10 @@ typedef struct { char c; int x; } st_int;
typedef struct { char c; long x; } st_long;
typedef struct { char c; float x; } st_float;
typedef struct { char c; double x; } st_double;
+#ifdef Py_HAVE_C_COMPLEX
+typedef struct { char c; float complex x; } st_float_complex;
+typedef struct { char c; double complex x; } st_double_complex;
+#endif
typedef struct { char c; void *x; } st_void_p;
typedef struct { char c; size_t x; } st_size_t;
typedef struct { char c; _Bool x; } st_bool;
@@ -89,6 +96,10 @@ typedef struct { char c; _Bool x; } st_bool;
#define LONG_ALIGN (sizeof(st_long) - sizeof(long))
#define FLOAT_ALIGN (sizeof(st_float) - sizeof(float))
#define DOUBLE_ALIGN (sizeof(st_double) - sizeof(double))
+#ifdef Py_HAVE_C_COMPLEX
+# define FLOAT_COMPLEX_ALIGN (sizeof(st_float_complex) - sizeof(float complex))
+# define DOUBLE_COMPLEX_ALIGN (sizeof(st_double_complex) - sizeof(double complex))
+#endif
#define VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *))
#define SIZE_T_ALIGN (sizeof(st_size_t) - sizeof(size_t))
#define BOOL_ALIGN (sizeof(st_bool) - sizeof(_Bool))
@@ -407,7 +418,7 @@ static PyObject *
nu_short(_structmodulestate *state, const char *p, const formatdef *f)
{
short x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyLong_FromLong((long)x);
}
@@ -415,7 +426,7 @@ static PyObject *
nu_ushort(_structmodulestate *state, const char *p, const formatdef *f)
{
unsigned short x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyLong_FromLong((long)x);
}
@@ -423,7 +434,7 @@ static PyObject *
nu_int(_structmodulestate *state, const char *p, const formatdef *f)
{
int x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyLong_FromLong((long)x);
}
@@ -431,7 +442,7 @@ static PyObject *
nu_uint(_structmodulestate *state, const char *p, const formatdef *f)
{
unsigned int x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyLong_FromUnsignedLong((unsigned long)x);
}
@@ -439,7 +450,7 @@ static PyObject *
nu_long(_structmodulestate *state, const char *p, const formatdef *f)
{
long x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyLong_FromLong(x);
}
@@ -447,7 +458,7 @@ static PyObject *
nu_ulong(_structmodulestate *state, const char *p, const formatdef *f)
{
unsigned long x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyLong_FromUnsignedLong(x);
}
@@ -455,7 +466,7 @@ static PyObject *
nu_ssize_t(_structmodulestate *state, const char *p, const formatdef *f)
{
Py_ssize_t x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyLong_FromSsize_t(x);
}
@@ -463,7 +474,7 @@ static PyObject *
nu_size_t(_structmodulestate *state, const char *p, const formatdef *f)
{
size_t x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyLong_FromSize_t(x);
}
@@ -471,7 +482,7 @@ static PyObject *
nu_longlong(_structmodulestate *state, const char *p, const formatdef *f)
{
long long x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyLong_FromLongLong(x);
}
@@ -479,7 +490,7 @@ static PyObject *
nu_ulonglong(_structmodulestate *state, const char *p, const formatdef *f)
{
unsigned long long x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyLong_FromUnsignedLongLong(x);
}
@@ -487,7 +498,7 @@ static PyObject *
nu_bool(_structmodulestate *state, const char *p, const formatdef *f)
{
_Bool x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyBool_FromLong(x != 0);
}
@@ -506,7 +517,7 @@ static PyObject *
nu_float(_structmodulestate *state, const char *p, const formatdef *f)
{
float x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyFloat_FromDouble((double)x);
}
@@ -514,15 +525,35 @@ static PyObject *
nu_double(_structmodulestate *state, const char *p, const formatdef *f)
{
double x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
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;
+
+ memcpy(&x, p, sizeof(x));
+ return PyComplex_FromDoubles(creal(x), cimag(x));
+}
+
+static PyObject *
+nu_double_complex(_structmodulestate *state, const char *p, const formatdef *f)
+{
+ double complex x;
+
+ memcpy(&x, p, sizeof(x));
+ return PyComplex_FromDoubles(creal(x), cimag(x));
+}
+#endif
+
static PyObject *
nu_void_p(_structmodulestate *state, const char *p, const formatdef *f)
{
void *x;
- memcpy((char *)&x, p, sizeof x);
+ memcpy(&x, p, sizeof x);
return PyLong_FromVoidPtr(x);
}
@@ -587,7 +618,7 @@ np_short(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
RANGE_ERROR(state, f, 0);
}
y = (short)x;
- memcpy(p, (char *)&y, sizeof y);
+ memcpy(p, &y, sizeof y);
return 0;
}
@@ -606,7 +637,7 @@ np_ushort(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
RANGE_ERROR(state, f, 1);
}
y = (unsigned short)x;
- memcpy(p, (char *)&y, sizeof y);
+ memcpy(p, &y, sizeof y);
return 0;
}
@@ -626,7 +657,7 @@ np_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
RANGE_ERROR(state, f, 0);
#endif
y = (int)x;
- memcpy(p, (char *)&y, sizeof y);
+ memcpy(p, &y, sizeof y);
return 0;
}
@@ -646,7 +677,7 @@ np_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
if (x > ((unsigned long)UINT_MAX))
RANGE_ERROR(state, f, 1);
#endif
- memcpy(p, (char *)&y, sizeof y);
+ memcpy(p, &y, sizeof y);
return 0;
}
@@ -660,7 +691,7 @@ np_long(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
}
return -1;
}
- memcpy(p, (char *)&x, sizeof x);
+ memcpy(p, &x, sizeof x);
return 0;
}
@@ -674,7 +705,7 @@ np_ulong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
}
return -1;
}
- memcpy(p, (char *)&x, sizeof x);
+ memcpy(p, &x, sizeof x);
return 0;
}
@@ -688,7 +719,7 @@ np_ssize_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
}
return -1;
}
- memcpy(p, (char *)&x, sizeof x);
+ memcpy(p, &x, sizeof x);
return 0;
}
@@ -702,7 +733,7 @@ np_size_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
}
return -1;
}
- memcpy(p, (char *)&x, sizeof x);
+ memcpy(p, &x, sizeof x);
return 0;
}
@@ -720,7 +751,7 @@ np_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
}
return -1;
}
- memcpy(p, (char *)&x, sizeof x);
+ memcpy(p, &x, sizeof x);
return 0;
}
@@ -737,7 +768,7 @@ np_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f
}
return -1;
}
- memcpy(p, (char *)&x, sizeof x);
+ memcpy(p, &x, sizeof x);
return 0;
}
@@ -751,7 +782,7 @@ np_bool(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
if (y < 0)
return -1;
x = y;
- memcpy(p, (char *)&x, sizeof x);
+ memcpy(p, &x, sizeof x);
return 0;
}
@@ -774,7 +805,7 @@ np_float(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
"required argument is not a float");
return -1;
}
- memcpy(p, (char *)&x, sizeof x);
+ memcpy(p, &x, sizeof x);
return 0;
}
@@ -787,9 +818,61 @@ np_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
"required argument is not a float");
return -1;
}
- memcpy(p, (char *)&x, sizeof(double));
+ memcpy(p, &x, sizeof(double));
+ 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);
+
+ if (c.real == -1 && PyErr_Occurred()) {
+ PyErr_SetString(state->StructError,
+ "required argument is not a complex");
+ return -1;
+ }
+ memcpy(p, &x, sizeof(x));
+ return 0;
+}
+
+static int
+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);
+
+ if (c.real == -1 && PyErr_Occurred()) {
+ PyErr_SetString(state->StructError,
+ "required argument is not a complex");
+ return -1;
+ }
+ 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)
@@ -804,7 +887,7 @@ np_void_p(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
Py_DECREF(v);
if (x == NULL && PyErr_Occurred())
return -1;
- memcpy(p, (char *)&x, sizeof x);
+ memcpy(p, &x, sizeof x);
return 0;
}
@@ -829,6 +912,13 @@ static const formatdef native_table[] = {
{'e', sizeof(short), SHORT_ALIGN, nu_halffloat, np_halffloat},
{'f', sizeof(float), FLOAT_ALIGN, nu_float, np_float},
{'d', sizeof(double), DOUBLE_ALIGN, nu_double, np_double},
+#ifdef Py_HAVE_C_COMPLEX
+ {'E', sizeof(float complex), FLOAT_COMPLEX_ALIGN, nu_float_complex, np_float_complex},
+ {'C', sizeof(double complex), DOUBLE_COMPLEX_ALIGN, nu_double_complex, np_double_complex},
+#else
+ {'E', 1, 0, nu_complex_stub, np_complex_stub},
+ {'C', 1, 0, nu_complex_stub, np_complex_stub},
+#endif
{'P', sizeof(void *), VOID_P_ALIGN, nu_void_p, np_void_p},
{0}
};
@@ -929,6 +1019,38 @@ 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)
+{
+ double x = PyFloat_Unpack4(p, 0);
+ if (x == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
+ double y = PyFloat_Unpack4(p + 4, 0);
+ if (y == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
+ return PyComplex_FromDoubles(x, y);
+}
+
+static PyObject *
+bu_double_complex(_structmodulestate *state, const char *p, const formatdef *f)
+{
+ double x, y;
+
+ x = PyFloat_Unpack8(p, 0);
+ if (x == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
+ y = PyFloat_Unpack8(p + 8, 0);
+ if (y == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
+ return PyComplex_FromDoubles(x, y);
+}
+#endif
+
static PyObject *
bu_bool(_structmodulestate *state, const char *p, const formatdef *f)
{
@@ -1068,6 +1190,38 @@ 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)
+{
+ Py_complex x = PyComplex_AsCComplex(v);
+ if (x.real == -1 && PyErr_Occurred()) {
+ PyErr_SetString(state->StructError,
+ "required argument is not a complex");
+ return -1;
+ }
+ if (PyFloat_Pack4(x.real, p, 0)) {
+ return -1;
+ }
+ return PyFloat_Pack4(x.imag, p + 4, 0);
+}
+
+static int
+bp_double_complex(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
+{
+ Py_complex x = PyComplex_AsCComplex(v);
+ if (x.real == -1 && PyErr_Occurred()) {
+ PyErr_SetString(state->StructError,
+ "required argument is not a complex");
+ return -1;
+ }
+ if (PyFloat_Pack8(x.real, p, 0)) {
+ return -1;
+ }
+ return PyFloat_Pack8(x.imag, p + 8, 0);
+}
+#endif
+
static int
bp_bool(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
{
@@ -1098,6 +1252,13 @@ 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
+ {'E', 8, 0, bu_float_complex, bp_float_complex},
+ {'C', 16, 0, bu_double_complex, bp_double_complex},
+#else
+ {'E', 1, 0, nu_complex_stub, np_complex_stub},
+ {'C', 1, 0, nu_complex_stub, np_complex_stub},
+#endif
{0}
};
@@ -1197,6 +1358,38 @@ 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)
+{
+ double x = PyFloat_Unpack4(p, 1);
+ if (x == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
+ double y = PyFloat_Unpack4(p + 4, 1);
+ if (y == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
+ return PyComplex_FromDoubles(x, y);
+}
+
+static PyObject *
+lu_double_complex(_structmodulestate *state, const char *p, const formatdef *f)
+{
+ double x, y;
+
+ x = PyFloat_Unpack8(p, 1);
+ if (x == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
+ y = PyFloat_Unpack8(p + 8, 1);
+ if (y == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
+ return PyComplex_FromDoubles(x, y);
+}
+#endif
+
static int
lp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
{
@@ -1330,6 +1523,39 @@ 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)
+{
+ Py_complex x = PyComplex_AsCComplex(v);
+ if (x.real == -1 && PyErr_Occurred()) {
+ PyErr_SetString(state->StructError,
+ "required argument is not a complex");
+ return -1;
+ }
+ if (PyFloat_Pack4(x.real, p, 1)) {
+ return -1;
+ }
+ return PyFloat_Pack4(x.imag, p + 4, 1);
+
+}
+
+static int
+lp_double_complex(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
+{
+ Py_complex x = PyComplex_AsCComplex(v);
+ if (x.real == -1 && PyErr_Occurred()) {
+ PyErr_SetString(state->StructError,
+ "required argument is not a complex");
+ return -1;
+ }
+ if (PyFloat_Pack8(x.real, p, 1)) {
+ return -1;
+ }
+ return PyFloat_Pack8(x.imag, p + 8, 1);
+}
+#endif
+
static formatdef lilendian_table[] = {
{'x', 1, 0, NULL},
{'b', 1, 0, nu_byte, np_byte},
@@ -1350,6 +1576,13 @@ 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
+ {'E', 8, 0, lu_float_complex, lp_float_complex},
+ {'C', 16, 0, lu_double_complex, lp_double_complex},
+#else
+ {'E', 1, 0, nu_complex_stub, np_complex_stub},
+ {'C', 1, 0, nu_complex_stub, np_complex_stub},
+#endif
{0}
};