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

Reply via email to