Added q/Q standard (x-platform 8-byte ints) mode in struct module.

This completes the q/Q project.

longobject.c _PyLong_AsByteArray:  The original code had a gross bug:
the most-significant Python digit doesn't necessarily have SHIFT
significant bits, and you really need to count how many copies of the sign
bit it has else spurious overflow errors result.

test_struct.py:  This now does exhaustive std q/Q testing at, and on both
sides of, all relevant power-of-2 boundaries, both positive and negative.

NEWS:  Added brief dict news while I was at it.
This commit is contained in:
Tim Peters 2001-06-12 01:22:22 +00:00
parent ac4797a12e
commit 7a3bfc3a47
5 changed files with 337 additions and 77 deletions

View file

@ -80,6 +80,34 @@ typedef struct { char c; LONG_LONG x; } s_long_long;
#pragma options align=reset
#endif
/* Helper to get a PyLongObject by hook or by crook. Caller should decref. */
static PyObject *
get_pylong(PyObject *v)
{
PyNumberMethods *m;
assert(v != NULL);
if (PyInt_Check(v))
return PyLong_FromLong(PyInt_AS_LONG(v));
if (PyLong_Check(v)) {
Py_INCREF(v);
return v;
}
m = v->ob_type->tp_as_number;
if (m != NULL && m->nb_long != NULL) {
v = m->nb_long(v);
if (v == NULL)
return NULL;
if (PyLong_Check(v))
return v;
Py_DECREF(v);
}
PyErr_SetString(StructError,
"cannot convert argument to long");
return NULL;
}
/* Helper routine to get a Python integer and raise the appropriate error
if it isn't one */
@ -123,33 +151,13 @@ static int
get_longlong(PyObject *v, LONG_LONG *p)
{
LONG_LONG x;
int v_needs_decref = 0;
if (PyInt_Check(v)) {
x = (LONG_LONG)PyInt_AS_LONG(v);
*p = x;
return 0;
}
if (!PyLong_Check(v)) {
PyNumberMethods *m = v->ob_type->tp_as_number;
if (m != NULL && m->nb_long != NULL) {
v = m->nb_long(v);
if (v == NULL)
return -1;
v_needs_decref = 1;
}
if (!PyLong_Check(v)) {
PyErr_SetString(StructError,
"cannot convert argument to long");
if (v_needs_decref)
Py_DECREF(v);
return -1;
}
}
v = get_pylong(v);
if (v == NULL)
return -1;
assert(PyLong_Check(v));
x = PyLong_AsLongLong(v);
if (v_needs_decref)
Py_DECREF(v);
Py_DECREF(v);
if (x == (LONG_LONG)-1 && PyErr_Occurred())
return -1;
*p = x;
@ -162,39 +170,13 @@ static int
get_ulonglong(PyObject *v, unsigned LONG_LONG *p)
{
unsigned LONG_LONG x;
int v_needs_decref = 0;
if (PyInt_Check(v)) {
long i = PyInt_AS_LONG(v);
if (i < 0) {
PyErr_SetString(StructError, "can't convert negative "
"int to unsigned");
return -1;
}
x = (unsigned LONG_LONG)i;
*p = x;
return 0;
}
if (!PyLong_Check(v)) {
PyNumberMethods *m = v->ob_type->tp_as_number;
if (m != NULL && m->nb_long != NULL) {
v = m->nb_long(v);
if (v == NULL)
return -1;
v_needs_decref = 1;
}
if (!PyLong_Check(v)) {
PyErr_SetString(StructError,
"cannot convert argument to long");
if (v_needs_decref)
Py_DECREF(v);
return -1;
}
}
v = get_pylong(v);
if (v == NULL)
return -1;
assert(PyLong_Check(v));
x = PyLong_AsUnsignedLongLong(v);
if (v_needs_decref)
Py_DECREF(v);
Py_DECREF(v);
if (x == (unsigned LONG_LONG)-1 && PyErr_Occurred())
return -1;
*p = x;
@ -500,7 +482,7 @@ typedef struct _formatdef {
TYPE is one of char, byte, ubyte, etc.
*/
/* Native mode routines. */
/* Native mode routines. ****************************************************/
static PyObject *
nu_char(const char *p, const formatdef *f)
@ -797,6 +779,8 @@ static formatdef native_table[] = {
{0}
};
/* Big-endian routines. *****************************************************/
static PyObject *
bu_int(const char *p, const formatdef *f)
{
@ -825,6 +809,24 @@ bu_uint(const char *p, const formatdef *f)
return PyInt_FromLong((long)x);
}
static PyObject *
bu_longlong(const char *p, const formatdef *f)
{
return _PyLong_FromByteArray((const unsigned char *)p,
8,
0, /* little-endian */
1 /* signed */);
}
static PyObject *
bu_ulonglong(const char *p, const formatdef *f)
{
return _PyLong_FromByteArray((const unsigned char *)p,
8,
0, /* little-endian */
0 /* signed */);
}
static PyObject *
bu_float(const char *p, const formatdef *f)
{
@ -867,6 +869,34 @@ bp_uint(char *p, PyObject *v, const formatdef *f)
return 0;
}
static int
bp_longlong(char *p, PyObject *v, const formatdef *f)
{
int res;
v = get_pylong(v);
res = _PyLong_AsByteArray((PyLongObject *)v,
(unsigned char *)p,
8,
0, /* little_endian */
1 /* signed */);
Py_DECREF(v);
return res;
}
static int
bp_ulonglong(char *p, PyObject *v, const formatdef *f)
{
int res;
v = get_pylong(v);
res = _PyLong_AsByteArray((PyLongObject *)v,
(unsigned char *)p,
8,
0, /* little_endian */
0 /* signed */);
Py_DECREF(v);
return res;
}
static int
bp_float(char *p, PyObject *v, const formatdef *f)
{
@ -904,11 +934,15 @@ static formatdef bigendian_table[] = {
{'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},
{'f', 4, 0, bu_float, bp_float},
{'d', 8, 0, bu_double, bp_double},
{0}
};
/* Little-endian routines. *****************************************************/
static PyObject *
lu_int(const char *p, const formatdef *f)
{
@ -937,6 +971,24 @@ lu_uint(const char *p, const formatdef *f)
return PyInt_FromLong((long)x);
}
static PyObject *
lu_longlong(const char *p, const formatdef *f)
{
return _PyLong_FromByteArray((const unsigned char *)p,
8,
1, /* little-endian */
1 /* signed */);
}
static PyObject *
lu_ulonglong(const char *p, const formatdef *f)
{
return _PyLong_FromByteArray((const unsigned char *)p,
8,
1, /* little-endian */
0 /* signed */);
}
static PyObject *
lu_float(const char *p, const formatdef *f)
{
@ -979,6 +1031,34 @@ lp_uint(char *p, PyObject *v, const formatdef *f)
return 0;
}
static int
lp_longlong(char *p, PyObject *v, const formatdef *f)
{
int res;
v = get_pylong(v);
res = _PyLong_AsByteArray((PyLongObject*)v,
(unsigned char *)p,
8,
1, /* little_endian */
1 /* signed */);
Py_DECREF(v);
return res;
}
static int
lp_ulonglong(char *p, PyObject *v, const formatdef *f)
{
int res;
v = get_pylong(v);
res = _PyLong_AsByteArray((PyLongObject*)v,
(unsigned char *)p,
8,
1, /* little_endian */
0 /* signed */);
Py_DECREF(v);
return res;
}
static int
lp_float(char *p, PyObject *v, const formatdef *f)
{
@ -1016,6 +1096,8 @@ static formatdef lilendian_table[] = {
{'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},
{'f', 4, 0, lu_float, lp_float},
{'d', 8, 0, lu_double, lp_double},
{0}