Author: Amaury Forgeot d'Arc <[email protected]>
Branch: py3k
Changeset: r59112:84f2fae1b947
Date: 2012-11-28 23:35 +0100
http://bitbucket.org/pypy/pypy/changeset/84f2fae1b947/
Log: Improve long.to_bytes(). It's not quadratic anymore, but my
implementation of result[::-1] is probably not very efficient.
diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -2,6 +2,7 @@
from pypy.rlib.rarithmetic import ovfcheck, r_longlong, widen, is_valid_int
from pypy.rlib.rarithmetic import most_neg_value_of_same_type
from pypy.rlib.rfloat import isinf, isnan
+from pypy.rlib.rstring import StringBuilder
from pypy.rlib.debug import make_sure_not_resized, check_regular_int
from pypy.rlib.objectmodel import we_are_translated, specialize
from pypy.rlib import jit
@@ -317,7 +318,7 @@
imax = self.numdigits()
accum = _widen_digit(0)
accumbits = 0
- digits = ''
+ result = StringBuilder(nbytes)
carry = 1
for i in range(0, imax):
@@ -342,10 +343,7 @@
raise OverflowError()
j += 1
- if bswap:
- digits = chr(accum & 0xFF) + digits
- else:
- digits += chr(accum & 0xFF)
+ result.append(chr(accum & 0xFF))
accum >>= 8
accumbits -= 8
@@ -358,31 +356,26 @@
# Add a sign bit
accum |= (~_widen_digit(0)) << accumbits;
- if bswap:
- digits = chr(accum & 0xFF) + digits
- else:
- digits += chr(accum & 0xFF)
+ result.append(chr(accum & 0xFF))
- elif j == nbytes and nbytes > 0 and signed:
+ if j < nbytes:
+ signbyte = 0xFF if self.sign == -1 else 0
+ result.append_multiple_char(chr(signbyte), nbytes - j)
+
+ digits = result.build()
+
+ if j == nbytes and nbytes > 0 and signed:
# If not already set, we cannot contain the sign bit
- assert len(digits) > 0
- if bswap:
- msb = digits[0]
- else:
- msb = digits[-1]
-
+ msb = digits[-1]
if (self.sign == -1) != (ord(msb) >= 0x80):
raise OverflowError()
- signbyte = 0xFF if self.sign == -1 else 0
- while j < nbytes:
- # Set INFINITE signbits!
- if bswap:
- digits = chr(signbyte) + digits
- else:
- digits += chr(signbyte)
- j += 1
-
+ if bswap:
+ # Bah, this is very inefficient. At least it's not
+ # quadratic.
+ length = len(digits)
+ if length >= 0:
+ digits = ''.join([digits[i] for i in range(length-1, -1, -1)])
return digits
@jit.elidable
diff --git a/pypy/rlib/test/test_rbigint.py b/pypy/rlib/test/test_rbigint.py
--- a/pypy/rlib/test/test_rbigint.py
+++ b/pypy/rlib/test/test_rbigint.py
@@ -784,6 +784,8 @@
def test_tobytes(self):
assert rbigint.fromint(0).tobytes(1, 'big', signed=True) == '\x00'
+ assert rbigint.fromint(1).tobytes(2, 'big', signed=True) == '\x00\x01'
+ raises(OverflowError, rbigint.fromint(255).tobytes, 1, 'big',
signed=True)
assert rbigint.fromint(-129).tobytes(2, 'big', signed=True) ==
'\xff\x7f'
assert rbigint.fromint(-129).tobytes(2, 'little', signed=True) ==
'\x7f\xff'
assert rbigint.fromint(65535).tobytes(3, 'big', signed=True) ==
'\x00\xff\xff'
@@ -794,3 +796,4 @@
raises(InvalidEndiannessError, i.tobytes, 3, 'foo', signed=True)
raises(InvalidSignednessError, i.tobytes, 3, 'little', signed=False)
raises(OverflowError, i.tobytes, 2, 'little', signed=True)
+
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit