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>
This commit is contained in:
Sergey B Kirpichev 2024-10-07 14:53:02 +03:00 committed by GitHub
parent f55273b3b7
commit 7487db4c7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 321 additions and 29 deletions

View file

@ -267,12 +267,26 @@ platform-dependent.
| ``P`` | :c:expr:`void \*` | integer | | \(5) | | ``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 .. versionchanged:: 3.3
Added support for the ``'n'`` and ``'N'`` formats. Added support for the ``'n'`` and ``'N'`` formats.
.. versionchanged:: 3.6 .. versionchanged:: 3.6
Added support for the ``'e'`` format. Added support for the ``'e'`` format.
.. versionchanged:: 3.14
Added support for the ``'E'`` and ``'C'`` formats.
Notes: Notes:
@ -349,6 +363,11 @@ Notes:
of bytes. As a special case, ``'0s'`` means a single, empty string (while of bytes. As a special case, ``'0s'`` means a single, empty string (while
``'0c'`` means 0 characters). ``'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, A format character may be preceded by an integral repeat count. For example,
the format string ``'4h'`` means exactly the same as ``'hhhh'``. the format string ``'4h'`` means exactly the same as ``'hhhh'``.

View file

@ -208,8 +208,10 @@ if sizeof(c_longdouble) == sizeof(c_double):
try: try:
class c_double_complex(_SimpleCData): class c_double_complex(_SimpleCData):
_type_ = "C" _type_ = "C"
_check_size(c_double_complex)
class c_float_complex(_SimpleCData): class c_float_complex(_SimpleCData):
_type_ = "E" _type_ = "E"
_check_size(c_float_complex)
class c_longdouble_complex(_SimpleCData): class c_longdouble_complex(_SimpleCData):
_type_ = "F" _type_ = "F"
except AttributeError: except AttributeError:

View file

@ -1,4 +1,5 @@
from collections import abc from collections import abc
from itertools import combinations
import array import array
import gc import gc
import math import math
@ -11,12 +12,22 @@ import weakref
from test import support from test import support
from test.support import import_helper, suppress_immortalization from test.support import import_helper, suppress_immortalization
from test.support.script_helper import assert_python_ok from test.support.script_helper import assert_python_ok
from test.support.testcase import ComplexesAreIdenticalMixin
ISBIGENDIAN = sys.byteorder == "big" ISBIGENDIAN = sys.byteorder == "big"
integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N' integer_codes = 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'n', 'N'
byteorders = '', '@', '=', '<', '>', '!' 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): def iter_integer_formats(byteorders=byteorders):
for code in integer_codes: for code in integer_codes:
for byteorder in byteorders: for byteorder in byteorders:
@ -33,7 +44,7 @@ def bigendian_to_native(value):
else: else:
return string_reverse(value) return string_reverse(value)
class StructTest(unittest.TestCase): class StructTest(ComplexesAreIdenticalMixin, unittest.TestCase):
def test_isbigendian(self): def test_isbigendian(self):
self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN) self.assertEqual((struct.pack('=i', 1)[0] == 0), ISBIGENDIAN)
@ -783,6 +794,30 @@ class StructTest(unittest.TestCase):
s = struct.Struct('=i2H') s = struct.Struct('=i2H')
self.assertEqual(repr(s), f'Struct({s.format!r})') 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): class UnpackIteratorTest(unittest.TestCase):
""" """
Tests for iterative unpacking (struct.Struct.iter_unpack). Tests for iterative unpacking (struct.Struct.iter_unpack).

View file

@ -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.

View file

@ -12,6 +12,9 @@
#include "pycore_long.h" // _PyLong_AsByteArray() #include "pycore_long.h" // _PyLong_AsByteArray()
#include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_moduleobject.h" // _PyModule_GetState()
#ifdef Py_HAVE_C_COMPLEX
# include "_complex.h" // complex
#endif
#include <stddef.h> // offsetof() #include <stddef.h> // offsetof()
/*[clinic input] /*[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; long x; } st_long;
typedef struct { char c; float x; } st_float; typedef struct { char c; float x; } st_float;
typedef struct { char c; double x; } st_double; 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; void *x; } st_void_p;
typedef struct { char c; size_t x; } st_size_t; typedef struct { char c; size_t x; } st_size_t;
typedef struct { char c; _Bool x; } st_bool; 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 LONG_ALIGN (sizeof(st_long) - sizeof(long))
#define FLOAT_ALIGN (sizeof(st_float) - sizeof(float)) #define FLOAT_ALIGN (sizeof(st_float) - sizeof(float))
#define DOUBLE_ALIGN (sizeof(st_double) - sizeof(double)) #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 VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *))
#define SIZE_T_ALIGN (sizeof(st_size_t) - sizeof(size_t)) #define SIZE_T_ALIGN (sizeof(st_size_t) - sizeof(size_t))
#define BOOL_ALIGN (sizeof(st_bool) - sizeof(_Bool)) #define BOOL_ALIGN (sizeof(st_bool) - sizeof(_Bool))
@ -407,7 +418,7 @@ static PyObject *
nu_short(_structmodulestate *state, const char *p, const formatdef *f) nu_short(_structmodulestate *state, const char *p, const formatdef *f)
{ {
short x; short x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyLong_FromLong((long)x); return PyLong_FromLong((long)x);
} }
@ -415,7 +426,7 @@ static PyObject *
nu_ushort(_structmodulestate *state, const char *p, const formatdef *f) nu_ushort(_structmodulestate *state, const char *p, const formatdef *f)
{ {
unsigned short x; unsigned short x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyLong_FromLong((long)x); return PyLong_FromLong((long)x);
} }
@ -423,7 +434,7 @@ static PyObject *
nu_int(_structmodulestate *state, const char *p, const formatdef *f) nu_int(_structmodulestate *state, const char *p, const formatdef *f)
{ {
int x; int x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyLong_FromLong((long)x); return PyLong_FromLong((long)x);
} }
@ -431,7 +442,7 @@ static PyObject *
nu_uint(_structmodulestate *state, const char *p, const formatdef *f) nu_uint(_structmodulestate *state, const char *p, const formatdef *f)
{ {
unsigned int x; unsigned int x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyLong_FromUnsignedLong((unsigned long)x); return PyLong_FromUnsignedLong((unsigned long)x);
} }
@ -439,7 +450,7 @@ static PyObject *
nu_long(_structmodulestate *state, const char *p, const formatdef *f) nu_long(_structmodulestate *state, const char *p, const formatdef *f)
{ {
long x; long x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyLong_FromLong(x); return PyLong_FromLong(x);
} }
@ -447,7 +458,7 @@ static PyObject *
nu_ulong(_structmodulestate *state, const char *p, const formatdef *f) nu_ulong(_structmodulestate *state, const char *p, const formatdef *f)
{ {
unsigned long x; unsigned long x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyLong_FromUnsignedLong(x); return PyLong_FromUnsignedLong(x);
} }
@ -455,7 +466,7 @@ static PyObject *
nu_ssize_t(_structmodulestate *state, const char *p, const formatdef *f) nu_ssize_t(_structmodulestate *state, const char *p, const formatdef *f)
{ {
Py_ssize_t x; Py_ssize_t x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyLong_FromSsize_t(x); return PyLong_FromSsize_t(x);
} }
@ -463,7 +474,7 @@ static PyObject *
nu_size_t(_structmodulestate *state, const char *p, const formatdef *f) nu_size_t(_structmodulestate *state, const char *p, const formatdef *f)
{ {
size_t x; size_t x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyLong_FromSize_t(x); return PyLong_FromSize_t(x);
} }
@ -471,7 +482,7 @@ static PyObject *
nu_longlong(_structmodulestate *state, const char *p, const formatdef *f) nu_longlong(_structmodulestate *state, const char *p, const formatdef *f)
{ {
long long x; long long x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyLong_FromLongLong(x); return PyLong_FromLongLong(x);
} }
@ -479,7 +490,7 @@ static PyObject *
nu_ulonglong(_structmodulestate *state, const char *p, const formatdef *f) nu_ulonglong(_structmodulestate *state, const char *p, const formatdef *f)
{ {
unsigned long long x; unsigned long long x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyLong_FromUnsignedLongLong(x); return PyLong_FromUnsignedLongLong(x);
} }
@ -487,7 +498,7 @@ static PyObject *
nu_bool(_structmodulestate *state, const char *p, const formatdef *f) nu_bool(_structmodulestate *state, const char *p, const formatdef *f)
{ {
_Bool x; _Bool x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyBool_FromLong(x != 0); return PyBool_FromLong(x != 0);
} }
@ -506,7 +517,7 @@ static PyObject *
nu_float(_structmodulestate *state, const char *p, const formatdef *f) nu_float(_structmodulestate *state, const char *p, const formatdef *f)
{ {
float x; float x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyFloat_FromDouble((double)x); return PyFloat_FromDouble((double)x);
} }
@ -514,15 +525,35 @@ static PyObject *
nu_double(_structmodulestate *state, const char *p, const formatdef *f) nu_double(_structmodulestate *state, const char *p, const formatdef *f)
{ {
double x; double x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyFloat_FromDouble(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 * static PyObject *
nu_void_p(_structmodulestate *state, const char *p, const formatdef *f) nu_void_p(_structmodulestate *state, const char *p, const formatdef *f)
{ {
void *x; void *x;
memcpy((char *)&x, p, sizeof x); memcpy(&x, p, sizeof x);
return PyLong_FromVoidPtr(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); RANGE_ERROR(state, f, 0);
} }
y = (short)x; y = (short)x;
memcpy(p, (char *)&y, sizeof y); memcpy(p, &y, sizeof y);
return 0; return 0;
} }
@ -606,7 +637,7 @@ np_ushort(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
RANGE_ERROR(state, f, 1); RANGE_ERROR(state, f, 1);
} }
y = (unsigned short)x; y = (unsigned short)x;
memcpy(p, (char *)&y, sizeof y); memcpy(p, &y, sizeof y);
return 0; return 0;
} }
@ -626,7 +657,7 @@ np_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
RANGE_ERROR(state, f, 0); RANGE_ERROR(state, f, 0);
#endif #endif
y = (int)x; y = (int)x;
memcpy(p, (char *)&y, sizeof y); memcpy(p, &y, sizeof y);
return 0; return 0;
} }
@ -646,7 +677,7 @@ np_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
if (x > ((unsigned long)UINT_MAX)) if (x > ((unsigned long)UINT_MAX))
RANGE_ERROR(state, f, 1); RANGE_ERROR(state, f, 1);
#endif #endif
memcpy(p, (char *)&y, sizeof y); memcpy(p, &y, sizeof y);
return 0; return 0;
} }
@ -660,7 +691,7 @@ np_long(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
} }
return -1; return -1;
} }
memcpy(p, (char *)&x, sizeof x); memcpy(p, &x, sizeof x);
return 0; return 0;
} }
@ -674,7 +705,7 @@ np_ulong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
} }
return -1; return -1;
} }
memcpy(p, (char *)&x, sizeof x); memcpy(p, &x, sizeof x);
return 0; return 0;
} }
@ -688,7 +719,7 @@ np_ssize_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
} }
return -1; return -1;
} }
memcpy(p, (char *)&x, sizeof x); memcpy(p, &x, sizeof x);
return 0; return 0;
} }
@ -702,7 +733,7 @@ np_size_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
} }
return -1; return -1;
} }
memcpy(p, (char *)&x, sizeof x); memcpy(p, &x, sizeof x);
return 0; return 0;
} }
@ -720,7 +751,7 @@ np_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
} }
return -1; return -1;
} }
memcpy(p, (char *)&x, sizeof x); memcpy(p, &x, sizeof x);
return 0; return 0;
} }
@ -737,7 +768,7 @@ np_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f
} }
return -1; return -1;
} }
memcpy(p, (char *)&x, sizeof x); memcpy(p, &x, sizeof x);
return 0; return 0;
} }
@ -751,7 +782,7 @@ np_bool(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
if (y < 0) if (y < 0)
return -1; return -1;
x = y; x = y;
memcpy(p, (char *)&x, sizeof x); memcpy(p, &x, sizeof x);
return 0; return 0;
} }
@ -774,7 +805,7 @@ np_float(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
"required argument is not a float"); "required argument is not a float");
return -1; return -1;
} }
memcpy(p, (char *)&x, sizeof x); memcpy(p, &x, sizeof x);
return 0; return 0;
} }
@ -787,10 +818,62 @@ np_double(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
"required argument is not a float"); "required argument is not a float");
return -1; return -1;
} }
memcpy(p, (char *)&x, sizeof(double)); memcpy(p, &x, sizeof(double));
return 0; 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 static int
np_void_p(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) 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); Py_DECREF(v);
if (x == NULL && PyErr_Occurred()) if (x == NULL && PyErr_Occurred())
return -1; return -1;
memcpy(p, (char *)&x, sizeof x); memcpy(p, &x, sizeof x);
return 0; return 0;
} }
@ -829,6 +912,13 @@ static const formatdef native_table[] = {
{'e', sizeof(short), SHORT_ALIGN, nu_halffloat, np_halffloat}, {'e', sizeof(short), SHORT_ALIGN, nu_halffloat, np_halffloat},
{'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},
#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}, {'P', sizeof(void *), VOID_P_ALIGN, nu_void_p, np_void_p},
{0} {0}
}; };
@ -929,6 +1019,38 @@ bu_double(_structmodulestate *state, const char *p, const formatdef *f)
return unpack_double(p, 0); 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 * static PyObject *
bu_bool(_structmodulestate *state, const char *p, const formatdef *f) 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); 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 static int
bp_bool(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) 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}, {'e', 2, 0, bu_halffloat, bp_halffloat},
{'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},
#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} {0}
}; };
@ -1197,6 +1358,38 @@ lu_double(_structmodulestate *state, const char *p, const formatdef *f)
return unpack_double(p, 1); 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 static int
lp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) 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); 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[] = { static formatdef lilendian_table[] = {
{'x', 1, 0, NULL}, {'x', 1, 0, NULL},
{'b', 1, 0, nu_byte, np_byte}, {'b', 1, 0, nu_byte, np_byte},
@ -1350,6 +1576,13 @@ static formatdef lilendian_table[] = {
{'e', 2, 0, lu_halffloat, lp_halffloat}, {'e', 2, 0, lu_halffloat, lp_halffloat},
{'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},
#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} {0}
}; };