diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2010-01-30 10:30:15 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2010-01-30 10:30:15 (GMT) |
commit | 93f562c4f9a751034616068468e7dc2cfd022275 (patch) | |
tree | 5f41dda113e687676341b3032abc0545c5c4543e /Objects/longobject.c | |
parent | a79b75743af3d7c66fcccc1c47699c838422064b (diff) | |
download | cpython-93f562c4f9a751034616068468e7dc2cfd022275.zip cpython-93f562c4f9a751034616068468e7dc2cfd022275.tar.gz cpython-93f562c4f9a751034616068468e7dc2cfd022275.tar.bz2 |
Merged revisions 77842 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r77842 | mark.dickinson | 2010-01-30 10:08:33 +0000 (Sat, 30 Jan 2010) | 4 lines
Issue #7767: Add new C-API function PyLong_AsLongLongAndOverflow, a
long long variant of PyLong_AsLongAndOverflow. Patch by Case Van
Horsen.
........
Diffstat (limited to 'Objects/longobject.c')
-rw-r--r-- | Objects/longobject.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c index afac856..db7a91c 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -971,6 +971,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. */ @@ -1269,6 +1270,101 @@ PyLong_AsUnsignedLongLongMask(register PyObject *op) } #undef IS_LITTLE_ENDIAN +/* 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 (!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 (!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; +} + #endif /* HAVE_LONG_LONG */ #define CHECK_BINOP(v,w) \ |