mirror of
https://github.com/python/cpython.git
synced 2026-05-04 09:31:02 +00:00
Merge c7840fa770 into 2e94f14310
This commit is contained in:
commit
379d06ccfa
22 changed files with 616 additions and 331 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
--------
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
21
Modules/clinic/arraymodule.c.h
generated
21
Modules/clinic/arraymodule.c.h
generated
|
|
@ -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]*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue