summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2008-04-15 21:42:42 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2008-04-15 21:42:42 (GMT)
commit7ab6be216af6fccae655bd5402ae0ad22447f37a (patch)
tree22503e2e936f131380051209bb1905c8d9541649 /Objects
parent32dde22186efbbfcfb275ac9542b3e62a9b5cf1b (diff)
downloadcpython-7ab6be216af6fccae655bd5402ae0ad22447f37a.zip
cpython-7ab6be216af6fccae655bd5402ae0ad22447f37a.tar.gz
cpython-7ab6be216af6fccae655bd5402ae0ad22447f37a.tar.bz2
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.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/longobject.c65
1 files changed, 53 insertions, 12 deletions
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 1d4b502..44b040c 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -1099,13 +1099,39 @@ PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG ival)
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 @@ PyLong_FromSsize_t(Py_ssize_t ival)
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.