Issue #7528: Backport PyLong_AsLongAndOverflow from py3k to trunk.
Thanks Case Van Horsen for the patch.
This commit is contained in:
parent
2b66da7d15
commit
e31d300664
|
@ -133,6 +133,19 @@ Long Integer Objects
|
|||
and ``-1`` will be returned.
|
||||
|
||||
|
||||
.. cfunction:: long PyLong_AsLongAndOverflow(PyObject *pylong, int* overflow)
|
||||
|
||||
Return a C :ctype:`long` representation of the contents of
|
||||
*pylong*. If *pylong* is greater than :const:`LONG_MAX` or less
|
||||
than :const:`LONG_MIN`, set `*overflow` to ``1`` or ``-1``,
|
||||
respectively, and return ``-1``; otherwise, set `*overflow` to
|
||||
``0``. If any other exception occurs (for example a TypeError or
|
||||
MemoryError), then ``-1`` will be returned and ``*overflow`` will
|
||||
be ``0``.
|
||||
|
||||
.. versionadded:: 2.7
|
||||
|
||||
|
||||
.. cfunction:: Py_ssize_t PyLong_AsSsize_t(PyObject *pylong)
|
||||
|
||||
.. index::
|
||||
|
|
|
@ -21,6 +21,7 @@ PyAPI_FUNC(PyObject *) PyLong_FromDouble(double);
|
|||
PyAPI_FUNC(PyObject *) PyLong_FromSize_t(size_t);
|
||||
PyAPI_FUNC(PyObject *) PyLong_FromSsize_t(Py_ssize_t);
|
||||
PyAPI_FUNC(long) PyLong_AsLong(PyObject *);
|
||||
PyAPI_FUNC(long) PyLong_AsLongAndOverflow(PyObject *, int *);
|
||||
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *);
|
||||
PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *);
|
||||
PyAPI_FUNC(Py_ssize_t) PyLong_AsSsize_t(PyObject *);
|
||||
|
|
|
@ -1648,6 +1648,8 @@ Documentation
|
|||
C-API
|
||||
-----
|
||||
|
||||
- Issue #7528: Add PyLong_AsLongAndOverflow (backported from py3k).
|
||||
|
||||
- Issue #7228: Add '%lld' and '%llu' support to PyString_FromFormat(V)
|
||||
and PyErr_Format, on machines with HAVE_LONG_LONG defined.
|
||||
|
||||
|
|
|
@ -358,6 +358,75 @@ test_longlong_api(PyObject* self, PyObject *args)
|
|||
#undef F_U_TO_PY
|
||||
#undef F_PY_TO_U
|
||||
|
||||
/* Test the PyLong_AsLongAndOverflow API. General conversion to PY_LONG
|
||||
is tested by test_long_api_inner. This test will concentrate on proper
|
||||
handling of overflow.
|
||||
*/
|
||||
|
||||
static PyObject *
|
||||
test_long_and_overflow(PyObject *self)
|
||||
{
|
||||
PyObject *num;
|
||||
long value;
|
||||
int overflow;
|
||||
|
||||
/* a number larger than LONG_MAX even on 64-bit platforms */
|
||||
num = PyLong_FromString("FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16);
|
||||
if (num == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Test that overflow is set properly for a large value. */
|
||||
overflow = 1234;
|
||||
value = PyLong_AsLongAndOverflow(num, &overflow);
|
||||
if (overflow != 1)
|
||||
return raiseTestError("test_long_and_overflow",
|
||||
"overflow was not set to 1");
|
||||
|
||||
overflow = 0;
|
||||
value = PyLong_AsLongAndOverflow(num, &overflow);
|
||||
if (overflow != 1)
|
||||
return raiseTestError("test_long_and_overflow",
|
||||
"overflow was not set to 0");
|
||||
|
||||
/* a number smaller than LONG_MIN even on 64-bit platforms */
|
||||
num = PyLong_FromString("-FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16);
|
||||
if (num == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Test that overflow is set properly for a large negative value. */
|
||||
overflow = 1234;
|
||||
value = PyLong_AsLongAndOverflow(num, &overflow);
|
||||
if (overflow != -1)
|
||||
return raiseTestError("test_long_and_overflow",
|
||||
"overflow was not set to -1");
|
||||
|
||||
overflow = 0;
|
||||
value = PyLong_AsLongAndOverflow(num, &overflow);
|
||||
if (overflow != -1)
|
||||
return raiseTestError("test_long_and_overflow",
|
||||
"overflow was not set to 0");
|
||||
|
||||
num = PyLong_FromString("FF", NULL, 16);
|
||||
if (num == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Test that overflow is cleared properly for a small value. */
|
||||
overflow = 1234;
|
||||
value = PyLong_AsLongAndOverflow(num, &overflow);
|
||||
if (overflow != 0)
|
||||
return raiseTestError("test_long_and_overflow",
|
||||
"overflow was not cleared");
|
||||
|
||||
overflow = 0;
|
||||
value = PyLong_AsLongAndOverflow(num, &overflow);
|
||||
if (overflow != 0)
|
||||
return raiseTestError("test_long_and_overflow",
|
||||
"overflow was set incorrectly");
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
/* Test the L code for PyArg_ParseTuple. This should deliver a PY_LONG_LONG
|
||||
for both long and int arguments. The test may leak a little memory if
|
||||
it fails.
|
||||
|
@ -1041,6 +1110,7 @@ static PyMethodDef TestMethods[] = {
|
|||
{"test_dict_iteration", (PyCFunction)test_dict_iteration,METH_NOARGS},
|
||||
{"test_lazy_hash_inheritance", (PyCFunction)test_lazy_hash_inheritance,METH_NOARGS},
|
||||
{"test_long_api", (PyCFunction)test_long_api, METH_NOARGS},
|
||||
{"test_long_and_overflow", (PyCFunction)test_long_and_overflow, METH_NOARGS},
|
||||
{"test_long_numbits", (PyCFunction)test_long_numbits, METH_NOARGS},
|
||||
{"test_k_code", (PyCFunction)test_k_code, METH_NOARGS},
|
||||
{"test_empty_argparse", (PyCFunction)test_empty_argparse,METH_NOARGS},
|
||||
|
|
|
@ -223,53 +223,123 @@ PyLong_FromDouble(double dval)
|
|||
#define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN)
|
||||
#define PY_ABS_SSIZE_T_MIN (0-(size_t)PY_SSIZE_T_MIN)
|
||||
|
||||
/* Get a C long int from a long int object.
|
||||
Returns -1 and sets an error condition if overflow occurs. */
|
||||
/* Get a C long int from a Python long or Python int object.
|
||||
On overflow, returns -1 and sets *overflow to 1 or -1 depending
|
||||
on the sign of the result. Otherwise *overflow is 0.
|
||||
|
||||
For other errors (e.g., type error), returns -1 and sets an error
|
||||
condition.
|
||||
*/
|
||||
|
||||
long
|
||||
PyLong_AsLong(PyObject *vv)
|
||||
PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
|
||||
{
|
||||
/* This version by Tim Peters */
|
||||
register PyLongObject *v;
|
||||
unsigned long x, prev;
|
||||
long res;
|
||||
Py_ssize_t i;
|
||||
int sign;
|
||||
int do_decref = 0; /* if nb_int was called */
|
||||
|
||||
if (vv == NULL || !PyLong_Check(vv)) {
|
||||
if (vv != NULL && PyInt_Check(vv))
|
||||
return PyInt_AsLong(vv);
|
||||
*overflow = 0;
|
||||
if (vv == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
}
|
||||
v = (PyLongObject *)vv;
|
||||
i = v->ob_size;
|
||||
sign = 1;
|
||||
x = 0;
|
||||
if (i < 0) {
|
||||
sign = -1;
|
||||
i = -(i);
|
||||
}
|
||||
while (--i >= 0) {
|
||||
prev = x;
|
||||
x = (x << PyLong_SHIFT) | v->ob_digit[i];
|
||||
if ((x >> PyLong_SHIFT) != prev)
|
||||
goto overflow;
|
||||
}
|
||||
/* Haven't lost any bits, but casting to long requires extra care
|
||||
* (see comment above).
|
||||
*/
|
||||
if (x <= (unsigned long)LONG_MAX) {
|
||||
return (long)x * sign;
|
||||
}
|
||||
else if (sign < 0 && x == PY_ABS_LONG_MIN) {
|
||||
return LONG_MIN;
|
||||
}
|
||||
/* else overflow */
|
||||
|
||||
overflow:
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"long int too large to convert to int");
|
||||
return -1;
|
||||
if(PyInt_Check(vv))
|
||||
return PyInt_AsLong(vv);
|
||||
|
||||
if (!PyLong_Check(vv)) {
|
||||
PyNumberMethods *nb;
|
||||
nb = vv->ob_type->tp_as_number;
|
||||
if (nb == NULL || nb->nb_int == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"an integer is required");
|
||||
return -1;
|
||||
}
|
||||
vv = (*nb->nb_int) (vv);
|
||||
if (vv == NULL)
|
||||
return -1;
|
||||
do_decref = 1;
|
||||
if(PyInt_Check(vv)) {
|
||||
res = PyInt_AsLong(vv);
|
||||
goto exit;
|
||||
}
|
||||
if (!PyLong_Check(vv)) {
|
||||
Py_DECREF(vv);
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"nb_int should return int object");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
res = -1;
|
||||
v = (PyLongObject *)vv;
|
||||
i = Py_SIZE(v);
|
||||
|
||||
switch (i) {
|
||||
case -1:
|
||||
res = -(sdigit)v->ob_digit[0];
|
||||
break;
|
||||
case 0:
|
||||
res = 0;
|
||||
break;
|
||||
case 1:
|
||||
res = v->ob_digit[0];
|
||||
break;
|
||||
default:
|
||||
sign = 1;
|
||||
x = 0;
|
||||
if (i < 0) {
|
||||
sign = -1;
|
||||
i = -(i);
|
||||
}
|
||||
while (--i >= 0) {
|
||||
prev = x;
|
||||
x = (x << PyLong_SHIFT) + v->ob_digit[i];
|
||||
if ((x >> PyLong_SHIFT) != prev) {
|
||||
*overflow = sign;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
/* Haven't lost any bits, but casting to long requires extra
|
||||
* care (see comment above).
|
||||
*/
|
||||
if (x <= (unsigned long)LONG_MAX) {
|
||||
res = (long)x * sign;
|
||||
}
|
||||
else if (sign < 0 && x == PY_ABS_LONG_MIN) {
|
||||
res = LONG_MIN;
|
||||
}
|
||||
else {
|
||||
*overflow = sign;
|
||||
/* res is already set to -1 */
|
||||
}
|
||||
}
|
||||
exit:
|
||||
if (do_decref) {
|
||||
Py_DECREF(vv);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Get a C long int from a long int object.
|
||||
Returns -1 and sets an error condition if overflow occurs. */
|
||||
|
||||
long
|
||||
PyLong_AsLong(PyObject *obj)
|
||||
{
|
||||
int overflow;
|
||||
long result = PyLong_AsLongAndOverflow(obj, &overflow);
|
||||
if (overflow) {
|
||||
/* XXX: could be cute and give a different
|
||||
message for overflow == -1 */
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"Python int too large to convert to C long");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Get a Py_ssize_t from a long int object.
|
||||
|
|
Loading…
Reference in New Issue