Commits

Amaury Forgeot d'Arc committed 6d32eeb

Implement a basic version of long.from_bytes,
it's enough for the random module.
Also attach it to 'int', until these types are unified...

Comments (0)

Files changed (4)

pypy/objspace/std/inttype.py

         val >>= 1
     return space.wrap(bits)
 
+@gateway.unwrap_spec(s='bufferstr', byteorder=str)
+def descr_from_bytes(space, w_cls, s, byteorder):
+    from pypy.objspace.std.longtype import descr_from_bytes
+    return descr_from_bytes(space, space.w_long, s)
 
 def wrapint(space, x):
     if space.config.objspace.std.withsmallint:
     denominator = typedef.GetSetProperty(descr_get_denominator),
     real = typedef.GetSetProperty(descr_get_real),
     imag = typedef.GetSetProperty(descr_get_imag),
+    from_bytes = gateway.interp2app(descr_from_bytes, as_classmethod=True),
 )
 int_typedef.registermethods(globals())

pypy/objspace/std/longtype.py

         raise OperationError(space.w_OverflowError,
                              space.wrap("too many digits in integer"))
 
+@gateway.unwrap_spec(s='bufferstr', byteorder=str)
+def descr_from_bytes(space, w_cls, s, byteorder):
+    from pypy.rlib.rbigint import rbigint
+    bigint = rbigint.frombytes(s)
+    from pypy.objspace.std.longobject import W_LongObject
+    w_obj = space.allocate_instance(W_LongObject, w_cls)
+    W_LongObject.__init__(w_obj, bigint)
+    return w_obj
+
 # ____________________________________________________________
 
 long_typedef = StdTypeDef("long",
     real = typedef.GetSetProperty(descr_get_real),
     imag = typedef.GetSetProperty(descr_get_imag),
     bit_length = gateway.interp2app(bit_length),
+    from_bytes = gateway.interp2app(descr_from_bytes, as_classmethod=True),
 )
 long_typedef.registermethods(globals())

pypy/objspace/std/test/test_longobject.py

         assert (-1<<40).bit_length() == 41
         assert ((2**31)-1).bit_length() == 31
 
+    def test_from_bytes(self):
+        assert long.from_bytes(b'c', 'little') == 99
+        assert long.from_bytes(b'\x01\x01', 'little') == 257
 
     def test_negative_zero(self):
         x = eval("-0L")

pypy/rlib/rbigint.py

         # then modify the result.
         return _decimalstr_to_bigint(s)
 
+    @staticmethod
+    def frombytes(s):
+        accum = 0
+        accumbits = 0
+        digits = []
+        for ch in s:
+            c = ord(ch)
+            accum <<= 8
+            accum |= c
+            accumbits += 8
+            if accumbits >= SHIFT:
+                digits.append(_store_digit(accum & MASK))
+                accum >>= SHIFT
+                accumbits -= SHIFT
+        if accumbits:
+            digits.append(_store_digit(accum))
+        return rbigint(digits, 1)
+
     @jit.elidable
     def toint(self):
         """