[Python-3000-checkins] r62356 - in python/branches/py3k: Misc/NEWS Objects/longobject.c

mark.dickinson python-3000-checkins at python.org
Tue Apr 15 23:42:42 CEST 2008


Author: mark.dickinson
Date: Tue Apr 15 23:42:42 2008
New Revision: 62356

Log:
PyLong_FromSsize_t was incorrect when sizeof(size_t) > sizeof(long);
rewrite it so that it doesn't care about relative sizes of size_t,
long and long long.

The rewrite is modeled on PyLong_FromLong, instead of using
PyLong_FromByteArray;  this makes the algorithm simpler and
more direct, and possibly also slightly faster.


Modified:
   python/branches/py3k/Misc/NEWS
   python/branches/py3k/Objects/longobject.c

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Tue Apr 15 23:42:42 2008
@@ -12,6 +12,9 @@
 Core and Builtins
 -----------------
 
+- Fix misbehaviour of PyLong_FromSsize_t on systems where sizeof(size_t) >
+  sizeof(long).
+
 - Issue #2221: Corrected a SystemError "error return without exception set",
   when the code executed by exec() raises an exception, and sys.stdout.flush()
   also raises an error.

Modified: python/branches/py3k/Objects/longobject.c
==============================================================================
--- python/branches/py3k/Objects/longobject.c	(original)
+++ python/branches/py3k/Objects/longobject.c	Tue Apr 15 23:42:42 2008
@@ -1099,13 +1099,39 @@
 PyObject *
 PyLong_FromSsize_t(Py_ssize_t ival)
 {
-	Py_ssize_t bytes = ival;
-	int one = 1;
-	if (ival < PyLong_BASE)
-		return PyLong_FromLong(ival);
-	return _PyLong_FromByteArray(
-			(unsigned char *)&bytes,
-			SIZEOF_SIZE_T, IS_LITTLE_ENDIAN, 1);
+	PyLongObject *v;
+	size_t abs_ival;
+	size_t t;  /* unsigned so >> doesn't propagate sign bit */
+	int ndigits = 0;
+	int negative = 0;
+
+	CHECK_SMALL_INT(ival);
+	if (ival < 0) {
+		/* avoid signed overflow when ival = SIZE_T_MIN */
+		abs_ival = (size_t)(-1-ival)+1;
+		negative = 1;
+	}
+	else {
+		abs_ival = (size_t)ival;
+	}
+
+	/* Count the number of Python digits. */
+	t = abs_ival;
+	while (t) {
+		++ndigits;
+		t >>= PyLong_SHIFT;
+	}
+	v = _PyLong_New(ndigits);
+	if (v != NULL) {
+		digit *p = v->ob_digit;
+		Py_SIZE(v) = negative ? -ndigits : ndigits;
+		t = abs_ival;
+		while (t) {
+			*p++ = (digit)(t & PyLong_MASK);
+			t >>= PyLong_SHIFT;
+		}
+	}
+	return (PyObject *)v;
 }
 
 /* Create a new long int object from a C size_t. */
@@ -1113,13 +1139,28 @@
 PyObject *
 PyLong_FromSize_t(size_t ival)
 {
-	size_t bytes = ival;
-	int one = 1;
+	PyLongObject *v;
+	size_t t;
+	int ndigits = 0;
+
 	if (ival < PyLong_BASE)
 		return PyLong_FromLong(ival);
-	return _PyLong_FromByteArray(
-			(unsigned char *)&bytes,
-			SIZEOF_SIZE_T, IS_LITTLE_ENDIAN, 0);
+	/* Count the number of Python digits. */
+	t = ival;
+	while (t) {
+		++ndigits;
+		t >>= PyLong_SHIFT;
+	}
+	v = _PyLong_New(ndigits);
+	if (v != NULL) {
+		digit *p = v->ob_digit;
+		Py_SIZE(v) = ndigits;
+		while (ival) {
+			*p++ = (digit)(ival & PyLong_MASK);
+			ival >>= PyLong_SHIFT;
+		}
+	}
+	return (PyObject *)v;
 }
 
 /* Get a C PY_LONG_LONG int from a long int object.


More information about the Python-3000-checkins mailing list