mirror of
https://github.com/python/cpython.git
synced 2025-08-02 16:13:13 +00:00
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
5 changed files with 288 additions and 0 deletions
|
@ -821,6 +821,7 @@ PyLong_AsVoidPtr(PyObject *vv)
|
|||
*/
|
||||
|
||||
#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. */
|
||||
|
||||
|
@ -1023,6 +1024,109 @@ PyLong_AsUnsignedLongLongMask(PyObject *vv)
|
|||
}
|
||||
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
|
||||
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue