* Add Zd/Zf format support to array, memoryview and struct.
* ctypes: Replace F/D/G complex format with Zf/Zd/Zg.
* Modify array, ctypes and struct modules to support format strings
longer than 1 character (such as "Zd").
* Change array.typecodes type from str to tuple.
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'D'`` | double complex | complex | 16 | \(4) |
+-----------+--------------------+-------------------+-----------------------+-------+
+| ``'Zf'`` | float complex | complex | 8 | \(4) |
++-----------+--------------------+-------------------+-----------------------+-------+
+| ``'Zd'`` | double complex | complex | 16 | \(4) |
++-----------+--------------------+-------------------+-----------------------+-------+
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
.. 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:
* - :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
+--------+--------------------------+--------------------+----------------+------------+
| ``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) |
.. 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,
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.
(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 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`.)
-----
* 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'``/``'Zf'`` and ``'D'``/``'Zd'`` respectively.
+ (Contributed by 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
---
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
--------
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
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):
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):
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.
#
[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
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):
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:
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'
'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':
'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):
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):
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)
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)]
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)
# ======================================================================
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)
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
@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)
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):
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)
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.
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)
--- /dev/null
+:mod:`array`, :mod:`struct`: Add support for ``Zd`` and ``Zf`` formats for
+double complex and float complex. Patch by Victor Stinner.
--- /dev/null
+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.
--- /dev/null
+: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.
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 */
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;
}
{
PyObject *proto;
const char *proto_str;
- Py_ssize_t proto_len;
PyMethodDef *ml;
struct fielddesc *fmt;
return -1;
}
if (PyUnicode_Check(proto)) {
- proto_str = PyUnicode_AsUTF8AndSize(proto, &proto_len);
+ proto_str = PyUnicode_AsUTF8(proto);
if (!proto_str)
goto error;
} else {
"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"
+ "one of these characters: '%s',\n"
+ "or one of these strings: %s.",
+ _ctypes_get_simple_type_chars(),
+ complex_formats);
+ }
+ else {
+ PyErr_Format(PyExc_AttributeError,
+ "class must define a '_type_' attribute which must be\n"
+ "one of these characters: '%s'.\n",
+ _ctypes_get_simple_type_chars());
+ }
goto error;
}
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);
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;
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 {
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);
}
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];
}
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);
}
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
#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);
}
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];
}
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);
}
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
#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);
}
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];
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 *
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;
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;
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;
// 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;
(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
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`,
#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) \
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);
// 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:
+ 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';
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';
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;
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;
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) {
return NULL;
}
+ if (fmt[1] != '\0') {
+ if (fmt[0] == 'Z') {
+ if (fmt[2] != '\0') {
+ return NULL;
+ }
+ }
+ else {
+ return NULL;
+ }
+ }
assert(result->pffi_type);
assert(result->setfunc);
assert(result->getfunc);
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;
};
// 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
/* 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 *,
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);
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);
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);
}
}
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}
};
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);
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;
}
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}
};
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);
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;
}
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}
};
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)
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;
}
+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;
}
}
/* 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)
else
num = 1;
- e = getentry(state, c, f);
+ s--;
+ e = getentry(state, s, f);
if (e == NULL)
return -1;
}
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)
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;
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;
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;
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;
* 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;
};
* 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 */
};
/****************************************************************************
}
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];
}
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];
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) {
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;
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);
* 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':
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);
* 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.
*
* 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;
assert(arraytype != NULL);
assert(items != NULL);
- typecode_obj = PyUnicode_FromOrdinal(typecode);
+ typecode_obj = PyUnicode_FromString(typecode);
if (typecode_obj == NULL)
return NULL;
array._array_reconstructor
arraytype: object(type="PyTypeObject *")
- typecode: int(accept={str})
+ typecode: str
mformat_code: int(type="enum machine_format_code")
items: object
/
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;
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;
}
/* 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
*
* 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);
return NULL;
}
- result = make_array(arraytype, (char)typecode, converted_items);
+ result = make_array(arraytype, typecode, converted_items);
Py_DECREF(converted_items);
return result;
}
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;
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;
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;
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 *
static PyObject *
array_repr(PyObject *op)
{
- char typecode;
+ const char *typecode;
PyObject *s, *v = NULL;
Py_ssize_t len;
arrayobject *a = arrayobject_CAST(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);
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;
}
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";
}
}
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;
!_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",
}
}
- 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;
}
}
|| 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;
*/
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;
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) {
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) {
}
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, e, f, d, F, D, Zf or Zd)");
return NULL;
}
\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\
'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\
array_modexec(PyObject *m)
{
array_state *state = get_array_state(m);
- char buffer[Py_ARRAY_LENGTH(descriptors)], *p;
PyObject *typecodes;
const struct arraydescr *descr;
return -1;
}
- p = buffer;
- for (descr = descriptors; descr->typecode != '\0'; descr++) {
- *p++ = (char)descr->typecode;
+ typecodes = PyList_New(0);
+ if (typecodes == NULL) {
+ return -1;
+ }
+ 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;
}
- typecodes = PyUnicode_DecodeASCII(buffer, p - buffer, NULL);
- if (PyModule_Add(m, "typecodes", typecodes) < 0) {
+ if (PyModule_Add(m, "typecodes", tuple) < 0) {
return -1;
}
static PyObject *
array__array_reconstructor_impl(PyObject *module, PyTypeObject *arraytype,
- int typecode,
+ const char *typecode,
enum machine_format_code mformat_code,
PyObject *items);
{
PyObject *return_value = NULL;
PyTypeObject *arraytype;
- int typecode;
+ const char *typecode;
enum machine_format_code mformat_code;
PyObject *items;
}
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;
return return_value;
}
-/*[clinic end generated code: output=9dcb2fc40710f83d input=a9049054013a1b77]*/
+/*[clinic end generated code: output=8699475b51151247 input=a9049054013a1b77]*/
/* This is not a general function for determining format equivalence.
It is used in copy_single() and copy_buffer() to weed out non-matching
formats. Skipping the '@' character is specifically used in slice
- assignments, where the lvalue is already known to have a single character
+ assignments, where the lvalue is already known to have a
format. This is a performance hack that could be rewritten (if properly
benchmarked). */
static inline int
/* 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;
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;
}
at = 1;
fmt++;
}
- if (fmt[0] == '\0' || fmt[1] != '\0') {
+ if (fmt[0] == '\0') {
return NULL;
}
+ if (fmt[0] == 'Z') {
+ if (fmt[1] == '\0' || fmt[2] != '\0') {
+ return NULL;
+ }
+ }
+ else {
+ if (fmt[1] != '\0') {
+ return NULL;
+ }
+ }
#define RETURN(s) do { return at ? "@" s : s; } while (0)
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");
}
{
Py_buffer *view = &mv->view;
PyObject *asciifmt;
- char srcchar, destchar;
+ const char *srcfmt, *destfmt;
Py_ssize_t itemsize;
int ret = -1;
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 "
- "character format prefixed with an optional '@'");
+ "memoryview: destination format must be a native "
+ "format prefixed with an optional '@'");
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;
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;
}
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);
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;
} 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);
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;
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;
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;
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)
/* 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();
Py_buffer *view = &self->view;
char *mem = view->buf;
Py_ssize_t ret;
- char fmt;
+ const char *fmt;
CHECK_RELEASED_INT(self);