[Python-checkins] r77843 - in python/branches/py3k: Doc/c-api/long.rst Include/longobject.h Misc/NEWS Modules/_testcapimodule.c Objects/longobject.c

mark.dickinson python-checkins at python.org
Sat Jan 30 11:30:16 CET 2010


Author: mark.dickinson
Date: Sat Jan 30 11:30:15 2010
New Revision: 77843

Log:
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.
........


Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Doc/c-api/long.rst
   python/branches/py3k/Include/longobject.h
   python/branches/py3k/Misc/NEWS
   python/branches/py3k/Modules/_testcapimodule.c
   python/branches/py3k/Objects/longobject.c

Modified: python/branches/py3k/Doc/c-api/long.rst
==============================================================================
--- python/branches/py3k/Doc/c-api/long.rst	(original)
+++ python/branches/py3k/Doc/c-api/long.rst	Sat Jan 30 11:30:15 2010
@@ -130,6 +130,19 @@
    be ``0``.
 
 
+.. 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:: 3.2
+
+
 .. cfunction:: Py_ssize_t PyLong_AsSsize_t(PyObject *pylong)
 
    .. index::

Modified: python/branches/py3k/Include/longobject.h
==============================================================================
--- python/branches/py3k/Include/longobject.h	(original)
+++ python/branches/py3k/Include/longobject.h	Sat Jan 30 11:30:15 2010
@@ -62,6 +62,7 @@
 PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLong(PyObject *);
 PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(PyObject *);
 PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLongMask(PyObject *);
+PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLongAndOverflow(PyObject *, int *);
 #endif /* HAVE_LONG_LONG */
 
 PyAPI_FUNC(PyObject *) PyLong_FromString(char *, char **, int);

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Sat Jan 30 11:30:15 2010
@@ -192,6 +192,9 @@
 C-API
 -----
 
+- Issue #7767: New function PyLong_AsLongLongAndOverflow added,
+  analogous to PyLong_AsLongAndOverflow.
+
 - Make PyUnicode_CompareWithASCIIString return not equal if the Python string
   has '\0' at the end.
 

Modified: python/branches/py3k/Modules/_testcapimodule.c
==============================================================================
--- python/branches/py3k/Modules/_testcapimodule.c	(original)
+++ python/branches/py3k/Modules/_testcapimodule.c	Sat Jan 30 11:30:15 2010
@@ -524,6 +524,171 @@
 	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
    for both long and int arguments.  The test may leak a little memory if
    it fails.
@@ -1791,6 +1956,8 @@
 	{"getargs_L",		getargs_L,			 METH_VARARGS},
 	{"getargs_K",		getargs_K,			 METH_VARARGS},
 	{"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},
 	{"codec_incrementalencoder",
 	 (PyCFunction)codec_incrementalencoder,	 METH_VARARGS},

Modified: python/branches/py3k/Objects/longobject.c
==============================================================================
--- python/branches/py3k/Objects/longobject.c	(original)
+++ python/branches/py3k/Objects/longobject.c	Sat Jan 30 11:30:15 2010
@@ -971,6 +971,7 @@
  */
 
 #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 @@
 }
 #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) \


More information about the Python-checkins mailing list