diff options
author | Tim Peters <tim.peters@gmail.com> | 2001-06-12 01:22:22 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2001-06-12 01:22:22 (GMT) |
commit | 7a3bfc3a472dafc42d20845389eb79db8af0b046 (patch) | |
tree | 5b59ec1db42d4559a21af550c3b068b053ac79d2 /Modules | |
parent | ac4797a12eed2fb5bcc68ae6e768e5ab4ec5b422 (diff) | |
download | cpython-7a3bfc3a472dafc42d20845389eb79db8af0b046.zip cpython-7a3bfc3a472dafc42d20845389eb79db8af0b046.tar.gz cpython-7a3bfc3a472dafc42d20845389eb79db8af0b046.tar.bz2 |
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.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/structmodule.c | 192 |
1 files changed, 137 insertions, 55 deletions
diff --git a/Modules/structmodule.c b/Modules/structmodule.c index 9b79978..4a8886f 100644 --- a/Modules/structmodule.c +++ b/Modules/structmodule.c @@ -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) { @@ -826,6 +810,24 @@ bu_uint(const char *p, const formatdef *f) } 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) { return unpack_float(p, 1); @@ -868,6 +870,34 @@ bp_uint(char *p, PyObject *v, const formatdef *f) } 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) { double x = PyFloat_AsDouble(v); @@ -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) { @@ -938,6 +972,24 @@ lu_uint(const char *p, const formatdef *f) } 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) { return unpack_float(p+3, -1); @@ -980,6 +1032,34 @@ lp_uint(char *p, PyObject *v, const formatdef *f) } 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) { double x = PyFloat_AsDouble(v); @@ -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} |