diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2008-04-15 21:42:42 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2008-04-15 21:42:42 (GMT) |
commit | 7ab6be216af6fccae655bd5402ae0ad22447f37a (patch) | |
tree | 22503e2e936f131380051209bb1905c8d9541649 /Objects | |
parent | 32dde22186efbbfcfb275ac9542b3e62a9b5cf1b (diff) | |
download | cpython-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.c | 65 |
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. |