mirror of https://github.com/python/cpython
Issue #7767: Add new C-API function PyLong_AsLongLongAndOverflow, a
long long variant of PyLong_AsLongAndOverflow. Patch by Case Van Horsen.
This commit is contained in:
parent
a2d4653740
commit
a36507c64c
|
@ -146,6 +146,19 @@ Long Integer Objects
|
||||||
.. versionadded:: 2.7
|
.. versionadded:: 2.7
|
||||||
|
|
||||||
|
|
||||||
|
.. cfunction:: PY_LONG_LONG PyLong_AsLongLongAndOverflow(PyObject *pylong, int* overflow)
|
||||||
|
|
||||||
|
Return a C :ctype:`long long` representation of the contents of
|
||||||
|
*pylong*. If *pylong* is greater than :const:`PY_LLONG_MAX` or less
|
||||||
|
than :const:`PY_LLONG_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)
|
.. cfunction:: Py_ssize_t PyLong_AsSsize_t(PyObject *pylong)
|
||||||
|
|
||||||
.. index::
|
.. index::
|
||||||
|
|
|
@ -51,6 +51,7 @@ PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG);
|
||||||
PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLong(PyObject *);
|
PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLong(PyObject *);
|
||||||
PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(PyObject *);
|
PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(PyObject *);
|
||||||
PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLongMask(PyObject *);
|
PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLongMask(PyObject *);
|
||||||
|
PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLongAndOverflow(PyObject *, int *);
|
||||||
#endif /* HAVE_LONG_LONG */
|
#endif /* HAVE_LONG_LONG */
|
||||||
|
|
||||||
PyAPI_FUNC(PyObject *) PyLong_FromString(char *, char **, int);
|
PyAPI_FUNC(PyObject *) PyLong_FromString(char *, char **, int);
|
||||||
|
|
|
@ -254,6 +254,9 @@ Library
|
||||||
C-API
|
C-API
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
- Issue #7767: New function PyLong_AsLongLongAndOverflow added,
|
||||||
|
analogous to PyLong_AsLongAndOverflow.
|
||||||
|
|
||||||
- Issue #5080: The argument parsing functions PyArg_ParseTuple,
|
- Issue #5080: The argument parsing functions PyArg_ParseTuple,
|
||||||
PyArg_ParseTupleAndKeywords, PyArg_VaParse,
|
PyArg_ParseTupleAndKeywords, PyArg_VaParse,
|
||||||
PyArg_VaParseTupleAndKeywords and PyArg_Parse no longer accept float
|
PyArg_VaParseTupleAndKeywords and PyArg_Parse no longer accept float
|
||||||
|
|
|
@ -523,6 +523,171 @@ test_long_and_overflow(PyObject *self)
|
||||||
return Py_None;
|
return Py_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Test the PyLong_AsLongLongAndOverflow API. General conversion to
|
||||||
|
PY_LONG_LONG is tested by test_long_api_inner. This test will
|
||||||
|
concentrate on proper handling of overflow.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
test_long_long_and_overflow(PyObject *self)
|
||||||
|
{
|
||||||
|
PyObject *num, *one, *temp;
|
||||||
|
PY_LONG_LONG value;
|
||||||
|
int overflow;
|
||||||
|
|
||||||
|
/* Test that overflow is set properly for a large value. */
|
||||||
|
/* num is a number larger than PY_LLONG_MAX on a typical machine. */
|
||||||
|
num = PyLong_FromString("FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16);
|
||||||
|
if (num == NULL)
|
||||||
|
return NULL;
|
||||||
|
overflow = 1234;
|
||||||
|
value = PyLong_AsLongLongAndOverflow(num, &overflow);
|
||||||
|
Py_DECREF(num);
|
||||||
|
if (value == -1 && PyErr_Occurred())
|
||||||
|
return NULL;
|
||||||
|
if (value != -1)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"return value was not set to -1");
|
||||||
|
if (overflow != 1)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"overflow was not set to 1");
|
||||||
|
|
||||||
|
/* Same again, with num = PY_LLONG_MAX + 1 */
|
||||||
|
num = PyLong_FromLongLong(PY_LLONG_MAX);
|
||||||
|
if (num == NULL)
|
||||||
|
return NULL;
|
||||||
|
one = PyLong_FromLong(1L);
|
||||||
|
if (one == NULL) {
|
||||||
|
Py_DECREF(num);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
temp = PyNumber_Add(num, one);
|
||||||
|
Py_DECREF(one);
|
||||||
|
Py_DECREF(num);
|
||||||
|
num = temp;
|
||||||
|
if (num == NULL)
|
||||||
|
return NULL;
|
||||||
|
overflow = 0;
|
||||||
|
value = PyLong_AsLongLongAndOverflow(num, &overflow);
|
||||||
|
Py_DECREF(num);
|
||||||
|
if (value == -1 && PyErr_Occurred())
|
||||||
|
return NULL;
|
||||||
|
if (value != -1)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"return value was not set to -1");
|
||||||
|
if (overflow != 1)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"overflow was not set to 1");
|
||||||
|
|
||||||
|
/* Test that overflow is set properly for a large negative value. */
|
||||||
|
/* num is a number smaller than PY_LLONG_MIN on a typical platform */
|
||||||
|
num = PyLong_FromString("-FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16);
|
||||||
|
if (num == NULL)
|
||||||
|
return NULL;
|
||||||
|
overflow = 1234;
|
||||||
|
value = PyLong_AsLongLongAndOverflow(num, &overflow);
|
||||||
|
Py_DECREF(num);
|
||||||
|
if (value == -1 && PyErr_Occurred())
|
||||||
|
return NULL;
|
||||||
|
if (value != -1)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"return value was not set to -1");
|
||||||
|
if (overflow != -1)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"overflow was not set to -1");
|
||||||
|
|
||||||
|
/* Same again, with num = PY_LLONG_MIN - 1 */
|
||||||
|
num = PyLong_FromLongLong(PY_LLONG_MIN);
|
||||||
|
if (num == NULL)
|
||||||
|
return NULL;
|
||||||
|
one = PyLong_FromLong(1L);
|
||||||
|
if (one == NULL) {
|
||||||
|
Py_DECREF(num);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
temp = PyNumber_Subtract(num, one);
|
||||||
|
Py_DECREF(one);
|
||||||
|
Py_DECREF(num);
|
||||||
|
num = temp;
|
||||||
|
if (num == NULL)
|
||||||
|
return NULL;
|
||||||
|
overflow = 0;
|
||||||
|
value = PyLong_AsLongLongAndOverflow(num, &overflow);
|
||||||
|
Py_DECREF(num);
|
||||||
|
if (value == -1 && PyErr_Occurred())
|
||||||
|
return NULL;
|
||||||
|
if (value != -1)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"return value was not set to -1");
|
||||||
|
if (overflow != -1)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"overflow was not set to -1");
|
||||||
|
|
||||||
|
/* Test that overflow is cleared properly for small values. */
|
||||||
|
num = PyLong_FromString("FF", NULL, 16);
|
||||||
|
if (num == NULL)
|
||||||
|
return NULL;
|
||||||
|
overflow = 1234;
|
||||||
|
value = PyLong_AsLongLongAndOverflow(num, &overflow);
|
||||||
|
Py_DECREF(num);
|
||||||
|
if (value == -1 && PyErr_Occurred())
|
||||||
|
return NULL;
|
||||||
|
if (value != 0xFF)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"expected return value 0xFF");
|
||||||
|
if (overflow != 0)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"overflow was not cleared");
|
||||||
|
|
||||||
|
num = PyLong_FromString("-FF", NULL, 16);
|
||||||
|
if (num == NULL)
|
||||||
|
return NULL;
|
||||||
|
overflow = 0;
|
||||||
|
value = PyLong_AsLongLongAndOverflow(num, &overflow);
|
||||||
|
Py_DECREF(num);
|
||||||
|
if (value == -1 && PyErr_Occurred())
|
||||||
|
return NULL;
|
||||||
|
if (value != -0xFF)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"expected return value 0xFF");
|
||||||
|
if (overflow != 0)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"overflow was set incorrectly");
|
||||||
|
|
||||||
|
num = PyLong_FromLongLong(PY_LLONG_MAX);
|
||||||
|
if (num == NULL)
|
||||||
|
return NULL;
|
||||||
|
overflow = 1234;
|
||||||
|
value = PyLong_AsLongLongAndOverflow(num, &overflow);
|
||||||
|
Py_DECREF(num);
|
||||||
|
if (value == -1 && PyErr_Occurred())
|
||||||
|
return NULL;
|
||||||
|
if (value != PY_LLONG_MAX)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"expected return value PY_LLONG_MAX");
|
||||||
|
if (overflow != 0)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"overflow was not cleared");
|
||||||
|
|
||||||
|
num = PyLong_FromLongLong(PY_LLONG_MIN);
|
||||||
|
if (num == NULL)
|
||||||
|
return NULL;
|
||||||
|
overflow = 0;
|
||||||
|
value = PyLong_AsLongLongAndOverflow(num, &overflow);
|
||||||
|
Py_DECREF(num);
|
||||||
|
if (value == -1 && PyErr_Occurred())
|
||||||
|
return NULL;
|
||||||
|
if (value != PY_LLONG_MIN)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"expected return value PY_LLONG_MIN");
|
||||||
|
if (overflow != 0)
|
||||||
|
return raiseTestError("test_long_long_and_overflow",
|
||||||
|
"overflow was not cleared");
|
||||||
|
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
/* Test the L code for PyArg_ParseTuple. This should deliver a PY_LONG_LONG
|
/* 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
|
for both long and int arguments. The test may leak a little memory if
|
||||||
it fails.
|
it fails.
|
||||||
|
@ -1252,6 +1417,8 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"getargs_L", getargs_L, METH_VARARGS},
|
{"getargs_L", getargs_L, METH_VARARGS},
|
||||||
{"getargs_K", getargs_K, METH_VARARGS},
|
{"getargs_K", getargs_K, METH_VARARGS},
|
||||||
{"test_longlong_api", test_longlong_api, METH_NOARGS},
|
{"test_longlong_api", test_longlong_api, METH_NOARGS},
|
||||||
|
{"test_long_long_and_overflow",
|
||||||
|
(PyCFunction)test_long_long_and_overflow, METH_NOARGS},
|
||||||
{"test_L_code", (PyCFunction)test_L_code, METH_NOARGS},
|
{"test_L_code", (PyCFunction)test_L_code, METH_NOARGS},
|
||||||
{"codec_incrementalencoder",
|
{"codec_incrementalencoder",
|
||||||
(PyCFunction)codec_incrementalencoder, METH_VARARGS},
|
(PyCFunction)codec_incrementalencoder, METH_VARARGS},
|
||||||
|
|
|
@ -821,6 +821,7 @@ PyLong_AsVoidPtr(PyObject *vv)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define IS_LITTLE_ENDIAN (int)*(unsigned char*)&one
|
#define IS_LITTLE_ENDIAN (int)*(unsigned char*)&one
|
||||||
|
#define PY_ABS_LLONG_MIN (0-(unsigned PY_LONG_LONG)PY_LLONG_MIN)
|
||||||
|
|
||||||
/* Create a new long int object from a C PY_LONG_LONG int. */
|
/* Create a new long int object from a C PY_LONG_LONG int. */
|
||||||
|
|
||||||
|
@ -1023,6 +1024,109 @@ PyLong_AsUnsignedLongLongMask(PyObject *vv)
|
||||||
}
|
}
|
||||||
return x * sign;
|
return x * sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get a C long 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PY_LONG_LONG
|
||||||
|
PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow)
|
||||||
|
{
|
||||||
|
/* This version by Tim Peters */
|
||||||
|
register PyLongObject *v;
|
||||||
|
unsigned PY_LONG_LONG x, prev;
|
||||||
|
PY_LONG_LONG res;
|
||||||
|
Py_ssize_t i;
|
||||||
|
int sign;
|
||||||
|
int do_decref = 0; /* if nb_int was called */
|
||||||
|
|
||||||
|
*overflow = 0;
|
||||||
|
if (vv == NULL) {
|
||||||
|
PyErr_BadInternalCall();
|
||||||
|
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 PY_LONG_LONG)PY_LLONG_MAX) {
|
||||||
|
res = (PY_LONG_LONG)x * sign;
|
||||||
|
}
|
||||||
|
else if (sign < 0 && x == PY_ABS_LLONG_MIN) {
|
||||||
|
res = PY_LLONG_MIN;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*overflow = sign;
|
||||||
|
/* res is already set to -1 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
if (do_decref) {
|
||||||
|
Py_DECREF(vv);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
#undef IS_LITTLE_ENDIAN
|
#undef IS_LITTLE_ENDIAN
|
||||||
|
|
||||||
#endif /* HAVE_LONG_LONG */
|
#endif /* HAVE_LONG_LONG */
|
||||||
|
|
Loading…
Reference in New Issue