This commit is contained in:
Victor Stinner 2026-05-04 02:41:22 +03:00 committed by GitHub
commit 379d06ccfa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 616 additions and 331 deletions

View file

@ -52,6 +52,10 @@ defined:
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'D'`` | double complex | complex | 16 | \(4) |
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'Zf'`` | float complex | complex | 8 | \(4) |
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'Zd'`` | double complex | complex | 16 | \(4) |
+-----------+--------------------+-------------------+-----------------------+-------+
Notes:
@ -80,7 +84,7 @@ Notes:
.. versionadded:: 3.15
(4)
Complex types (``F`` and ``D``) are available unconditionally,
Complex types (``F``, ``D``, ``Zf`` and ``Zd``) are available unconditionally,
regardless on support for complex types (the Annex G of the C11 standard)
by the C compiler.
As specified in the C11 standard, each complex type is represented by a
@ -105,7 +109,10 @@ The module defines the following item:
.. data:: typecodes
A string with all available type codes.
A tuple with all available type codes.
.. versionchanged:: next
The type changed from :class:`str` to :class:`tuple`.
The module defines the following type:

View file

@ -370,15 +370,19 @@ in both C and ``libffi``, the following complex types are available:
* - :class:`c_float_complex`
- :c:expr:`float complex`
- :py:class:`complex`
- ``'F'``
- ``'Zf'``
* - :class:`c_double_complex`
- :c:expr:`double complex`
- :py:class:`complex`
- ``'D'``
- ``'Zd'``
* - :class:`c_longdouble_complex`
- :c:expr:`long double complex`
- :py:class:`complex`
- ``'G'``
- ``'Zg'``
.. versionchanged:: next
The :py:attr:`~_SimpleCData._type_` types ``F``, ``D`` and ``G`` have been
replaced with ``Zf``, ``Zd`` and ``Zg``.
All these types can be created by calling them with an optional initializer of

View file

@ -264,6 +264,10 @@ platform-dependent.
+--------+--------------------------+--------------------+----------------+------------+
| ``D`` | :c:expr:`double complex` | complex | 16 | \(10) |
+--------+--------------------------+--------------------+----------------+------------+
| ``Zf`` | :c:expr:`float complex` | complex | 8 | \(10) |
+--------+--------------------------+--------------------+----------------+------------+
| ``Zd`` | :c:expr:`double complex` | complex | 16 | \(10) |
+--------+--------------------------+--------------------+----------------+------------+
| ``s`` | :c:expr:`char[]` | bytes | | \(9) |
+--------+--------------------------+--------------------+----------------+------------+
| ``p`` | :c:expr:`char[]` | bytes | | \(8) |
@ -280,6 +284,9 @@ platform-dependent.
.. versionchanged:: 3.14
Added support for the ``'F'`` and ``'D'`` formats.
.. versionchanged:: next
Added support for the ``'Zf'`` and ``'Zd'`` formats.
.. seealso::
The :mod:`array` and :ref:`ctypes <ctypes-fundamental-data-types>` modules,
@ -372,7 +379,7 @@ Notes:
For the ``'F'`` and ``'D'`` 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.
Note that complex types (``F`` and ``D``) are available unconditionally,
Note that complex types (``F``/``Zf`` and ``D``/``Zd``) are available unconditionally,
despite complex types being an optional feature in C.
As specified in the C11 standard, each complex type is represented by a
two-element C array containing, respectively, the real and imaginary parts.

View file

@ -668,9 +668,10 @@ Other language changes
(Contributed by James Hilton-Balfe in :gh:`128335`.)
* The class :class:`memoryview` now supports the :c:expr:`float complex` and
:c:expr:`double complex` C types: formatting characters ``'F'`` and ``'D'``
respectively.
(Contributed by Sergey B Kirpichev in :gh:`146151`.)
:c:expr:`double complex` C types: formatting characters ``'F'``/``'Zf'``
and ``'D'``/``'Zd'`` respectively.
(Contributed by Sergey B Kirpichev and Victor Stinner in :gh:`146151`
and :gh:`148675`.)
* Allow the *count* argument of :meth:`bytes.replace` to be a keyword.
(Contributed by Stan Ulbrych in :gh:`147856`.)
@ -721,13 +722,18 @@ array
-----
* Support the :c:expr:`float complex` and :c:expr:`double complex` C types:
formatting characters ``'F'`` and ``'D'`` respectively.
(Contributed by Sergey B Kirpichev in :gh:`146151`.)
formatting characters ``'F'``/``'Zd'`` and ``'D'``/``'Zd'`` respectively.
(Contributed by Sergey B Kirpichev and Victor Stinner in :gh:`146151`
and :gh:`148675`.)
* Support half-floats (16-bit IEEE 754 binary interchange format): formatting
character ``'e'``.
(Contributed by Sergey B Kirpichev in :gh:`146238`.)
* The :data:`array.typecodes` type changed from :class:`str` to :class:`tuple`
to support type codes longer than 1 character (``Zf`` and ``Zd``).
(Contributed by Victor Stinner in :gh:`148675`.)
ast
---
@ -1733,6 +1739,12 @@ ctypes
which has been deprecated since Python 3.13.
(Contributed by Bénédikt Tran in :gh:`133866`.)
* Change the :py:attr:`~ctypes._SimpleCData._type_` of
:class:`~ctypes.c_float_complex`, :class:`~ctypes.c_double_complex` and
:class:`~ctypes.c_longdouble_complex` from ``F``, ``D`` and ``G`` to ``Zf``,
``Zd`` and ``Zg`` for compatibility with numpy.
(Contributed by Victor Stinner in :gh:`148675`.)
datetime
--------

View file

@ -206,13 +206,13 @@ class c_longdouble(_SimpleCData):
try:
class c_double_complex(_SimpleCData):
_type_ = "D"
_type_ = "Zd"
_check_size(c_double_complex)
class c_float_complex(_SimpleCData):
_type_ = "F"
_type_ = "Zf"
_check_size(c_float_complex)
class c_longdouble_complex(_SimpleCData):
_type_ = "G"
_type_ = "Zg"
except AttributeError:
pass

View file

@ -31,7 +31,10 @@ class ArraySubclassWithKwargs(array.array):
def __init__(self, typecode, newarg=None):
array.array.__init__(self)
typecodes = 'uwbBhHiIlLfdqQFDe'
typecodes = (
'u', 'w', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L',
'f', 'd', 'q', 'Q', 'F', 'D', 'e', 'Zf', 'Zd')
class MiscTest(unittest.TestCase):
@ -42,8 +45,9 @@ def test_array_is_sequence(self):
def test_bad_constructor(self):
self.assertRaises(TypeError, array.array)
self.assertRaises(TypeError, array.array, spam=42)
self.assertRaises(TypeError, array.array, 'xx')
self.assertRaises(ValueError, array.array, 'xx')
self.assertRaises(ValueError, array.array, 'x')
self.assertRaises(ValueError, array.array, 'Z')
@support.cpython_only
def test_disallow_instantiation(self):
@ -85,6 +89,12 @@ def __index__(self):
with self.assertRaises(TypeError):
a.fromlist(lst)
def test_typecodes(self):
self.assertIsInstance(array.typecodes, tuple)
for typecode in array.typecodes:
self.assertIsInstance(typecode, str)
self.assertGreaterEqual(len(typecode), 1)
# Machine format codes.
#
@ -208,6 +218,14 @@ def test_numbers(self):
[9006104071832581.0j, float('inf'), complex('1-infj'), -0.0]),
(['D'], IEEE_754_DOUBLE_COMPLEX_BE, '>DDDD',
[9006104071832581.0j, float('inf'), complex('1-infj'), -0.0]),
(['Zf'], IEEE_754_FLOAT_COMPLEX_LE, '<ZfZfZfZf',
[16711938.0j, float('inf'), complex('1-infj'), -0.0]),
(['Zf'], IEEE_754_FLOAT_COMPLEX_BE, '>ZfZfZfZf',
[16711938.0j, float('inf'), complex('1-infj'), -0.0]),
(['Zd'], IEEE_754_DOUBLE_COMPLEX_LE, '<ZdZdZdZd',
[9006104071832581.0j, float('inf'), complex('1-infj'), -0.0]),
(['Zd'], IEEE_754_DOUBLE_COMPLEX_BE, '>ZdZdZdZd',
[9006104071832581.0j, float('inf'), complex('1-infj'), -0.0]),
)
for testcase in testcases:
valid_typecodes, mformat_code, struct_fmt, values = testcase
@ -1237,6 +1255,9 @@ def test_free_after_iterating(self):
support.check_free_after_iterating(self, reversed, array.array,
(self.typecode,))
def test_known_typecode(self):
self.assertIn(self.typecode, array.typecodes)
class StringTest(BaseTest):
def test_setitem(self):
@ -1576,7 +1597,7 @@ def test_nan(self):
def test_byteswap(self):
a = array.array(self.typecode, self.example)
self.assertRaises(TypeError, a.byteswap, 42)
if a.itemsize in (1, 2, 4, 8):
if a.itemsize in (1, 2, 4, 8, 16):
b = array.array(self.typecode, self.example)
b.byteswap()
if a.itemsize == 1:
@ -1631,6 +1652,14 @@ class ComplexDoubleTest(CFPTest, unittest.TestCase):
typecode = 'D'
minitemsize = 16
class ComplexZfFloatTest(CFPTest, unittest.TestCase):
typecode = 'Zf'
minitemsize = 8
class ComplexZdDoubleTest(CFPTest, unittest.TestCase):
typecode = 'Zd'
minitemsize = 16
class LargeArrayTest(unittest.TestCase):
typecode = 'b'

View file

@ -67,7 +67,7 @@
'h':0, 'H':0, 'i':0, 'I':0,
'l':0, 'L':0, 'n':0, 'N':0,
'e':0, 'f':0, 'd':0, 'P':0,
'F':0, 'D':0
'F':0, 'D':0, 'Zf':0, 'Zd':0,
}
# NumPy does not have 'n' or 'N':
@ -95,7 +95,9 @@
'e':(-65519, 65520), 'f':(-(1<<63), 1<<63),
'd':(-(1<<1023), 1<<1023),
'F':(-(1<<63), 1<<63),
'D':(-(1<<1023), 1<<1023)
'D':(-(1<<1023), 1<<1023),
'Zf':(-(1<<63), 1<<63),
'Zd':(-(1<<1023), 1<<1023),
}
def native_type_range(fmt):
@ -110,9 +112,9 @@ def native_type_range(fmt):
lh = (-(1<<63), 1<<63)
elif fmt == 'd':
lh = (-(1<<1023), 1<<1023)
elif fmt == 'F':
elif fmt in ('F', 'Zf'):
lh = (-(1<<63), 1<<63)
elif fmt == 'D':
elif fmt in ('D', 'Zd'):
lh = (-(1<<1023), 1<<1023)
else:
for exp in (128, 127, 64, 63, 32, 31, 16, 15, 8, 7):
@ -182,18 +184,28 @@ def randrange_fmt(mode, char, obj):
if char in 'efd':
x = struct.pack(char, x)
x = struct.unpack(char, x)[0]
if char in 'FD':
if char in ('F', 'D', 'Zf', 'Zd'):
y = randrange(*fmtdict[mode][char])
x = complex(x, y)
x = struct.pack(char, x)
x = struct.unpack(char, x)[0]
return x
def split_format(fmt):
i = 0
while i < len(fmt):
if fmt[i] == 'Z':
n = 2
else:
n = 1
yield fmt[i:i + n]
i += n
def gen_item(fmt, obj):
"""Return single random item."""
mode, chars = fmt.split('#')
x = []
for c in chars:
for c in split_format(chars):
x.append(randrange_fmt(mode, c, obj))
return x[0] if len(x) == 1 else tuple(x)
@ -254,9 +266,7 @@ def is_byte_format(fmt):
def is_memoryview_format(fmt):
"""format suitable for memoryview"""
x = len(fmt)
return ((x == 1 or (x == 2 and fmt[0] == '@')) and
fmt[x-1] in MEMORYVIEW)
return fmt.removeprefix('@') in MEMORYVIEW
NON_BYTE_FORMAT = [c for c in fmtdict['@'] if not is_byte_format(c)]
@ -648,14 +658,22 @@ def ndarray_from_structure(items, fmt, t, flags=0):
return ndarray(items, shape=shape, strides=strides, format=fmt,
offset=offset, flags=ND_WRITABLE|flags)
# Convert PEP 3118 formats to numpy dtypes
FORMAT_TO_DTYPE = {
'Zf': 'F',
'Zd': 'D',
}
def numpy_array_from_structure(items, fmt, t):
"""Return numpy_array from the tuple returned by rand_structure()"""
memlen, itemsize, ndim, shape, strides, offset = t
buf = bytearray(memlen)
for j, v in enumerate(items):
struct.pack_into(fmt, buf, j*itemsize, v)
# Replace Zd/Zf formats with D/F dtypes
dtype = FORMAT_TO_DTYPE.get(fmt, fmt)
return numpy_array(buffer=buf, shape=shape, strides=strides,
dtype=fmt, offset=offset)
dtype=dtype, offset=offset)
# ======================================================================
@ -3037,7 +3055,7 @@ def test_memoryview_assign(self):
continue
m2 = m1.cast(fmt)
lo, hi = _range
if fmt in "dfDF":
if fmt in ("d", "f", "D", "F", "Zd", "Zf"):
lo, hi = -2**1024, 2**1024
if fmt != 'P': # PyLong_AsVoidPtr() accepts negative numbers
self.assertRaises(ValueError, m2.__setitem__, 0, lo-1)

View file

@ -213,14 +213,12 @@ def test_bad_type_message(self):
class F(metaclass=PyCSimpleType):
_type_ = "\0"
message = str(cm.exception)
expected_type_chars = list('cbBhHiIlLdDFGfuzZqQPXOv?g')
if not hasattr(ctypes, 'c_float_complex'):
expected_type_chars.remove('F')
expected_type_chars.remove('D')
expected_type_chars.remove('G')
expected_type_chars = list('cbBhHiIlLdfuzZqQPXOv?g')
if not MS_WINDOWS:
expected_type_chars.remove('X')
self.assertIn("'" + ''.join(expected_type_chars) + "'", message)
if hasattr(ctypes, 'c_float_complex'):
self.assertIn("'Zf', 'Zd', 'Zg'", message)
def test_creating_pointer_in_dunder_init_3(self):
"""Check if interfcase subclasses properly creates according internal

View file

@ -119,8 +119,11 @@ def test_floats(self):
@unittest.skipUnless(hasattr(ctypes, "c_double_complex"),
"requires C11 complex type")
def test_complex(self):
for t in [ctypes.c_double_complex, ctypes.c_float_complex,
ctypes.c_longdouble_complex]:
for format, t in [
('Zd', ctypes.c_double_complex),
('Zf', ctypes.c_float_complex),
('Zg', ctypes.c_longdouble_complex),
]:
self.assertEqual(t(1).value, 1+0j)
self.assertEqual(t(1.0).value, 1+0j)
self.assertEqual(t(1+0.125j).value, 1+0.125j)
@ -128,6 +131,12 @@ def test_complex(self):
self.assertEqual(t(FloatLike()).value, 2+0j)
self.assertEqual(t(ComplexLike()).value, 1+1j)
prefix = '>' if sys.byteorder == 'big' else '<'
num = t(1.0)
self.assertEqual(memoryview(num).format, prefix + format)
array = (t * 3)()
self.assertEqual(memoryview(array).format, prefix + format)
@unittest.skipUnless(hasattr(ctypes, "c_double_complex"),
"requires C11 complex type")
def test_complex_round_trip(self):

View file

@ -637,7 +637,7 @@ def check_equal(view, is_equal):
check_equal(m, True)
# Test complex formats
for complex_format in 'FD':
for complex_format in ('F', 'D', 'Zf', 'Zd'):
with self.subTest(format=complex_format):
data = struct.pack(complex_format * 3, 1.0, 2.0, float('nan'))
m = memoryview(data).cast(complex_format)
@ -723,6 +723,10 @@ def test_complex_types(self):
double_complex_view = memoryview(double_complex_data).cast('D')
self.assertEqual(float_complex_view.nbytes * 2, double_complex_view.nbytes)
self.assertListEqual(float_complex_view.tolist(), double_complex_view.tolist())
float_complex_view = memoryview(float_complex_data).cast('Zf')
double_complex_view = memoryview(double_complex_data).cast('Zd')
self.assertEqual(float_complex_view.nbytes * 2, double_complex_view.nbytes)
self.assertListEqual(float_complex_view.tolist(), double_complex_view.tolist())
def test_memoryview_hex(self):
# Issue #9951: memoryview.hex() segfaults with non-contiguous buffers.

View file

@ -995,7 +995,11 @@ 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 ['F', 'D', '>F', '>D', '<F', '<D']:
for f in [
'F', 'D', 'Zf', 'Zd',
'>F', '>D', '>Zf', '>Zd',
'<F', '<D', '<Zf', '<Zd',
]:
with self.subTest(z=z, format=f):
round_trip = struct.unpack(f, struct.pack(f, z))[0]
self.assertComplexesAreIdentical(z, round_trip)

View file

@ -0,0 +1,2 @@
:mod:`array`, :mod:`struct`: Add support for ``Zd`` and ``Zf`` formats for
double complex and float complex. Patch by Victor Stinner.

View file

@ -0,0 +1,3 @@
The :data:`array.typecodes` type changed from :class:`str` to :class:`tuple`
to support type codes longer than 1 character (``Zf`` and ``Zd``). Patch by
Victor Stinner.

View file

@ -0,0 +1,4 @@
:mod:`ctypes`: Change the :py:attr:`~ctypes._SimpleCData._type_` of
:class:`~ctypes.c_float_complex`, :class:`~ctypes.c_double_complex` and
:class:`~ctypes.c_longdouble_complex` from ``F``, ``D`` and ``G`` to ``Zf``,
``Zd`` and ``Zg`` for compatibility with numpy. Patch by Victor Stinner.

View file

@ -267,41 +267,40 @@ _PyDict_GetItemProxy(PyObject *dict, PyObject *key, PyObject **presult)
later on.
*/
static char *
_ctypes_alloc_format_string_for_type(char code, int big_endian)
_ctypes_alloc_format_string_for_type(const char *code, int big_endian)
{
char *result;
char pep_code = '\0';
const char *pep_code = NULL;
switch (code) {
switch (code[0]) {
#if SIZEOF_INT == 2
case 'i': pep_code = 'h'; break;
case 'I': pep_code = 'H'; break;
case 'i': pep_code = "h"; break;
case 'I': pep_code = "H"; break;
#elif SIZEOF_INT == 4
case 'i': pep_code = 'i'; break;
case 'I': pep_code = 'I'; break;
case 'i': pep_code = "i"; break;
case 'I': pep_code = "I"; break;
#elif SIZEOF_INT == 8
case 'i': pep_code = 'q'; break;
case 'I': pep_code = 'Q'; break;
case 'i': pep_code = "q"; break;
case 'I': pep_code = "Q"; break;
#else
# error SIZEOF_INT has an unexpected value
#endif /* SIZEOF_INT */
#if SIZEOF_LONG == 4
case 'l': pep_code = 'l'; break;
case 'L': pep_code = 'L'; break;
case 'l': pep_code = "l"; break;
case 'L': pep_code = "L"; break;
#elif SIZEOF_LONG == 8
case 'l': pep_code = 'q'; break;
case 'L': pep_code = 'Q'; break;
case 'l': pep_code = "q"; break;
case 'L': pep_code = "Q"; break;
#else
# error SIZEOF_LONG has an unexpected value
#endif /* SIZEOF_LONG */
#if SIZEOF__BOOL == 1
case '?': pep_code = '?'; break;
case '?': pep_code = "?"; break;
#elif SIZEOF__BOOL == 2
case '?': pep_code = 'H'; break;
case '?': pep_code = "H"; break;
#elif SIZEOF__BOOL == 4
case '?': pep_code = 'L'; break;
case '?': pep_code = "L"; break;
#elif SIZEOF__BOOL == 8
case '?': pep_code = 'Q'; break;
case '?': pep_code = "Q"; break;
#else
# error SIZEOF__BOOL has an unexpected value
#endif /* SIZEOF__BOOL */
@ -311,15 +310,14 @@ _ctypes_alloc_format_string_for_type(char code, int big_endian)
break;
}
result = PyMem_Malloc(3);
char *result = PyMem_Malloc(1 + strlen(pep_code) + 1);
if (result == NULL) {
PyErr_NoMemory();
return NULL;
}
result[0] = big_endian ? '>' : '<';
result[1] = pep_code;
result[2] = '\0';
strcpy(result + 1, pep_code);
return result;
}
@ -2347,7 +2345,6 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
{
PyObject *proto;
const char *proto_str;
Py_ssize_t proto_len;
PyMethodDef *ml;
struct fielddesc *fmt;
@ -2365,7 +2362,7 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
return -1;
}
if (PyUnicode_Check(proto)) {
proto_str = PyUnicode_AsUTF8AndSize(proto, &proto_len);
proto_str = PyUnicode_AsUTF8(proto);
if (!proto_str)
goto error;
} else {
@ -2373,19 +2370,25 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
"class must define a '_type_' string attribute");
goto error;
}
if (proto_len != 1) {
PyErr_SetString(PyExc_ValueError,
"class must define a '_type_' attribute "
"which must be a string of length 1");
goto error;
}
fmt = _ctypes_get_fielddesc(proto_str);
if (!fmt) {
PyErr_Format(PyExc_AttributeError,
"class must define a '_type_' attribute which must be\n"
"a single character string containing one of the\n"
"supported types: '%s'.",
_ctypes_get_simple_type_chars());
const char *complex_formats = _ctypes_get_complex_type_formats();
if (complex_formats) {
PyErr_Format(PyExc_AttributeError,
"class must define a '_type_' attribute which must be\n"
"a single character string containing one of the\n"
"supported types: '%s', or one of these strings:\n"
"%s.",
_ctypes_get_simple_type_chars(),
complex_formats);
}
else {
PyErr_Format(PyExc_AttributeError,
"class must define a '_type_' attribute which must be\n"
"a single character string containing one of the\n"
"supported types: '%s'.\n",
_ctypes_get_simple_type_chars());
}
goto error;
}
@ -2403,9 +2406,9 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
stginfo->setfunc = fmt->setfunc;
stginfo->getfunc = fmt->getfunc;
#ifdef WORDS_BIGENDIAN
stginfo->format = _ctypes_alloc_format_string_for_type(proto_str[0], 1);
stginfo->format = _ctypes_alloc_format_string_for_type(proto_str, 1);
#else
stginfo->format = _ctypes_alloc_format_string_for_type(proto_str[0], 0);
stginfo->format = _ctypes_alloc_format_string_for_type(proto_str, 0);
#endif
if (stginfo->format == NULL) {
Py_DECREF(proto);
@ -2432,9 +2435,15 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
ml = c_char_p_methods;
stginfo->flags |= TYPEFLAG_ISPOINTER;
break;
case 'Z': /* c_wchar_p */
ml = c_wchar_p_methods;
stginfo->flags |= TYPEFLAG_ISPOINTER;
case 'Z':
if (proto_str[1] == '\0') {
/* "Z": c_wchar_p */
ml = c_wchar_p_methods;
stginfo->flags |= TYPEFLAG_ISPOINTER;
}
else {
ml = NULL;
}
break;
case 'P': /* c_void_p */
ml = c_void_p_methods;

View file

@ -641,9 +641,9 @@ union result {
double d;
float f;
void *p;
double D[2];
float F[2];
long double G[2];
double Zd[2];
float Zf[2];
long double Zg[2];
};
struct argument {

View file

@ -767,9 +767,9 @@ d_get(void *ptr, Py_ssize_t size)
corresponding real type; the first element is equal to the real part, and
the second element to the imaginary part, of the complex number." */
/* D: double complex */
/* Zd: double complex */
static PyObject *
D_set(void *ptr, PyObject *value, Py_ssize_t size)
Zd_set(void *ptr, PyObject *value, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(double)));
Py_complex c = PyComplex_AsCComplex(value);
@ -783,7 +783,7 @@ D_set(void *ptr, PyObject *value, Py_ssize_t size)
}
static PyObject *
D_get(void *ptr, Py_ssize_t size)
Zd_get(void *ptr, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(double)));
double x[2];
@ -793,7 +793,7 @@ D_get(void *ptr, Py_ssize_t size)
}
static PyObject *
D_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
Zd_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(double)));
Py_complex c = PyComplex_AsCComplex(value);
@ -818,7 +818,7 @@ D_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
}
static PyObject *
D_get_sw(void *ptr, Py_ssize_t size)
Zd_get_sw(void *ptr, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(double)));
#ifdef WORDS_BIGENDIAN
@ -830,9 +830,9 @@ D_get_sw(void *ptr, Py_ssize_t size)
#endif
}
/* F: float complex */
/* Zf: float complex */
static PyObject *
F_set(void *ptr, PyObject *value, Py_ssize_t size)
Zf_set(void *ptr, PyObject *value, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(float)));
Py_complex c = PyComplex_AsCComplex(value);
@ -846,7 +846,7 @@ F_set(void *ptr, PyObject *value, Py_ssize_t size)
}
static PyObject *
F_get(void *ptr, Py_ssize_t size)
Zf_get(void *ptr, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(float)));
float x[2];
@ -856,7 +856,7 @@ F_get(void *ptr, Py_ssize_t size)
}
static PyObject *
F_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
Zf_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(float)));
Py_complex c = PyComplex_AsCComplex(value);
@ -881,7 +881,7 @@ F_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
}
static PyObject *
F_get_sw(void *ptr, Py_ssize_t size)
Zf_get_sw(void *ptr, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(float)));
#ifdef WORDS_BIGENDIAN
@ -893,9 +893,9 @@ F_get_sw(void *ptr, Py_ssize_t size)
#endif
}
/* G: long double complex */
/* Zg: long double complex */
static PyObject *
G_set(void *ptr, PyObject *value, Py_ssize_t size)
Zg_set(void *ptr, PyObject *value, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(long double)));
Py_complex c = PyComplex_AsCComplex(value);
@ -909,7 +909,7 @@ G_set(void *ptr, PyObject *value, Py_ssize_t size)
}
static PyObject *
G_get(void *ptr, Py_ssize_t size)
Zg_get(void *ptr, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(long double)));
long double x[2];
@ -917,7 +917,8 @@ G_get(void *ptr, Py_ssize_t size)
memcpy(&x, ptr, sizeof(x));
return PyComplex_FromDoubles((double)x[0], (double)x[1]);
}
#endif
#endif // _Py_FFI_SUPPORT_C_COMPLEX
/* d: double */
static PyObject *
@ -1451,7 +1452,7 @@ struct formattable {
for nbytes in 8, 16, 32, 64:
for sgn in 'i', 'u':
print(f' struct fielddesc fmt_{sgn}{nbytes};')
for code in 'sbBcdFDGgfhHiIlLqQPzuUZXvO':
for code in 'sbBcdgfhHiIlLqQPzuUZXvO':
print(f' struct fielddesc fmt_{code};')
[python start generated code]*/
struct fielddesc fmt_i8;
@ -1467,9 +1468,6 @@ for code in 'sbBcdFDGgfhHiIlLqQPzuUZXvO':
struct fielddesc fmt_B;
struct fielddesc fmt_c;
struct fielddesc fmt_d;
struct fielddesc fmt_F;
struct fielddesc fmt_D;
struct fielddesc fmt_G;
struct fielddesc fmt_g;
struct fielddesc fmt_f;
struct fielddesc fmt_h;
@ -1488,7 +1486,10 @@ for code in 'sbBcdFDGgfhHiIlLqQPzuUZXvO':
struct fielddesc fmt_X;
struct fielddesc fmt_v;
struct fielddesc fmt_O;
/*[python end generated code: output=f5a07c066fedaca6 input=ffa5d46c29dfb07a]*/
/*[python end generated code: output=266ae6d30b6286a1 input=a1b7a263c7cf681f]*/
struct fielddesc fmt_Zf;
struct fielddesc fmt_Zd;
struct fielddesc fmt_Zg;
// bool has code '?':
struct fielddesc fmt_bool;
@ -1498,7 +1499,7 @@ for code in 'sbBcdFDGgfhHiIlLqQPzuUZXvO':
// Result of _ctypes_get_simple_type_chars. Initialized just after
// the rest of formattable, so we stash it here.
char simple_type_chars[26];
char simple_type_chars[23];
};
static struct formattable formattable;
@ -1617,7 +1618,7 @@ for base_code, base_c_type in [
(base_code.upper(), 'unsigned ' + base_c_type, 'u' + base_c_type),
]:
print(f' formattable.fmt_{code} = *FIXINT_FIELDDESC_FOR({c_type});')
print(f" formattable.fmt_{code}.code = '{code}';")
print(f' formattable.fmt_{code}.code = "{code}";')
if base_code == 'q':
# ffi doesn't have `long long`; keep use the fixint type
pass
@ -1625,34 +1626,34 @@ for base_code, base_c_type in [
print(f' formattable.fmt_{code}.pffi_type = &ffi_type_{ffi_type};')
[python start generated code]*/
formattable.fmt_b = *FIXINT_FIELDDESC_FOR(signed char);
formattable.fmt_b.code = 'b';
formattable.fmt_b.code = "b";
formattable.fmt_b.pffi_type = &ffi_type_schar;
formattable.fmt_B = *FIXINT_FIELDDESC_FOR(unsigned char);
formattable.fmt_B.code = 'B';
formattable.fmt_B.code = "B";
formattable.fmt_B.pffi_type = &ffi_type_uchar;
formattable.fmt_h = *FIXINT_FIELDDESC_FOR(signed short);
formattable.fmt_h.code = 'h';
formattable.fmt_h.code = "h";
formattable.fmt_h.pffi_type = &ffi_type_sshort;
formattable.fmt_H = *FIXINT_FIELDDESC_FOR(unsigned short);
formattable.fmt_H.code = 'H';
formattable.fmt_H.code = "H";
formattable.fmt_H.pffi_type = &ffi_type_ushort;
formattable.fmt_i = *FIXINT_FIELDDESC_FOR(signed int);
formattable.fmt_i.code = 'i';
formattable.fmt_i.code = "i";
formattable.fmt_i.pffi_type = &ffi_type_sint;
formattable.fmt_I = *FIXINT_FIELDDESC_FOR(unsigned int);
formattable.fmt_I.code = 'I';
formattable.fmt_I.code = "I";
formattable.fmt_I.pffi_type = &ffi_type_uint;
formattable.fmt_l = *FIXINT_FIELDDESC_FOR(signed long);
formattable.fmt_l.code = 'l';
formattable.fmt_l.code = "l";
formattable.fmt_l.pffi_type = &ffi_type_slong;
formattable.fmt_L = *FIXINT_FIELDDESC_FOR(unsigned long);
formattable.fmt_L.code = 'L';
formattable.fmt_L.code = "L";
formattable.fmt_L.pffi_type = &ffi_type_ulong;
formattable.fmt_q = *FIXINT_FIELDDESC_FOR(signed long long);
formattable.fmt_q.code = 'q';
formattable.fmt_q.code = "q";
formattable.fmt_Q = *FIXINT_FIELDDESC_FOR(unsigned long long);
formattable.fmt_Q.code = 'Q';
/*[python end generated code: output=873c87a2e6b5075a input=ee814ca263aac18e]*/
formattable.fmt_Q.code = "Q";
/*[python end generated code: output=b91080b4b821a6da input=7356e281df4debd3]*/
/* Other types have bespoke setters and getters named `@_set` and `@_get`,
@ -1662,7 +1663,7 @@ for base_code, base_c_type in [
#define _TABLE_ENTRY(SYMBOL, FFI_TYPE, ...) \
formattable.fmt_ ## SYMBOL = \
(struct fielddesc){(#SYMBOL)[0], (FFI_TYPE), __VA_ARGS__}; \
(struct fielddesc){(#SYMBOL), (FFI_TYPE), __VA_ARGS__}; \
///////////////////////////////////////////////////////////////////////////
#define TABLE_ENTRY(SYMBOL, FFI_TYPE) \
@ -1677,11 +1678,11 @@ for base_code, base_c_type in [
TABLE_ENTRY_SW(d, &ffi_type_double);
#if defined(_Py_FFI_SUPPORT_C_COMPLEX)
if (Py_FFI_COMPLEX_AVAILABLE) {
TABLE_ENTRY(D, &ffi_type_complex_double);
TABLE_ENTRY_SW(D, &ffi_type_complex_double);
TABLE_ENTRY(F, &ffi_type_complex_float);
TABLE_ENTRY_SW(F, &ffi_type_complex_float);
TABLE_ENTRY(G, &ffi_type_complex_longdouble);
TABLE_ENTRY(Zd, &ffi_type_complex_double);
TABLE_ENTRY_SW(Zd, &ffi_type_complex_double);
TABLE_ENTRY(Zf, &ffi_type_complex_float);
TABLE_ENTRY_SW(Zf, &ffi_type_complex_float);
TABLE_ENTRY(Zg, &ffi_type_complex_longdouble);
}
#endif
TABLE_ENTRY(g, &ffi_type_longdouble);
@ -1711,12 +1712,12 @@ for base_code, base_c_type in [
// ctypes.c_bool is unsigned for FFI, even where C bool is signed.
formattable.fmt_bool = *_ctypes_fixint_fielddesc(sizeof(bool), false);
formattable.fmt_bool.code = '?';
formattable.fmt_bool.code = "?";
formattable.fmt_bool.setfunc = bool_set;
formattable.fmt_bool.getfunc = bool_get;
/*[python input]
all_chars = "cbBhHiIlLdDFGfuzZqQPXOv?g"
all_chars = "cbBhHiIlLdfuzZqQPXOv?g"
print(f' assert(sizeof(formattable.simple_type_chars) == {len(all_chars)+1});')
print(f' int i = 0;')
for char in all_chars:
@ -1725,7 +1726,7 @@ for char in all_chars:
+ f"formattable.simple_type_chars[i++] = '{char}';")
print(f" formattable.simple_type_chars[i] = 0;")
[python start generated code]*/
assert(sizeof(formattable.simple_type_chars) == 26);
assert(sizeof(formattable.simple_type_chars) == 23);
int i = 0;
if (formattable.fmt_c.code) formattable.simple_type_chars[i++] = 'c';
if (formattable.fmt_b.code) formattable.simple_type_chars[i++] = 'b';
@ -1737,9 +1738,6 @@ print(f" formattable.simple_type_chars[i] = 0;")
if (formattable.fmt_l.code) formattable.simple_type_chars[i++] = 'l';
if (formattable.fmt_L.code) formattable.simple_type_chars[i++] = 'L';
if (formattable.fmt_d.code) formattable.simple_type_chars[i++] = 'd';
if (formattable.fmt_D.code) formattable.simple_type_chars[i++] = 'D';
if (formattable.fmt_F.code) formattable.simple_type_chars[i++] = 'F';
if (formattable.fmt_G.code) formattable.simple_type_chars[i++] = 'G';
if (formattable.fmt_f.code) formattable.simple_type_chars[i++] = 'f';
if (formattable.fmt_u.code) formattable.simple_type_chars[i++] = 'u';
if (formattable.fmt_z.code) formattable.simple_type_chars[i++] = 'z';
@ -1753,24 +1751,34 @@ print(f" formattable.simple_type_chars[i] = 0;")
if (formattable.fmt_bool.code) formattable.simple_type_chars[i++] = '?';
if (formattable.fmt_g.code) formattable.simple_type_chars[i++] = 'g';
formattable.simple_type_chars[i] = 0;
/*[python end generated code: output=2aa52670d1570f18 input=cff3e7cb95adac61]*/
/*[python end generated code: output=b78c8b7eed73d45a input=30ddc50637dd8ee4]*/
}
#undef FIXINT_FIELDDESC_FOR
_Py_COMP_DIAG_POP
char *
const char*
_ctypes_get_simple_type_chars(void) {
return formattable.simple_type_chars;
}
const char*
_ctypes_get_complex_type_formats(void) {
if (Py_FFI_COMPLEX_AVAILABLE) {
return "'Zf', 'Zd', 'Zg'";
}
else {
return NULL;
}
}
struct fielddesc *
_ctypes_get_fielddesc(const char *fmt)
{
struct fielddesc *result = NULL;
switch(fmt[0]) {
/*[python input]
for code in 'sbBcdDFGgfhHiIlLqQPzuUZXvO':
for code in 'sbBcdgfhHiIlLqQPzuUXvO':
print(f" case '{code}': result = &formattable.fmt_{code}; break;")
[python start generated code]*/
case 's': result = &formattable.fmt_s; break;
@ -1778,9 +1786,6 @@ for code in 'sbBcdDFGgfhHiIlLqQPzuUZXvO':
case 'B': result = &formattable.fmt_B; break;
case 'c': result = &formattable.fmt_c; break;
case 'd': result = &formattable.fmt_d; break;
case 'D': result = &formattable.fmt_D; break;
case 'F': result = &formattable.fmt_F; break;
case 'G': result = &formattable.fmt_G; break;
case 'g': result = &formattable.fmt_g; break;
case 'f': result = &formattable.fmt_f; break;
case 'h': result = &formattable.fmt_h; break;
@ -1795,11 +1800,19 @@ for code in 'sbBcdDFGgfhHiIlLqQPzuUZXvO':
case 'z': result = &formattable.fmt_z; break;
case 'u': result = &formattable.fmt_u; break;
case 'U': result = &formattable.fmt_U; break;
case 'Z': result = &formattable.fmt_Z; break;
case 'X': result = &formattable.fmt_X; break;
case 'v': result = &formattable.fmt_v; break;
case 'O': result = &formattable.fmt_O; break;
/*[python end generated code: output=6e5c91940732fde9 input=902223feffc2fe38]*/
/*[python end generated code: output=8e95bd0d49efb1c8 input=82d4ee1538b9b282]*/
case 'Z': {
switch(fmt[1]) {
case '\0': result = &formattable.fmt_Z; break;
case 'd': result = &formattable.fmt_Zd; break;
case 'f': result = &formattable.fmt_Zf; break;
case 'g': result = &formattable.fmt_Zg; break;
}
break;
}
case '?': result = &formattable.fmt_bool; break;
}
if (!result || !result->code) {

View file

@ -280,7 +280,7 @@ extern CThunkObject *_ctypes_alloc_callback(ctypes_state *st,
int flags);
/* a table entry describing a predefined ctypes type */
struct fielddesc {
char code;
const char *code;
ffi_type *pffi_type; /* always statically allocated */
SETFUNC setfunc;
GETFUNC getfunc;
@ -289,7 +289,8 @@ struct fielddesc {
};
// Get all single-character type codes (for use in error messages)
extern char *_ctypes_get_simple_type_chars(void);
extern const char* _ctypes_get_simple_type_chars(void);
extern const char* _ctypes_get_complex_type_formats(void);
typedef struct CFieldObject {
PyObject_HEAD

View file

@ -45,7 +45,7 @@ static struct PyModuleDef _structmodule;
/* The translation function for each format character is table driven */
typedef struct _formatdef {
char format;
const char *format;
Py_ssize_t size;
Py_ssize_t alignment;
PyObject* (*unpack)(_structmodulestate *, const char *,
@ -327,13 +327,13 @@ _range_error(_structmodulestate *state, const formatdef *f, int is_unsigned)
assert(f->size >= 1 && f->size <= SIZEOF_SIZE_T);
if (is_unsigned)
PyErr_Format(state->StructError,
"'%c' format requires 0 <= number <= %zu",
"'%s' format requires 0 <= number <= %zu",
f->format,
ulargest);
else {
const Py_ssize_t largest = (Py_ssize_t)(ulargest >> 1);
PyErr_Format(state->StructError,
"'%c' format requires %zd <= number <= %zd",
"'%s' format requires %zd <= number <= %zd",
f->format,
~ largest,
largest);
@ -708,7 +708,7 @@ np_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
if (get_longlong(state, v, &x) < 0) {
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
PyErr_Format(state->StructError,
"'%c' format requires %lld <= number <= %lld",
"'%s' format requires %lld <= number <= %lld",
f->format,
LLONG_MIN,
LLONG_MAX);
@ -726,7 +726,7 @@ np_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f
if (get_ulonglong(state, v, &x) < 0) {
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
PyErr_Format(state->StructError,
"'%c' format requires 0 <= number <= %llu",
"'%s' format requires 0 <= number <= %llu",
f->format,
ULLONG_MAX);
}
@ -835,29 +835,31 @@ np_void_p(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
}
static const formatdef native_table[] = {
{'x', sizeof(char), 0, NULL},
{'b', sizeof(char), 0, nu_byte, np_byte},
{'B', sizeof(char), 0, nu_ubyte, np_ubyte},
{'c', sizeof(char), 0, nu_char, np_char},
{'s', sizeof(char), 0, NULL},
{'p', sizeof(char), 0, NULL},
{'h', sizeof(short), _Alignof(short), nu_short, np_short},
{'H', sizeof(short), _Alignof(short), nu_ushort, np_ushort},
{'i', sizeof(int), _Alignof(int), nu_int, np_int},
{'I', sizeof(int), _Alignof(int), nu_uint, np_uint},
{'l', sizeof(long), _Alignof(long), nu_long, np_long},
{'L', sizeof(long), _Alignof(long), nu_ulong, np_ulong},
{'n', sizeof(size_t), _Alignof(size_t), nu_ssize_t, np_ssize_t},
{'N', sizeof(size_t), _Alignof(size_t), nu_size_t, np_size_t},
{'q', sizeof(long long), _Alignof(long long), nu_longlong, np_longlong},
{'Q', sizeof(long long), _Alignof(long long), nu_ulonglong,np_ulonglong},
{'?', sizeof(_Bool), _Alignof(_Bool), nu_bool, np_bool},
{'e', sizeof(short), _Alignof(short), nu_halffloat, np_halffloat},
{'f', sizeof(float), _Alignof(float), nu_float, np_float},
{'d', sizeof(double), _Alignof(double), nu_double, np_double},
{'F', 2*sizeof(float), _Alignof(float), nu_float_complex, np_float_complex},
{'D', 2*sizeof(double), _Alignof(double), nu_double_complex, np_double_complex},
{'P', sizeof(void *), _Alignof(void *), nu_void_p, np_void_p},
{"x", sizeof(char), 0, NULL},
{"b", sizeof(char), 0, nu_byte, np_byte},
{"B", sizeof(char), 0, nu_ubyte, np_ubyte},
{"c", sizeof(char), 0, nu_char, np_char},
{"s", sizeof(char), 0, NULL},
{"p", sizeof(char), 0, NULL},
{"h", sizeof(short), _Alignof(short), nu_short, np_short},
{"H", sizeof(short), _Alignof(short), nu_ushort, np_ushort},
{"i", sizeof(int), _Alignof(int), nu_int, np_int},
{"I", sizeof(int), _Alignof(int), nu_uint, np_uint},
{"l", sizeof(long), _Alignof(long), nu_long, np_long},
{"L", sizeof(long), _Alignof(long), nu_ulong, np_ulong},
{"n", sizeof(size_t), _Alignof(size_t), nu_ssize_t, np_ssize_t},
{"N", sizeof(size_t), _Alignof(size_t), nu_size_t, np_size_t},
{"q", sizeof(long long), _Alignof(long long), nu_longlong, np_longlong},
{"Q", sizeof(long long), _Alignof(long long), nu_ulonglong,np_ulonglong},
{"?", sizeof(_Bool), _Alignof(_Bool), nu_bool, np_bool},
{"e", sizeof(short), _Alignof(short), nu_halffloat, np_halffloat},
{"f", sizeof(float), _Alignof(float), nu_float, np_float},
{"d", sizeof(double), _Alignof(double), nu_double, np_double},
{"F", 2*sizeof(float), _Alignof(float), nu_float_complex, np_float_complex},
{"D", 2*sizeof(double), _Alignof(double), nu_double_complex, np_double_complex},
{"Zf", 2*sizeof(float), _Alignof(float), nu_float_complex, np_float_complex},
{"Zd", 2*sizeof(double), _Alignof(double), nu_double_complex, np_double_complex},
{"P", sizeof(void *), _Alignof(void *), nu_void_p, np_void_p},
{0}
};
@ -1063,7 +1065,7 @@ bp_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
Py_DECREF(v);
if (res < 0) {
PyErr_Format(state->StructError,
"'%c' format requires %lld <= number <= %lld",
"'%s' format requires %lld <= number <= %lld",
f->format,
LLONG_MIN,
LLONG_MAX);
@ -1088,7 +1090,7 @@ bp_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f
Py_DECREF(v);
if (res < 0) {
PyErr_Format(state->StructError,
"'%c' format requires 0 <= number <= %llu",
"'%s' format requires 0 <= number <= %llu",
f->format,
ULLONG_MAX);
return -1;
@ -1168,26 +1170,28 @@ bp_bool(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
}
static formatdef bigendian_table[] = {
{'x', 1, 0, NULL},
{'b', 1, 0, nu_byte, np_byte},
{'B', 1, 0, nu_ubyte, np_ubyte},
{'c', 1, 0, nu_char, np_char},
{'s', 1, 0, NULL},
{'p', 1, 0, NULL},
{'h', 2, 0, bu_short, bp_int},
{'H', 2, 0, bu_uint, bp_uint},
{'i', 4, 0, bu_int, bp_int},
{'I', 4, 0, bu_uint, bp_uint},
{'l', 4, 0, bu_int, bp_int},
{'L', 4, 0, bu_uint, bp_uint},
{'q', 8, 0, bu_longlong, bp_longlong},
{'Q', 8, 0, bu_ulonglong, bp_ulonglong},
{'?', 1, 0, bu_bool, bp_bool},
{'e', 2, 0, bu_halffloat, bp_halffloat},
{'f', 4, 0, bu_float, bp_float},
{'d', 8, 0, bu_double, bp_double},
{'F', 8, 0, bu_float_complex, bp_float_complex},
{'D', 16, 0, bu_double_complex, bp_double_complex},
{"x", 1, 0, NULL},
{"b", 1, 0, nu_byte, np_byte},
{"B", 1, 0, nu_ubyte, np_ubyte},
{"c", 1, 0, nu_char, np_char},
{"s", 1, 0, NULL},
{"p", 1, 0, NULL},
{"h", 2, 0, bu_short, bp_int},
{"H", 2, 0, bu_uint, bp_uint},
{"i", 4, 0, bu_int, bp_int},
{"I", 4, 0, bu_uint, bp_uint},
{"l", 4, 0, bu_int, bp_int},
{"L", 4, 0, bu_uint, bp_uint},
{"q", 8, 0, bu_longlong, bp_longlong},
{"Q", 8, 0, bu_ulonglong, bp_ulonglong},
{"?", 1, 0, bu_bool, bp_bool},
{"e", 2, 0, bu_halffloat, bp_halffloat},
{"f", 4, 0, bu_float, bp_float},
{"d", 8, 0, bu_double, bp_double},
{"F", 8, 0, bu_float_complex, bp_float_complex},
{"D", 16, 0, bu_double_complex, bp_double_complex},
{"Zf", 8, 0, bu_float_complex, bp_float_complex},
{"Zd", 16, 0, bu_double_complex, bp_double_complex},
{0}
};
@ -1387,7 +1391,7 @@ lp_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
Py_DECREF(v);
if (res < 0) {
PyErr_Format(state->StructError,
"'%c' format requires %lld <= number <= %lld",
"'%s' format requires %lld <= number <= %lld",
f->format,
LLONG_MIN,
LLONG_MAX);
@ -1412,7 +1416,7 @@ lp_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f
Py_DECREF(v);
if (res < 0) {
PyErr_Format(state->StructError,
"'%c' format requires 0 <= number <= %llu",
"'%s' format requires 0 <= number <= %llu",
f->format,
ULLONG_MAX);
return -1;
@ -1482,27 +1486,29 @@ lp_double_complex(_structmodulestate *state, char *p, PyObject *v, const formatd
}
static formatdef lilendian_table[] = {
{'x', 1, 0, NULL},
{'b', 1, 0, nu_byte, np_byte},
{'B', 1, 0, nu_ubyte, np_ubyte},
{'c', 1, 0, nu_char, np_char},
{'s', 1, 0, NULL},
{'p', 1, 0, NULL},
{'h', 2, 0, lu_short, lp_int},
{'H', 2, 0, lu_uint, lp_uint},
{'i', 4, 0, lu_int, lp_int},
{'I', 4, 0, lu_uint, lp_uint},
{'l', 4, 0, lu_int, lp_int},
{'L', 4, 0, lu_uint, lp_uint},
{'q', 8, 0, lu_longlong, lp_longlong},
{'Q', 8, 0, lu_ulonglong, lp_ulonglong},
{'?', 1, 0, bu_bool, bp_bool}, /* Std rep not endian dep,
{"x", 1, 0, NULL},
{"b", 1, 0, nu_byte, np_byte},
{"B", 1, 0, nu_ubyte, np_ubyte},
{"c", 1, 0, nu_char, np_char},
{"s", 1, 0, NULL},
{"p", 1, 0, NULL},
{"h", 2, 0, lu_short, lp_int},
{"H", 2, 0, lu_uint, lp_uint},
{"i", 4, 0, lu_int, lp_int},
{"I", 4, 0, lu_uint, lp_uint},
{"l", 4, 0, lu_int, lp_int},
{"L", 4, 0, lu_uint, lp_uint},
{"q", 8, 0, lu_longlong, lp_longlong},
{"Q", 8, 0, lu_ulonglong, lp_ulonglong},
{"?", 1, 0, bu_bool, bp_bool}, /* Std rep not endian dep,
but potentially different from native rep -- reuse bx_bool funcs. */
{'e', 2, 0, lu_halffloat, lp_halffloat},
{'f', 4, 0, lu_float, lp_float},
{'d', 8, 0, lu_double, lp_double},
{'F', 8, 0, lu_float_complex, lp_float_complex},
{'D', 16, 0, lu_double_complex, lp_double_complex},
{"e", 2, 0, lu_halffloat, lp_halffloat},
{"f", 4, 0, lu_float, lp_float},
{"d", 8, 0, lu_double, lp_double},
{"F", 8, 0, lu_float_complex, lp_float_complex},
{"D", 16, 0, lu_double_complex, lp_double_complex},
{"Zf", 8, 0, lu_float_complex, lp_float_complex},
{"Zd", 16, 0, lu_double_complex, lp_double_complex},
{0}
};
@ -1523,10 +1529,10 @@ init_endian_tables(void *Py_UNUSED(arg))
entry in the endian table and swap in the
native implementations whenever possible
(64-bit platforms may not have "standard" sizes) */
while (native->format != '\0' && other->format != '\0') {
while (native->format != NULL && other->format != NULL) {
ptr = other;
while (ptr->format != '\0') {
if (ptr->format == native->format) {
while (ptr->format != NULL) {
if (strcmp(ptr->format, native->format) == 0) {
/* Match faster when formats are
listed in the same order */
if (ptr == other)
@ -1536,8 +1542,9 @@ init_endian_tables(void *Py_UNUSED(arg))
if (ptr->size != native->size)
break;
/* Skip _Bool, semantics are different for standard size */
if (ptr->format == '?')
if (strcmp(ptr->format, "?") == 0) {
break;
}
ptr->pack = native->pack;
ptr->unpack = native->unpack;
break;
@ -1576,13 +1583,28 @@ whichtable(const char **pfmt)
}
static int
format_equal(const formatdef *e, const char *s)
{
const char *format = e->format;
size_t i = 0;
while (format[i] == s[i]) {
i++;
if (format[i] == 0) {
return 1;
}
}
return 0;
}
/* Get the table entry for a format code */
static const formatdef *
getentry(_structmodulestate *state, int c, const formatdef *f)
getentry(_structmodulestate *state, const char *s, const formatdef *f)
{
for (; f->format != '\0'; f++) {
if (f->format == c) {
for (; f->format != NULL; f++) {
if (format_equal(f, s)) {
return f;
}
}
@ -1594,11 +1616,11 @@ getentry(_structmodulestate *state, int c, const formatdef *f)
/* Align a size according to a format code. Return -1 on overflow. */
static Py_ssize_t
align(Py_ssize_t size, char c, const formatdef *e)
align(Py_ssize_t size, const char *s, const formatdef *e)
{
Py_ssize_t extra;
if (e->format == c) {
if (format_equal(e, s)) {
if (e->alignment && size > 0) {
extra = (e->alignment - 1) - (size - 1) % (e->alignment);
if (extra > PY_SSIZE_T_MAX - size)
@ -1670,7 +1692,8 @@ prepare_s(PyStructObject *self, PyObject *format)
else
num = 1;
e = getentry(state, c, f);
s--;
e = getentry(state, s, f);
if (e == NULL)
return -1;
@ -1696,9 +1719,10 @@ prepare_s(PyStructObject *self, PyObject *format)
}
itemsize = e->size;
size = align(size, c, e);
size = align(size, s, e);
if (size == -1)
goto overflow;
s += strlen(e->format);
/* if (size + num * itemsize > PY_SSIZE_T_MAX) { ... } */
if (num > (PY_SSIZE_T_MAX - size) / itemsize)
@ -1731,9 +1755,11 @@ prepare_s(PyStructObject *self, PyObject *format)
else
num = 1;
e = getentry(state, c, f);
s--;
e = getentry(state, s, f);
size = align(size, s, e);
s += strlen(e->format);
size = align(size, c, e);
if (c == 's' || c == 'p') {
codes->offset = size;
codes->size = num;
@ -2024,9 +2050,9 @@ s_unpack_internal(PyStructObject *soself, const char *startfrom,
Py_ssize_t j = code->repeat;
while (j--) {
PyObject *v;
if (e->format == 's') {
if (strcmp(e->format, "s") == 0) {
v = PyBytes_FromStringAndSize(res, code->size);
} else if (e->format == 'p') {
} else if (strcmp(e->format, "p") == 0) {
Py_ssize_t n;
if (code->size == 0) {
n = 0;
@ -2319,7 +2345,7 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args,
Py_ssize_t j = code->repeat;
while (j--) {
PyObject *v = args[i++];
if (e->format == 's') {
if (strcmp(e->format, "s") == 0) {
Py_ssize_t n;
int isstring;
const void *p;
@ -2341,7 +2367,7 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args,
n = code->size;
if (n > 0)
memcpy(res, p, n);
} else if (e->format == 'p') {
} else if (strcmp(e->format, "p") == 0) {
Py_ssize_t n;
int isstring;
const void *p;

View file

@ -33,12 +33,11 @@ static struct PyModuleDef arraymodule;
* functions aren't visible yet.
*/
struct arraydescr {
char typecode;
const char *typecode;
int itemsize;
PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
int (*compareitems)(const void *, const void *, Py_ssize_t);
const char *formats;
int is_integer_type;
int is_signed;
};
@ -768,24 +767,26 @@ DEFINE_COMPAREITEMS(QQ, unsigned long long)
* typecode.
*/
static const struct arraydescr descriptors[] = {
{'b', 1, b_getitem, b_setitem, b_compareitems, "b", 1, 1},
{'B', 1, BB_getitem, BB_setitem, BB_compareitems, "B", 1, 0},
{'u', sizeof(wchar_t), u_getitem, u_setitem, u_compareitems, "u", 0, 0},
{'w', sizeof(Py_UCS4), w_getitem, w_setitem, w_compareitems, "w", 0, 0,},
{'h', sizeof(short), h_getitem, h_setitem, h_compareitems, "h", 1, 1},
{'H', sizeof(short), HH_getitem, HH_setitem, HH_compareitems, "H", 1, 0},
{'i', sizeof(int), i_getitem, i_setitem, i_compareitems, "i", 1, 1},
{'I', sizeof(int), II_getitem, II_setitem, II_compareitems, "I", 1, 0},
{'l', sizeof(long), l_getitem, l_setitem, l_compareitems, "l", 1, 1},
{'L', sizeof(long), LL_getitem, LL_setitem, LL_compareitems, "L", 1, 0},
{'q', sizeof(long long), q_getitem, q_setitem, q_compareitems, "q", 1, 1},
{'Q', sizeof(long long), QQ_getitem, QQ_setitem, QQ_compareitems, "Q", 1, 0},
{'e', sizeof(short), e_getitem, e_setitem, NULL, "e", 0, 0},
{'f', sizeof(float), f_getitem, f_setitem, NULL, "f", 0, 0},
{'d', sizeof(double), d_getitem, d_setitem, NULL, "d", 0, 0},
{'F', 2*sizeof(float), cf_getitem, cf_setitem, NULL, "F", 0, 0},
{'D', 2*sizeof(double), cd_getitem, cd_setitem, NULL, "D", 0, 0},
{'\0', 0, 0, 0, 0, 0, 0} /* Sentinel */
{"b", 1, b_getitem, b_setitem, b_compareitems, 1, 1},
{"B", 1, BB_getitem, BB_setitem, BB_compareitems, 1, 0},
{"u", sizeof(wchar_t), u_getitem, u_setitem, u_compareitems, 0, 0},
{"w", sizeof(Py_UCS4), w_getitem, w_setitem, w_compareitems, 0, 0,},
{"h", sizeof(short), h_getitem, h_setitem, h_compareitems, 1, 1},
{"H", sizeof(short), HH_getitem, HH_setitem, HH_compareitems, 1, 0},
{"i", sizeof(int), i_getitem, i_setitem, i_compareitems, 1, 1},
{"I", sizeof(int), II_getitem, II_setitem, II_compareitems, 1, 0},
{"l", sizeof(long), l_getitem, l_setitem, l_compareitems, 1, 1},
{"L", sizeof(long), LL_getitem, LL_setitem, LL_compareitems, 1, 0},
{"q", sizeof(long long), q_getitem, q_setitem, q_compareitems, 1, 1},
{"Q", sizeof(long long), QQ_getitem, QQ_setitem, QQ_compareitems, 1, 0},
{"e", sizeof(short), e_getitem, e_setitem, NULL, 0, 0},
{"f", sizeof(float), f_getitem, f_setitem, NULL, 0, 0},
{"d", sizeof(double), d_getitem, d_setitem, NULL, 0, 0},
{"F", 2*sizeof(float), cf_getitem, cf_setitem, NULL, 0, 0},
{"D", 2*sizeof(double), cd_getitem, cd_setitem, NULL, 0, 0},
{"Zf", 2*sizeof(float), cf_getitem, cf_setitem, NULL, 0, 0},
{"Zd", 2*sizeof(double), cd_getitem, cd_setitem, NULL, 0, 0},
{NULL, 0, 0, 0, 0, 0, 0} /* Sentinel */
};
/****************************************************************************
@ -1611,7 +1612,9 @@ array_array_byteswap_impl(arrayobject *self)
}
break;
case 8:
if (self->ob_descr->typecode != 'F') {
if (strcmp(self->ob_descr->typecode, "F") != 0
&& strcmp(self->ob_descr->typecode, "Zf") != 0)
{
for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 8) {
char p0 = p[0];
char p1 = p[1];
@ -1645,7 +1648,8 @@ array_array_byteswap_impl(arrayobject *self)
}
break;
case 16:
assert(self->ob_descr->typecode == 'D');
assert(strcmp(self->ob_descr->typecode, "D") == 0
|| strcmp(self->ob_descr->typecode, "Zd") == 0);
for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 8) {
char t0 = p[0];
char t1 = p[1];
@ -1985,15 +1989,15 @@ static PyObject *
array_array_fromunicode_impl(arrayobject *self, PyObject *ustr)
/*[clinic end generated code: output=24359f5e001a7f2b input=158d47c302f27ca1]*/
{
int typecode = self->ob_descr->typecode;
if (typecode != 'u' && typecode != 'w') {
const char *typecode = self->ob_descr->typecode;
if (strcmp(typecode, "u") != 0 && strcmp(typecode, "w") != 0) {
PyErr_SetString(PyExc_ValueError,
"fromunicode() may only be called on "
"unicode type arrays ('u' or 'w')");
return NULL;
}
if (typecode == 'u') {
if (strcmp(typecode, "u") == 0) {
Py_ssize_t ustr_length = PyUnicode_AsWideChar(ustr, NULL, 0);
assert(ustr_length > 0);
if (ustr_length > 1) {
@ -2008,7 +2012,7 @@ array_array_fromunicode_impl(arrayobject *self, PyObject *ustr)
ustr, ((wchar_t *)self->ob_item) + old_size, ustr_length);
}
}
else { // typecode == 'w'
else { // typecode == "w"
Py_ssize_t ustr_length = PyUnicode_GetLength(ustr);
Py_ssize_t old_size = Py_SIZE(self);
Py_ssize_t new_size = old_size + ustr_length;
@ -2045,16 +2049,16 @@ static PyObject *
array_array_tounicode_impl(arrayobject *self)
/*[clinic end generated code: output=08e442378336e1ef input=6690997213d219db]*/
{
int typecode = self->ob_descr->typecode;
if (typecode != 'u' && typecode != 'w') {
const char *typecode = self->ob_descr->typecode;
if (strcmp(typecode, "u") != 0 && strcmp(typecode, "w") != 0) {
PyErr_SetString(PyExc_ValueError,
"tounicode() may only be called on unicode type arrays ('u' or 'w')");
return NULL;
}
if (typecode == 'u') {
if (strcmp(typecode, "u") == 0) {
return PyUnicode_FromWideChar((wchar_t *) self->ob_item, Py_SIZE(self));
}
else { // typecode == 'w'
else { // typecode == "w"
int byteorder = 0; // native byteorder
return PyUnicode_DecodeUTF32((const char *) self->ob_item, Py_SIZE(self) * 4,
NULL, &byteorder);
@ -2121,14 +2125,14 @@ static const struct mformatdescr {
* be found.
*/
static enum machine_format_code
typecode_to_mformat_code(char typecode)
typecode_to_mformat_code(const char *typecode)
{
const int is_big_endian = PY_BIG_ENDIAN;
size_t intsize;
int is_signed;
switch (typecode) {
switch (typecode[0]) {
case 'b':
return SIGNED_INT8;
case 'B':
@ -2163,6 +2167,21 @@ typecode_to_mformat_code(char typecode)
return _PY_FLOAT_BIG_ENDIAN ? \
IEEE_754_DOUBLE_COMPLEX_BE : IEEE_754_DOUBLE_COMPLEX_LE;
case 'Z': {
switch (typecode[1]) {
case 'f':
return _PY_FLOAT_BIG_ENDIAN ? \
IEEE_754_FLOAT_COMPLEX_BE : IEEE_754_FLOAT_COMPLEX_LE;
case 'd':
return _PY_FLOAT_BIG_ENDIAN ? \
IEEE_754_DOUBLE_COMPLEX_BE : IEEE_754_DOUBLE_COMPLEX_LE;
default:
return UNKNOWN_FORMAT;
}
}
/* Integers */
case 'h':
intsize = sizeof(short);
@ -2218,7 +2237,7 @@ static PyObject *array_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
* Internal: This function wraps the array constructor--i.e., array_new()--to
* allow the creation of array objects from C code without having to deal
* directly the tuple argument of array_new(). The typecode argument is a
* Unicode character value, like 'i' or 'f' for example, representing an array
* string, like "i" or "f" for example, representing an array
* type code. The items argument is a bytes or a list object from which
* contains the initial value of the array.
*
@ -2226,7 +2245,7 @@ static PyObject *array_new(PyTypeObject *type, PyObject *args, PyObject *kwds);
* NULL is returned to indicate a failure.
*/
static PyObject *
make_array(PyTypeObject *arraytype, char typecode, PyObject *items)
make_array(PyTypeObject *arraytype, const char *typecode, PyObject *items)
{
PyObject *new_args;
PyObject *array_obj;
@ -2235,7 +2254,7 @@ make_array(PyTypeObject *arraytype, char typecode, PyObject *items)
assert(arraytype != NULL);
assert(items != NULL);
typecode_obj = PyUnicode_FromOrdinal(typecode);
typecode_obj = PyUnicode_FromString(typecode);
if (typecode_obj == NULL)
return NULL;
@ -2260,7 +2279,7 @@ make_array(PyTypeObject *arraytype, char typecode, PyObject *items)
array._array_reconstructor
arraytype: object(type="PyTypeObject *")
typecode: int(accept={str})
typecode: str
mformat_code: int(type="enum machine_format_code")
items: object
/
@ -2270,10 +2289,10 @@ Internal. Used for pickling support.
static PyObject *
array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype,
int typecode,
const char *typecode,
enum machine_format_code mformat_code,
PyObject *items)
/*[clinic end generated code: output=e05263141ba28365 input=2464dc8f4c7736b5]*/
/*[clinic end generated code: output=723e3813e0a18b7b input=9f1c331baae742a6]*/
{
array_state *state = get_array_state(module);
PyObject *converted_items;
@ -2292,11 +2311,12 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype,
arraytype->tp_name, state->ArrayType->tp_name);
return NULL;
}
for (descr = descriptors; descr->typecode != '\0'; descr++) {
if ((int)descr->typecode == typecode)
for (descr = descriptors; descr->typecode != NULL; descr++) {
if (strcmp(descr->typecode, typecode) == 0) {
break;
}
}
if (descr->typecode == '\0') {
if (descr->typecode == NULL) {
PyErr_SetString(PyExc_ValueError,
"second argument must be a valid type code");
return NULL;
@ -2315,9 +2335,9 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype,
}
/* Fast path: No decoding has to be done. */
if (mformat_code == typecode_to_mformat_code((char)typecode) ||
if (mformat_code == typecode_to_mformat_code(typecode) ||
mformat_code == UNKNOWN_FORMAT) {
return make_array(arraytype, (char)typecode, items);
return make_array(arraytype, typecode, items);
}
/* Slow path: Decode the byte string according to the given machine
@ -2493,11 +2513,13 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype,
*
* XXX: Is it possible to write a unit test for this?
*/
for (descr = descriptors; descr->typecode != '\0'; descr++) {
for (descr = descriptors; descr->typecode != NULL; descr++) {
if (descr->is_integer_type &&
(size_t)descr->itemsize == mf_descr.size &&
descr->is_signed == mf_descr.is_signed)
{
typecode = descr->typecode;
}
}
converted_items = PyList_New(itemcount);
@ -2528,7 +2550,7 @@ array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype,
return NULL;
}
result = make_array(arraytype, (char)typecode, converted_items);
result = make_array(arraytype, typecode, converted_items);
Py_DECREF(converted_items);
return result;
}
@ -2551,7 +2573,7 @@ array_array___reduce_ex___impl(arrayobject *self, PyTypeObject *cls,
PyObject *dict;
PyObject *result;
PyObject *array_str;
int typecode = self->ob_descr->typecode;
const char *typecode = self->ob_descr->typecode;
int mformat_code;
long protocol;
@ -2602,7 +2624,7 @@ array_array___reduce_ex___impl(arrayobject *self, PyTypeObject *cls,
return NULL;
}
result = Py_BuildValue(
"O(CO)O", Py_TYPE(self), typecode, list, dict);
"O(sO)O", Py_TYPE(self), typecode, list, dict);
Py_DECREF(list);
Py_DECREF(dict);
return result;
@ -2616,7 +2638,7 @@ array_array___reduce_ex___impl(arrayobject *self, PyTypeObject *cls,
assert(state->array_reconstructor != NULL);
result = Py_BuildValue(
"O(OCiN)O", state->array_reconstructor, Py_TYPE(self), typecode,
"O(OsiN)O", state->array_reconstructor, Py_TYPE(self), typecode,
mformat_code, array_str, dict);
Py_DECREF(dict);
return result;
@ -2626,8 +2648,8 @@ static PyObject *
array_get_typecode(PyObject *op, void *Py_UNUSED(closure))
{
arrayobject *a = arrayobject_CAST(op);
char typecode = a->ob_descr->typecode;
return PyUnicode_FromOrdinal(typecode);
const char *typecode = a->ob_descr->typecode;
return PyUnicode_FromString(typecode);
}
static PyObject *
@ -2676,7 +2698,7 @@ static PyMethodDef array_methods[] = {
static PyObject *
array_repr(PyObject *op)
{
char typecode;
const char *typecode;
PyObject *s, *v = NULL;
Py_ssize_t len;
arrayobject *a = arrayobject_CAST(op);
@ -2684,10 +2706,10 @@ array_repr(PyObject *op)
len = Py_SIZE(a);
typecode = a->ob_descr->typecode;
if (len == 0) {
return PyUnicode_FromFormat("%s('%c')",
_PyType_Name(Py_TYPE(a)), (int)typecode);
return PyUnicode_FromFormat("%s('%s')",
_PyType_Name(Py_TYPE(a)), typecode);
}
if (typecode == 'u' || typecode == 'w') {
if (strcmp(typecode, "u") == 0 || strcmp(typecode, "w") == 0) {
v = array_array_tounicode_impl(a);
} else {
v = array_array_tolist_impl(a);
@ -2695,8 +2717,8 @@ array_repr(PyObject *op)
if (v == NULL)
return NULL;
s = PyUnicode_FromFormat("%s('%c', %R)",
_PyType_Name(Py_TYPE(a)), (int)typecode, v);
s = PyUnicode_FromFormat("%s('%s', %R)",
_PyType_Name(Py_TYPE(a)), typecode, v);
Py_DECREF(v);
return s;
}
@ -2956,8 +2978,8 @@ array_buffer_getbuf(PyObject *op, Py_buffer *view, int flags)
view->format = NULL;
view->internal = NULL;
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
view->format = (char *)self->ob_descr->formats;
if (sizeof(wchar_t) >= 4 && self->ob_descr->typecode == 'u') {
view->format = (char *)self->ob_descr->typecode;
if (sizeof(wchar_t) >= 4 && strcmp(self->ob_descr->typecode, "u") == 0) {
view->format = "w";
}
}
@ -2977,7 +2999,7 @@ static PyObject *
array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
array_state *state = find_array_state_by_type(type);
int c;
const char *s;
PyObject *initial = NULL, *it = NULL;
const struct arraydescr *descr;
@ -2986,15 +3008,15 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
!_PyArg_NoKeywords("array.array", kwds))
return NULL;
if (!PyArg_ParseTuple(args, "C|O:array", &c, &initial))
if (!PyArg_ParseTuple(args, "s|O:array", &s, &initial))
return NULL;
if (PySys_Audit("array.__new__", "CO",
c, initial ? initial : Py_None) < 0) {
if (PySys_Audit("array.__new__", "sO",
s, initial ? initial : Py_None) < 0) {
return NULL;
}
if (c == 'u') {
if (strcmp(s, "u") == 0) {
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"The 'u' type code is deprecated and "
"will be removed in Python 3.16",
@ -3003,19 +3025,19 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
}
bool is_unicode = c == 'u' || c == 'w';
bool is_unicode = (strcmp(s, "u") == 0 || strcmp(s, "w") == 0);
if (initial && !is_unicode) {
if (PyUnicode_Check(initial)) {
PyErr_Format(PyExc_TypeError, "cannot use a str to initialize "
"an array with typecode '%c'", c);
"an array with typecode '%s'", s);
return NULL;
}
else if (array_Check(initial, state)) {
int ic = ((arrayobject*)initial)->ob_descr->typecode;
if (ic == 'u' || ic == 'w') {
const char *is = ((arrayobject*)initial)->ob_descr->typecode;
if (strcmp(is, "u") == 0 || strcmp(is, "w") == 0) {
PyErr_Format(PyExc_TypeError, "cannot use a unicode array to "
"initialize an array with typecode '%c'", c);
"initialize an array with typecode '%s'", s);
return NULL;
}
}
@ -3027,7 +3049,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|| PyTuple_Check(initial)
|| (is_unicode && PyUnicode_Check(initial))
|| (array_Check(initial, state)
&& c == ((arrayobject*)initial)->ob_descr->typecode))) {
&& strcmp(s, ((arrayobject*)initial)->ob_descr->typecode) == 0))) {
it = PyObject_GetIter(initial);
if (it == NULL)
return NULL;
@ -3038,8 +3060,8 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
*/
initial = NULL;
}
for (descr = descriptors; descr->typecode != '\0'; descr++) {
if (descr->typecode == c) {
for (descr = descriptors; descr->typecode != NULL; descr++) {
if (strcmp(descr->typecode, s) == 0) {
PyObject *a;
Py_ssize_t len;
@ -3089,7 +3111,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_DECREF(v);
}
else if (initial != NULL && PyUnicode_Check(initial)) {
if (c == 'u') {
if (strcmp(s, "u") == 0) {
Py_ssize_t n;
wchar_t *ustr = PyUnicode_AsWideCharString(initial, &n);
if (ustr == NULL) {
@ -3110,7 +3132,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
PyMem_Free(ustr);
}
}
else { // c == 'w'
else { // s == "w"
Py_ssize_t n = PyUnicode_GET_LENGTH(initial);
Py_UCS4 *ustr = PyUnicode_AsUCS4Copy(initial);
if (ustr == NULL) {
@ -3145,7 +3167,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
Py_XDECREF(it);
PyErr_SetString(PyExc_ValueError,
"bad typecode (must be b, B, u, w, h, H, i, I, l, L, q, Q, f or d)");
"bad typecode (must be b, B, u, w, h, H, i, I, l, L, q, Q, f, d, F, D, Zd or Zf)");
return NULL;
}
@ -3165,7 +3187,7 @@ string or iterable over elements of the appropriate type.\n\
\n\
Arrays represent basic values and behave very much like lists, except\n\
the type of objects stored in them is constrained. The type is specified\n\
at object creation time by using a type code, which is a single character.\n\
at object creation time by using a type code, which is a string.\n\
The following type codes are defined:\n\
\n\
Type code C Type Minimum size in bytes\n\
@ -3185,6 +3207,8 @@ The following type codes are defined:\n\
'd' floating-point 8\n\
'F' float complex 8\n\
'D' double complex 16\n\
'Zf' float complex 8\n\
'Zd' double complex 16\n\
\n\
NOTE: The 'u' typecode corresponds to Python's unicode character. On\n\
narrow builds this is 2-bytes on wide builds this is 4-bytes.\n\
@ -3480,7 +3504,6 @@ static int
array_modexec(PyObject *m)
{
array_state *state = get_array_state(m);
char buffer[Py_ARRAY_LENGTH(descriptors)], *p;
PyObject *typecodes;
const struct arraydescr *descr;
@ -3519,12 +3542,29 @@ array_modexec(PyObject *m)
return -1;
}
p = buffer;
for (descr = descriptors; descr->typecode != '\0'; descr++) {
*p++ = (char)descr->typecode;
typecodes = PyList_New(0);
if (typecodes == NULL) {
return -1;
}
typecodes = PyUnicode_DecodeASCII(buffer, p - buffer, NULL);
if (PyModule_Add(m, "typecodes", typecodes) < 0) {
for (descr = descriptors; descr->typecode != NULL; descr++) {
PyObject *typecode = PyUnicode_DecodeASCII(descr->typecode, strlen(descr->typecode), NULL);
if (typecode == NULL) {
Py_DECREF(typecodes);
return -1;
}
int res = PyList_Append(typecodes, typecode);
Py_DECREF(typecode);
if (res < 0) {
Py_DECREF(typecodes);
return -1;
}
}
PyObject *tuple = PyList_AsTuple(typecodes);
Py_DECREF(typecodes);
if (tuple == NULL) {
return -1;
}
if (PyModule_Add(m, "typecodes", tuple) < 0) {
return -1;
}

View file

@ -651,7 +651,7 @@ PyDoc_STRVAR(array__array_reconstructor__doc__,
static PyObject *
array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype,
int typecode,
const char *typecode,
enum machine_format_code mformat_code,
PyObject *items);
@ -660,7 +660,7 @@ array__array_reconstructor(PyObject *module, PyObject *const *args, Py_ssize_t n
{
PyObject *return_value = NULL;
PyTypeObject *arraytype;
int typecode;
const char *typecode;
enum machine_format_code mformat_code;
PyObject *items;
@ -669,17 +669,18 @@ array__array_reconstructor(PyObject *module, PyObject *const *args, Py_ssize_t n
}
arraytype = (PyTypeObject *)args[0];
if (!PyUnicode_Check(args[1])) {
_PyArg_BadArgument("_array_reconstructor", "argument 2", "a unicode character", args[1]);
_PyArg_BadArgument("_array_reconstructor", "argument 2", "str", args[1]);
goto exit;
}
if (PyUnicode_GET_LENGTH(args[1]) != 1) {
PyErr_Format(PyExc_TypeError,
"_array_reconstructor(): argument 2 must be a unicode character, "
"not a string of length %zd",
PyUnicode_GET_LENGTH(args[1]));
Py_ssize_t typecode_length;
typecode = PyUnicode_AsUTF8AndSize(args[1], &typecode_length);
if (typecode == NULL) {
goto exit;
}
if (strlen(typecode) != (size_t)typecode_length) {
PyErr_SetString(PyExc_ValueError, "embedded null character");
goto exit;
}
typecode = PyUnicode_READ_CHAR(args[1], 0);
mformat_code = PyLong_AsInt(args[2]);
if (mformat_code == -1 && PyErr_Occurred()) {
goto exit;
@ -779,4 +780,4 @@ array_arrayiterator___setstate__(PyObject *self, PyObject *state)
return return_value;
}
/*[clinic end generated code: output=9dcb2fc40710f83d input=a9049054013a1b77]*/
/*[clinic end generated code: output=8699475b51151247 input=a9049054013a1b77]*/

View file

@ -1197,10 +1197,11 @@ memory_exit(PyObject *self, PyObject *args)
/* Casting format and shape */
/****************************************************************************/
#define IS_BYTE_FORMAT(f) (f == 'b' || f == 'B' || f == 'c')
#define IS_BYTE_FORMAT(f) \
(strcmp(f, "b") == 0 || strcmp(f, "B") == 0 || strcmp(f, "c") == 0)
static inline Py_ssize_t
get_native_fmtchar(char *result, const char *fmt)
get_native_fmtchar(const char **result, const char *fmt)
{
Py_ssize_t size = -1;
@ -1220,10 +1221,21 @@ get_native_fmtchar(char *result, const char *fmt)
case 'D': size = 2*sizeof(double); break;
case '?': size = sizeof(_Bool); break;
case 'P': size = sizeof(void *); break;
case 'Z': {
switch (fmt[1]) {
case 'f': size = 2*sizeof(float); break;
case 'd': size = 2*sizeof(double); break;
}
if (size > 0 && fmt[2] == '\0') {
*result = fmt;
return size;
}
break;
}
}
if (size > 0 && fmt[1] == '\0') {
*result = fmt[0];
*result = fmt;
return size;
}
@ -1239,9 +1251,19 @@ get_native_fmtstr(const char *fmt)
at = 1;
fmt++;
}
if (fmt[0] == '\0' || fmt[1] != '\0') {
if (fmt[0] == '\0') {
return NULL;
}
if (fmt[0] == 'Z') {
if (fmt[2] != '\0') {
return NULL;
}
}
else {
if (fmt[1] != '\0') {
return NULL;
}
}
#define RETURN(s) do { return at ? "@" s : s; } while (0)
@ -1264,6 +1286,13 @@ get_native_fmtstr(const char *fmt)
case 'e': RETURN("e");
case 'F': RETURN("F");
case 'D': RETURN("D");
case 'Z': {
switch (fmt[1]) {
case 'f': RETURN("Zf");
case 'd': RETURN("Zd");
}
break;
}
case '?': RETURN("?");
case 'P': RETURN("P");
}
@ -1281,7 +1310,7 @@ cast_to_1D(PyMemoryViewObject *mv, PyObject *format)
{
Py_buffer *view = &mv->view;
PyObject *asciifmt;
char srcchar, destchar;
const char *srcfmt, *destfmt;
Py_ssize_t itemsize;
int ret = -1;
@ -1295,7 +1324,7 @@ cast_to_1D(PyMemoryViewObject *mv, PyObject *format)
if (asciifmt == NULL)
return ret;
itemsize = get_native_fmtchar(&destchar, PyBytes_AS_STRING(asciifmt));
itemsize = get_native_fmtchar(&destfmt, PyBytes_AS_STRING(asciifmt));
if (itemsize < 0) {
PyErr_SetString(PyExc_ValueError,
"memoryview: destination format must be a native single "
@ -1303,8 +1332,8 @@ cast_to_1D(PyMemoryViewObject *mv, PyObject *format)
goto out;
}
if ((get_native_fmtchar(&srcchar, view->format) < 0 ||
!IS_BYTE_FORMAT(srcchar)) && !IS_BYTE_FORMAT(destchar)) {
if ((get_native_fmtchar(&srcfmt, view->format) < 0 ||
!IS_BYTE_FORMAT(srcfmt)) && !IS_BYTE_FORMAT(destfmt)) {
PyErr_SetString(PyExc_TypeError,
"memoryview: cannot cast between two non-byte formats");
goto out;
@ -1846,6 +1875,23 @@ unpack_single(PyMemoryViewObject *self, const char *ptr, const char *fmt)
d[1] = PyFloat_Unpack8(ptr + sizeof(double), endian);
goto convert_double_complex;
case 'Z': {
switch (fmt[1]) {
case 'f':
d[0] = PyFloat_Unpack4(ptr, endian);
d[1] = PyFloat_Unpack4(ptr + sizeof(float), endian);
goto convert_double_complex;
case 'd':
d[0] = PyFloat_Unpack8(ptr, endian);
d[1] = PyFloat_Unpack8(ptr + sizeof(double), endian);
goto convert_double_complex;
default: goto err_format;
}
break;
}
/* bytes object */
case 'c': goto convert_bytes;
@ -2027,6 +2073,31 @@ pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt
}
break;
case 'Z': {
switch (fmt[1]) {
case 'f': case 'd':
c = PyComplex_AsCComplex(item);
if (c.real == -1.0 && PyErr_Occurred()) {
goto err_occurred;
}
CHECK_RELEASED_INT_AGAIN(self);
if (fmt[1] == 'd') {
double x[2] = {c.real, c.imag};
memcpy(ptr, &x, sizeof(x));
}
else {
float x[2] = {(float)c.real, (float)c.imag};
memcpy(ptr, &x, sizeof(x));
}
break;
default: goto err_format;
}
break;
}
/* bool */
case '?':
ld = PyObject_IsTrue(item);
@ -2200,6 +2271,8 @@ adjust_fmt(const Py_buffer *view)
const char *fmt;
fmt = (view->format[0] == '@') ? view->format+1 : view->format;
if (fmt[0] == 'Z' && fmt[1] && fmt[2] == '\0')
return fmt;
if (fmt[0] && fmt[1] == '\0')
return fmt;
@ -3018,12 +3091,12 @@ struct_unpack_cmp(const char *p, const char *q,
} while (0)
static inline int
unpack_cmp(const char *p, const char *q, char fmt,
unpack_cmp(const char *p, const char *q, const char *fmt,
struct unpacker *unpack_p, struct unpacker *unpack_q)
{
int equal;
switch (fmt) {
switch (fmt[0]) {
/* signed integers and fast path for 'B' */
case 'B': return *((const unsigned char *)p) == *((const unsigned char *)q);
@ -3081,6 +3154,27 @@ unpack_cmp(const char *p, const char *q, char fmt,
memcpy(&y, q, sizeof(y));
return (x[0] == y[0]) && (x[1] == y[1]);
}
case 'Z': {
switch (fmt[1]) {
case 'f':
{
float x[2], y[2];
memcpy(&x, p, sizeof(x));
memcpy(&y, q, sizeof(y));
return (x[0] == y[0]) && (x[1] == y[1]);
}
case 'd':
{
double x[2], y[2];
memcpy(&x, p, sizeof(x));
memcpy(&y, q, sizeof(y));
return (x[0] == y[0]) && (x[1] == y[1]);
}
}
break;
}
/* bytes object */
case 'c': return *p == *q;
@ -3106,7 +3200,7 @@ static int
cmp_base(const char *p, const char *q, const Py_ssize_t *shape,
const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
const char *fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
{
Py_ssize_t i;
int equal;
@ -3129,7 +3223,7 @@ cmp_rec(const char *p, const char *q,
Py_ssize_t ndim, const Py_ssize_t *shape,
const Py_ssize_t *pstrides, const Py_ssize_t *psuboffsets,
const Py_ssize_t *qstrides, const Py_ssize_t *qsuboffsets,
char fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
const char *fmt, struct unpacker *unpack_p, struct unpacker *unpack_q)
{
Py_ssize_t i;
int equal;
@ -3168,7 +3262,7 @@ memory_richcompare(PyObject *v, PyObject *w, int op)
Py_buffer *ww = NULL;
struct unpacker *unpack_v = NULL;
struct unpacker *unpack_w = NULL;
char vfmt, wfmt;
const char *vfmt, *wfmt;
int equal = MV_COMPARE_NOT_IMPL;
if (op != Py_EQ && op != Py_NE)
@ -3228,15 +3322,15 @@ memory_richcompare(PyObject *v, PyObject *w, int op)
/* Use fast unpacking for identical primitive C type formats. */
if (get_native_fmtchar(&vfmt, vv->format) < 0)
vfmt = '_';
vfmt = "_";
if (get_native_fmtchar(&wfmt, ww->format) < 0)
wfmt = '_';
if (vfmt == '_' || wfmt == '_' || vfmt != wfmt) {
wfmt = "_";
if (strcmp(vfmt, "_") == 0 || strcmp(wfmt, "_") == 0 || strcmp(vfmt, wfmt) != 0) {
/* Use struct module unpacking. NOTE: Even for equal format strings,
memcmp() cannot be used for item comparison since it would give
incorrect results in the case of NaNs or uninitialized padding
bytes. */
vfmt = '_';
vfmt = "_";
unpack_v = struct_get_unpacker(vv->format, vv->itemsize);
if (unpack_v == NULL) {
equal = fix_struct_error_int();
@ -3299,7 +3393,7 @@ memory_hash(PyObject *_self)
Py_buffer *view = &self->view;
char *mem = view->buf;
Py_ssize_t ret;
char fmt;
const char *fmt;
CHECK_RELEASED_INT(self);