mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 18:28:49 +00:00 
			
		
		
		
	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:
		
							parent
							
								
									f55273b3b7
								
							
						
					
					
						commit
						7487db4c7a
					
				
					 5 changed files with 321 additions and 29 deletions
				
			
		|  | @ -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'``. | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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: | ||||||
|  |  | ||||||
|  | @ -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). | ||||||
|  |  | ||||||
|  | @ -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. | ||||||
|  | @ -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} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Sergey B Kirpichev
						Sergey B Kirpichev