[Python-checkins] r76963 - in python/trunk: Doc/c-api/long.rst Include/longobject.h Misc/NEWS Modules/_testcapimodule.c Objects/longobject.c
mark.dickinson
python-checkins at python.org
Mon Dec 21 12:21:26 CET 2009
Author: mark.dickinson
Date: Mon Dec 21 12:21:25 2009
New Revision: 76963
Log:
Issue #7528: Backport PyLong_AsLongAndOverflow from py3k to trunk.
Thanks Case Van Horsen for the patch.
Modified:
python/trunk/Doc/c-api/long.rst
python/trunk/Include/longobject.h
python/trunk/Misc/NEWS
python/trunk/Modules/_testcapimodule.c
python/trunk/Objects/longobject.c
Modified: python/trunk/Doc/c-api/long.rst
==============================================================================
--- python/trunk/Doc/c-api/long.rst (original)
+++ python/trunk/Doc/c-api/long.rst Mon Dec 21 12:21:25 2009
@@ -133,6 +133,19 @@
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::
Modified: python/trunk/Include/longobject.h
==============================================================================
--- python/trunk/Include/longobject.h (original)
+++ python/trunk/Include/longobject.h Mon Dec 21 12:21:25 2009
@@ -21,6 +21,7 @@
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 *);
Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS (original)
+++ python/trunk/Misc/NEWS Mon Dec 21 12:21:25 2009
@@ -1648,6 +1648,8 @@
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.
Modified: python/trunk/Modules/_testcapimodule.c
==============================================================================
--- python/trunk/Modules/_testcapimodule.c (original)
+++ python/trunk/Modules/_testcapimodule.c Mon Dec 21 12:21:25 2009
@@ -358,6 +358,75 @@
#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 @@
{"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},
Modified: python/trunk/Objects/longobject.c
==============================================================================
--- python/trunk/Objects/longobject.c (original)
+++ python/trunk/Objects/longobject.c Mon Dec 21 12:21:25 2009
@@ -223,53 +223,123 @@
#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;
+
+ 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;
+ }
}
- /* 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;
+
+ 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 */
+ }
}
- else if (sign < 0 && x == PY_ABS_LONG_MIN) {
- return LONG_MIN;
+ exit:
+ if (do_decref) {
+ Py_DECREF(vv);
}
- /* else overflow */
+ return res;
+}
- overflow:
- PyErr_SetString(PyExc_OverflowError,
- "long int too large to convert to int");
- return -1;
+/* 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.
More information about the Python-checkins
mailing list