Skip to content

Commit 226aaab

Browse files
committed
gh-148464: Add missing __ctype_le/be__ attributes for complex types in the ctype module
1 parent 8fc66ae commit 226aaab

File tree

4 files changed

+111
-1
lines changed

4 files changed

+111
-1
lines changed

Lib/test/test_ctypes/test_byteswap.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import binascii
2+
import ctypes
23
import math
34
import struct
45
import sys
@@ -165,6 +166,48 @@ def test_endian_double(self):
165166
self.assertEqual(s.value, math.pi)
166167
self.assertEqual(bin(struct.pack(">d", math.pi)), bin(s))
167168

169+
@unittest.skipUnless(hasattr(ctypes, 'c_float_complex'), "No complex types")
170+
def test_endian_float_complex(self):
171+
c_float_complex = ctypes.c_float_complex
172+
if sys.byteorder == "little":
173+
self.assertIs(c_float_complex.__ctype_le__, c_float_complex)
174+
self.assertIs(c_float_complex.__ctype_be__.__ctype_le__,
175+
c_float_complex)
176+
else:
177+
self.assertIs(c_float_complex.__ctype_be__, c_float_complex)
178+
self.assertIs(c_float_complex.__ctype_le__.__ctype_be__,
179+
c_float_complex)
180+
s = c_float_complex(math.pi+1j)
181+
self.assertEqual(bin(struct.pack("F", math.pi+1j)), bin(s))
182+
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
183+
s = c_float_complex.__ctype_le__(math.pi+1j)
184+
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
185+
self.assertEqual(bin(struct.pack("<F", math.pi+1j)), bin(s))
186+
s = c_float_complex.__ctype_be__(math.pi+1j)
187+
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
188+
self.assertEqual(bin(struct.pack(">F", math.pi+1j)), bin(s))
189+
190+
@unittest.skipUnless(hasattr(ctypes, 'c_double_complex'), "No complex types")
191+
def test_endian_double_complex(self):
192+
c_double_complex = ctypes.c_double_complex
193+
if sys.byteorder == "little":
194+
self.assertIs(c_double_complex.__ctype_le__, c_double_complex)
195+
self.assertIs(c_double_complex.__ctype_be__.__ctype_le__,
196+
c_double_complex)
197+
else:
198+
self.assertIs(c_double_complex.__ctype_be__, c_double_complex)
199+
self.assertIs(c_double_complex.__ctype_le__.__ctype_be__,
200+
c_double_complex)
201+
s = c_double_complex(math.pi+1j)
202+
self.assertEqual(bin(struct.pack("D", math.pi+1j)), bin(s))
203+
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
204+
s = c_double_complex.__ctype_le__(math.pi+1j)
205+
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
206+
self.assertEqual(bin(struct.pack("<D", math.pi+1j)), bin(s))
207+
s = c_double_complex.__ctype_be__(math.pi+1j)
208+
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
209+
self.assertEqual(bin(struct.pack(">D", math.pi+1j)), bin(s))
210+
168211
def test_endian_other(self):
169212
self.assertIs(c_byte.__ctype_le__, c_byte)
170213
self.assertIs(c_byte.__ctype_be__, c_byte)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add missing ``__ctype_le/be__`` attributes for
2+
:class:`~ctypes.c_double_float` and :class:`~ctypes.c_double_complex`. Patch
3+
by Sergey B Kirpichev.

Modules/_ctypes/_ctypes.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2267,7 +2267,17 @@ static PyObject *CreateSwappedType(ctypes_state *st, PyTypeObject *type,
22672267
return NULL;
22682268
}
22692269

2270-
stginfo->ffi_type_pointer = *fmt->pffi_type;
2270+
if (!fmt->pffi_type->elements) {
2271+
stginfo->ffi_type_pointer = *fmt->pffi_type;
2272+
}
2273+
else {
2274+
stginfo->ffi_type_pointer.size = fmt->pffi_type->size;
2275+
stginfo->ffi_type_pointer.alignment = fmt->pffi_type->alignment;
2276+
stginfo->ffi_type_pointer.type = fmt->pffi_type->type;
2277+
stginfo->ffi_type_pointer.elements = PyMem_Malloc(2 * sizeof(ffi_type));
2278+
memcpy(stginfo->ffi_type_pointer.elements,
2279+
fmt->pffi_type->elements, 2 * sizeof(ffi_type));
2280+
}
22712281
stginfo->align = fmt->pffi_type->alignment;
22722282
stginfo->length = 0;
22732283
stginfo->size = fmt->pffi_type->size;

Modules/_ctypes/cfield.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,32 @@ D_get(void *ptr, Py_ssize_t size)
792792
return PyComplex_FromDoubles(x[0], x[1]);
793793
}
794794

795+
static PyObject *
796+
D_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
797+
{
798+
assert(NUM_BITS(size) || (size == 2*sizeof(double)));
799+
Py_complex c = PyComplex_AsCComplex(value);
800+
801+
if (c.real == -1 && PyErr_Occurred()) {
802+
return NULL;
803+
}
804+
if (PyFloat_Pack8(c.real, ptr, PY_BIG_ENDIAN)
805+
|| PyFloat_Pack8(c.imag, ptr + sizeof(double), PY_BIG_ENDIAN))
806+
{
807+
return NULL;
808+
}
809+
_RET(value);
810+
}
811+
812+
static PyObject *
813+
D_get_sw(void *ptr, Py_ssize_t size)
814+
{
815+
assert(NUM_BITS(size) || (size == 2*sizeof(double)));
816+
return PyComplex_FromDoubles(PyFloat_Unpack8(ptr, PY_BIG_ENDIAN),
817+
PyFloat_Unpack8(ptr + sizeof(double),
818+
PY_BIG_ENDIAN));
819+
}
820+
795821
/* F: float complex */
796822
static PyObject *
797823
F_set(void *ptr, PyObject *value, Py_ssize_t size)
@@ -817,6 +843,32 @@ F_get(void *ptr, Py_ssize_t size)
817843
return PyComplex_FromDoubles(x[0], x[1]);
818844
}
819845

846+
static PyObject *
847+
F_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
848+
{
849+
assert(NUM_BITS(size) || (size == 2*sizeof(float)));
850+
Py_complex c = PyComplex_AsCComplex(value);
851+
852+
if (c.real == -1 && PyErr_Occurred()) {
853+
return NULL;
854+
}
855+
if (PyFloat_Pack4(c.real, ptr, PY_BIG_ENDIAN)
856+
|| PyFloat_Pack4(c.imag, ptr + sizeof(float), PY_BIG_ENDIAN))
857+
{
858+
return NULL;
859+
}
860+
_RET(value);
861+
}
862+
863+
static PyObject *
864+
F_get_sw(void *ptr, Py_ssize_t size)
865+
{
866+
assert(NUM_BITS(size) || (size == 2*sizeof(float)));
867+
return PyComplex_FromDoubles(PyFloat_Unpack4(ptr, PY_BIG_ENDIAN),
868+
PyFloat_Unpack4(ptr + sizeof(float),
869+
PY_BIG_ENDIAN));
870+
}
871+
820872
/* G: long double complex */
821873
static PyObject *
822874
G_set(void *ptr, PyObject *value, Py_ssize_t size)
@@ -1602,7 +1654,9 @@ for base_code, base_c_type in [
16021654
#if defined(_Py_FFI_SUPPORT_C_COMPLEX)
16031655
if (Py_FFI_COMPLEX_AVAILABLE) {
16041656
TABLE_ENTRY(D, &ffi_type_complex_double);
1657+
TABLE_ENTRY_SW(D, &ffi_type_complex_double);
16051658
TABLE_ENTRY(F, &ffi_type_complex_float);
1659+
TABLE_ENTRY_SW(F, &ffi_type_complex_float);
16061660
TABLE_ENTRY(G, &ffi_type_complex_longdouble);
16071661
}
16081662
#endif

0 commit comments

Comments
 (0)