summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2010-01-30 10:08:33 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2010-01-30 10:08:33 (GMT)
commita36507c64cd8d299749c758503b0951070e202f8 (patch)
tree0b90f9b4ef76013d53300ba7de85a715a3aa958e /Objects
parenta2d465374099c582ef9bc042c2fe1be4776ee641 (diff)
downloadcpython-a36507c64cd8d299749c758503b0951070e202f8.zip
cpython-a36507c64cd8d299749c758503b0951070e202f8.tar.gz
cpython-a36507c64cd8d299749c758503b0951070e202f8.tar.bz2
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')
-rw-r--r--Objects/longobject.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 51442d3..4290f4e 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -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 */