summaryrefslogtreecommitdiff
path: root/Modules/_struct.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_struct.c')
-rw-r--r--Modules/_struct.c198
1 files changed, 111 insertions, 87 deletions
diff --git a/Modules/_struct.c b/Modules/_struct.c
index f965541a5b..796d1682f0 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -60,6 +60,7 @@ typedef struct { char c; float x; } st_float;
typedef struct { char c; double x; } st_double;
typedef struct { char c; void *x; } st_void_p;
typedef struct { char c; size_t x; } st_size_t;
+typedef struct { char c; _Bool x; } st_bool;
#define SHORT_ALIGN (sizeof(st_short) - sizeof(short))
#define INT_ALIGN (sizeof(st_int) - sizeof(int))
@@ -68,22 +69,12 @@ typedef struct { char c; size_t x; } st_size_t;
#define DOUBLE_ALIGN (sizeof(st_double) - sizeof(double))
#define VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *))
#define SIZE_T_ALIGN (sizeof(st_size_t) - sizeof(size_t))
+#define BOOL_ALIGN (sizeof(st_bool) - sizeof(_Bool))
/* We can't support q and Q in native mode unless the compiler does;
in std mode, they're 8 bytes on all platforms. */
-#ifdef HAVE_LONG_LONG
-typedef struct { char c; PY_LONG_LONG x; } s_long_long;
-#define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(PY_LONG_LONG))
-#endif
-
-#ifdef HAVE_C99_BOOL
-#define BOOL_TYPE _Bool
-typedef struct { char c; _Bool x; } s_bool;
-#define BOOL_ALIGN (sizeof(s_bool) - sizeof(BOOL_TYPE))
-#else
-#define BOOL_TYPE char
-#define BOOL_ALIGN 0
-#endif
+typedef struct { char c; long long x; } s_long_long;
+#define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(long long))
#ifdef __powerc
#pragma options align=reset
@@ -164,14 +155,12 @@ get_ulong(PyObject *v, unsigned long *p)
return 0;
}
-#ifdef HAVE_LONG_LONG
-
/* Same, but handling native long long. */
static int
-get_longlong(PyObject *v, PY_LONG_LONG *p)
+get_longlong(PyObject *v, long long *p)
{
- PY_LONG_LONG x;
+ long long x;
v = get_pylong(v);
if (v == NULL)
@@ -179,7 +168,7 @@ get_longlong(PyObject *v, PY_LONG_LONG *p)
assert(PyLong_Check(v));
x = PyLong_AsLongLong(v);
Py_DECREF(v);
- if (x == (PY_LONG_LONG)-1 && PyErr_Occurred()) {
+ if (x == (long long)-1 && PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_OverflowError))
PyErr_SetString(StructError,
"argument out of range");
@@ -192,9 +181,9 @@ get_longlong(PyObject *v, PY_LONG_LONG *p)
/* Same, but handling native unsigned long long. */
static int
-get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p)
+get_ulonglong(PyObject *v, unsigned long long *p)
{
- unsigned PY_LONG_LONG x;
+ unsigned long long x;
v = get_pylong(v);
if (v == NULL)
@@ -202,7 +191,7 @@ get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p)
assert(PyLong_Check(v));
x = PyLong_AsUnsignedLongLong(v);
Py_DECREF(v);
- if (x == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) {
+ if (x == (unsigned long long)-1 && PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_OverflowError))
PyErr_SetString(StructError,
"argument out of range");
@@ -212,8 +201,6 @@ get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p)
return 0;
}
-#endif
-
/* Same, but handling Py_ssize_t */
static int
@@ -267,6 +254,33 @@ get_size_t(PyObject *v, size_t *p)
/* Floating point helpers */
static PyObject *
+unpack_halffloat(const char *p, /* start of 2-byte string */
+ int le) /* true for little-endian, false for big-endian */
+{
+ double x;
+
+ x = _PyFloat_Unpack2((unsigned char *)p, le);
+ if (x == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
+ return PyFloat_FromDouble(x);
+}
+
+static int
+pack_halffloat(char *p, /* start of 2-byte string */
+ PyObject *v, /* value to pack */
+ int le) /* true for little-endian, false for big-endian */
+{
+ double x = PyFloat_AsDouble(v);
+ if (x == -1.0 && PyErr_Occurred()) {
+ PyErr_SetString(StructError,
+ "required argument is not a float");
+ return -1;
+ }
+ return _PyFloat_Pack2(x, (unsigned char *)p, le);
+}
+
+static PyObject *
unpack_float(const char *p, /* start of 4-byte string */
int le) /* true for little-endian, false for big-endian */
{
@@ -436,40 +450,46 @@ nu_size_t(const char *p, const formatdef *f)
/* Native mode doesn't support q or Q unless the platform C supports
long long (or, on Windows, __int64). */
-#ifdef HAVE_LONG_LONG
-
static PyObject *
nu_longlong(const char *p, const formatdef *f)
{
- PY_LONG_LONG x;
+ long long x;
memcpy((char *)&x, p, sizeof x);
if (x >= LONG_MIN && x <= LONG_MAX)
- return PyLong_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long));
+ return PyLong_FromLong(Py_SAFE_DOWNCAST(x, long long, long));
return PyLong_FromLongLong(x);
}
static PyObject *
nu_ulonglong(const char *p, const formatdef *f)
{
- unsigned PY_LONG_LONG x;
+ unsigned long long x;
memcpy((char *)&x, p, sizeof x);
if (x <= LONG_MAX)
- return PyLong_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long));
+ return PyLong_FromLong(Py_SAFE_DOWNCAST(x, unsigned long long, long));
return PyLong_FromUnsignedLongLong(x);
}
-#endif
-
static PyObject *
nu_bool(const char *p, const formatdef *f)
{
- BOOL_TYPE x;
+ _Bool x;
memcpy((char *)&x, p, sizeof x);
return PyBool_FromLong(x != 0);
}
static PyObject *
+nu_halffloat(const char *p, const formatdef *f)
+{
+#if PY_LITTLE_ENDIAN
+ return unpack_halffloat(p, 1);
+#else
+ return unpack_halffloat(p, 0);
+#endif
+}
+
+static PyObject *
nu_float(const char *p, const formatdef *f)
{
float x;
@@ -643,12 +663,10 @@ np_size_t(char *p, PyObject *v, const formatdef *f)
return 0;
}
-#ifdef HAVE_LONG_LONG
-
static int
np_longlong(char *p, PyObject *v, const formatdef *f)
{
- PY_LONG_LONG x;
+ long long x;
if (get_longlong(v, &x) < 0)
return -1;
memcpy(p, (char *)&x, sizeof x);
@@ -658,20 +676,19 @@ np_longlong(char *p, PyObject *v, const formatdef *f)
static int
np_ulonglong(char *p, PyObject *v, const formatdef *f)
{
- unsigned PY_LONG_LONG x;
+ unsigned long long x;
if (get_ulonglong(v, &x) < 0)
return -1;
memcpy(p, (char *)&x, sizeof x);
return 0;
}
-#endif
static int
np_bool(char *p, PyObject *v, const formatdef *f)
{
int y;
- BOOL_TYPE x;
+ _Bool x;
y = PyObject_IsTrue(v);
if (y < 0)
return -1;
@@ -681,6 +698,16 @@ np_bool(char *p, PyObject *v, const formatdef *f)
}
static int
+np_halffloat(char *p, PyObject *v, const formatdef *f)
+{
+#if PY_LITTLE_ENDIAN
+ return pack_halffloat(p, v, 1);
+#else
+ return pack_halffloat(p, v, 0);
+#endif
+}
+
+static int
np_float(char *p, PyObject *v, const formatdef *f)
{
float x = (float)PyFloat_AsDouble(v);
@@ -723,7 +750,7 @@ np_void_p(char *p, PyObject *v, const formatdef *f)
return 0;
}
-static formatdef native_table[] = {
+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},
@@ -738,11 +765,10 @@ static formatdef native_table[] = {
{'L', sizeof(long), LONG_ALIGN, nu_ulong, np_ulong},
{'n', sizeof(size_t), SIZE_T_ALIGN, nu_ssize_t, np_ssize_t},
{'N', sizeof(size_t), SIZE_T_ALIGN, nu_size_t, np_size_t},
-#ifdef HAVE_LONG_LONG
- {'q', sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_longlong, np_longlong},
- {'Q', sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_ulonglong,np_ulonglong},
-#endif
- {'?', sizeof(BOOL_TYPE), BOOL_ALIGN, nu_bool, np_bool},
+ {'q', sizeof(long long), LONG_LONG_ALIGN, nu_longlong, np_longlong},
+ {'Q', sizeof(long long), LONG_LONG_ALIGN, nu_ulonglong,np_ulonglong},
+ {'?', sizeof(_Bool), BOOL_ALIGN, nu_bool, np_bool},
+ {'e', sizeof(short), SHORT_ALIGN, nu_halffloat, np_halffloat},
{'f', sizeof(float), FLOAT_ALIGN, nu_float, np_float},
{'d', sizeof(double), DOUBLE_ALIGN, nu_double, np_double},
{'P', sizeof(void *), VOID_P_ALIGN, nu_void_p, np_void_p},
@@ -783,8 +809,7 @@ bu_uint(const char *p, const formatdef *f)
static PyObject *
bu_longlong(const char *p, const formatdef *f)
{
-#ifdef HAVE_LONG_LONG
- PY_LONG_LONG x = 0;
+ long long x = 0;
Py_ssize_t i = f->size;
const unsigned char *bytes = (const unsigned char *)p;
do {
@@ -792,37 +817,30 @@ bu_longlong(const char *p, const formatdef *f)
} while (--i > 0);
/* Extend the sign bit. */
if (SIZEOF_LONG_LONG > f->size)
- x |= -(x & ((PY_LONG_LONG)1 << ((8 * f->size) - 1)));
+ x |= -(x & ((long long)1 << ((8 * f->size) - 1)));
if (x >= LONG_MIN && x <= LONG_MAX)
- return PyLong_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long));
+ return PyLong_FromLong(Py_SAFE_DOWNCAST(x, long long, long));
return PyLong_FromLongLong(x);
-#else
- return _PyLong_FromByteArray((const unsigned char *)p,
- 8,
- 0, /* little-endian */
- 1 /* signed */);
-#endif
}
static PyObject *
bu_ulonglong(const char *p, const formatdef *f)
{
-#ifdef HAVE_LONG_LONG
- unsigned PY_LONG_LONG x = 0;
+ unsigned long long x = 0;
Py_ssize_t i = f->size;
const unsigned char *bytes = (const unsigned char *)p;
do {
x = (x<<8) | *bytes++;
} while (--i > 0);
if (x <= LONG_MAX)
- return PyLong_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long));
+ return PyLong_FromLong(Py_SAFE_DOWNCAST(x, unsigned long long, long));
return PyLong_FromUnsignedLongLong(x);
-#else
- return _PyLong_FromByteArray((const unsigned char *)p,
- 8,
- 0, /* little-endian */
- 0 /* signed */);
-#endif
+}
+
+static PyObject *
+bu_halffloat(const char *p, const formatdef *f)
+{
+ return unpack_halffloat(p, 0);
}
static PyObject *
@@ -922,6 +940,12 @@ bp_ulonglong(char *p, PyObject *v, const formatdef *f)
}
static int
+bp_halffloat(char *p, PyObject *v, const formatdef *f)
+{
+ return pack_halffloat(p, v, 0);
+}
+
+static int
bp_float(char *p, PyObject *v, const formatdef *f)
{
double x = PyFloat_AsDouble(v);
@@ -972,6 +996,7 @@ static formatdef bigendian_table[] = {
{'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},
{0}
@@ -1011,8 +1036,7 @@ lu_uint(const char *p, const formatdef *f)
static PyObject *
lu_longlong(const char *p, const formatdef *f)
{
-#ifdef HAVE_LONG_LONG
- PY_LONG_LONG x = 0;
+ long long x = 0;
Py_ssize_t i = f->size;
const unsigned char *bytes = (const unsigned char *)p;
do {
@@ -1020,37 +1044,30 @@ lu_longlong(const char *p, const formatdef *f)
} while (i > 0);
/* Extend the sign bit. */
if (SIZEOF_LONG_LONG > f->size)
- x |= -(x & ((PY_LONG_LONG)1 << ((8 * f->size) - 1)));
+ x |= -(x & ((long long)1 << ((8 * f->size) - 1)));
if (x >= LONG_MIN && x <= LONG_MAX)
- return PyLong_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long));
+ return PyLong_FromLong(Py_SAFE_DOWNCAST(x, long long, long));
return PyLong_FromLongLong(x);
-#else
- return _PyLong_FromByteArray((const unsigned char *)p,
- 8,
- 1, /* little-endian */
- 1 /* signed */);
-#endif
}
static PyObject *
lu_ulonglong(const char *p, const formatdef *f)
{
-#ifdef HAVE_LONG_LONG
- unsigned PY_LONG_LONG x = 0;
+ unsigned long long x = 0;
Py_ssize_t i = f->size;
const unsigned char *bytes = (const unsigned char *)p;
do {
x = (x<<8) | bytes[--i];
} while (i > 0);
if (x <= LONG_MAX)
- return PyLong_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long));
+ return PyLong_FromLong(Py_SAFE_DOWNCAST(x, unsigned long long, long));
return PyLong_FromUnsignedLongLong(x);
-#else
- return _PyLong_FromByteArray((const unsigned char *)p,
- 8,
- 1, /* little-endian */
- 0 /* signed */);
-#endif
+}
+
+static PyObject *
+lu_halffloat(const char *p, const formatdef *f)
+{
+ return unpack_halffloat(p, 1);
}
static PyObject *
@@ -1142,6 +1159,12 @@ lp_ulonglong(char *p, PyObject *v, const formatdef *f)
}
static int
+lp_halffloat(char *p, PyObject *v, const formatdef *f)
+{
+ return pack_halffloat(p, v, 1);
+}
+
+static int
lp_float(char *p, PyObject *v, const formatdef *f)
{
double x = PyFloat_AsDouble(v);
@@ -1182,6 +1205,7 @@ static formatdef lilendian_table[] = {
{'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},
{0}
@@ -1189,7 +1213,7 @@ static formatdef lilendian_table[] = {
static const formatdef *
-whichtable(char **pfmt)
+whichtable(const char **pfmt)
{
const char *fmt = (*pfmt)++; /* May be backed out of later */
switch (*fmt) {
@@ -1268,7 +1292,7 @@ prepare_s(PyStructObject *self)
fmt = PyBytes_AS_STRING(self->s_format);
- f = whichtable((char **)&fmt);
+ f = whichtable(&fmt);
s = fmt;
size = 0;
@@ -1456,7 +1480,7 @@ s_dealloc(PyStructObject *s)
}
static PyObject *
-s_unpack_internal(PyStructObject *soself, char *startfrom) {
+s_unpack_internal(PyStructObject *soself, const char *startfrom) {
formatcode *code;
Py_ssize_t i = 0;
PyObject *result = PyTuple_New(soself->s_len);
@@ -2239,7 +2263,7 @@ these can be preceded by a decimal repeat count:\n\
x: pad byte (no data); c:char; b:signed byte; B:unsigned byte;\n\
?: _Bool (requires C99; if not available, char is used instead)\n\
h:short; H:unsigned short; i:int; I:unsigned int;\n\
- l:long; L:unsigned long; f:float; d:double.\n\
+ l:long; L:unsigned long; f:float; d:double; e:half-float.\n\
Special cases (preceding decimal count indicates length):\n\
s:string (array of char); p: pascal string (with count byte).\n\
Special cases (only available in native format):\n\
@@ -2279,7 +2303,7 @@ PyInit__struct(void)
/* Check endian and swap in faster functions */
{
- formatdef *native = native_table;
+ const formatdef *native = native_table;
formatdef *other, *ptr;
#if PY_LITTLE_ENDIAN
other = lilendian_table;