https://github.com/python/cpython/commit/7487db4c7af629f0a81b2127a3ee0000a288cefc
commit: 7487db4c7af629f0a81b2127a3ee0000a288cefc
branch: main
author: Sergey B Kirpichev <[email protected]>
committer: vstinner <[email protected]>
date: 2024-10-07T13:53:02+02:00
summary:

gh-121249: Support _Complex types in the struct module (#121613)

Co-authored-by: Peter Bierma <[email protected]>
Co-authored-by: Bénédikt Tran <[email protected]>
Co-authored-by: Victor Stinner <[email protected]>

files:
A Misc/NEWS.d/next/Library/2024-07-10-08-13-34.gh-issue-121249.W9Gd09.rst
M Doc/library/struct.rst
M Lib/ctypes/__init__.py
M Lib/test/test_struct.py
M Modules/_struct.c

diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst
index 4769affdf1d666..3ea9e5ba071289 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 cb3a61287bfe5d..4a368f02d851c5 100644
--- a/Lib/ctypes/__init__.py
+++ b/Lib/ctypes/__init__.py
@@ -208,8 +208,10 @@ class c_longdouble(_SimpleCData):
 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 bdbf8800cfd8f6..e3193c7863fbae 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 @@
 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 @@ def test_repr(self):
         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 00000000000000..2d41fca45bcad9
--- /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 2ae5060ba34163..4387c55b7c8848 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}
 };
 

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to