Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r81579:af91853285d1
Date: 2016-01-05 13:52 +0100
http://bitbucket.org/pypy/pypy/changeset/af91853285d1/

Log:    Add __pypy__.decode_long(), an app-level interface to
        rbigint.frombytes(). Use it in the pickle.py module.

diff --git a/lib-python/2.7/pickle.py b/lib-python/2.7/pickle.py
--- a/lib-python/2.7/pickle.py
+++ b/lib-python/2.7/pickle.py
@@ -1376,6 +1376,7 @@
 
 def decode_long(data):
     r"""Decode a long from a two's complement little-endian binary string.
+    This is overriden on PyPy by a RPython version that has linear complexity.
 
     >>> decode_long('')
     0L
@@ -1402,6 +1403,11 @@
         n -= 1L << (nbytes * 8)
     return n
 
+try:
+    from __pypy__ import decode_long
+except ImportError:
+    pass
+
 # Shorthands
 
 try:
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -89,6 +89,7 @@
         'set_code_callback'         : 'interp_magic.set_code_callback',
         'save_module_content_for_future_reload':
                           'interp_magic.save_module_content_for_future_reload',
+        'decode_long'               : 'interp_magic.decode_long',
     }
     if sys.platform == 'win32':
         interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp'
diff --git a/pypy/module/__pypy__/interp_magic.py 
b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -1,4 +1,4 @@
-from pypy.interpreter.error import OperationError, wrap_oserror
+from pypy.interpreter.error import OperationError, oefmt, wrap_oserror
 from pypy.interpreter.gateway import unwrap_spec
 from pypy.interpreter.pycode import CodeHookCache
 from pypy.interpreter.pyframe import PyFrame
@@ -158,4 +158,13 @@
     if space.is_none(w_callable):
         cache._code_hook = None
     else:
-        cache._code_hook = w_callable
\ No newline at end of file
+        cache._code_hook = w_callable
+
+@unwrap_spec(string=str, byteorder=str, signed=int)
+def decode_long(space, string, byteorder='little', signed=1):
+    from rpython.rlib.rbigint import rbigint, InvalidEndiannessError
+    try:
+        result = rbigint.frombytes(string, byteorder, bool(signed))
+    except InvalidEndiannessError:
+        raise oefmt(space.w_ValueError, "invalid byteorder argument")
+    return space.newlong_from_rbigint(result)
diff --git a/pypy/module/__pypy__/test/test_magic.py 
b/pypy/module/__pypy__/test/test_magic.py
--- a/pypy/module/__pypy__/test/test_magic.py
+++ b/pypy/module/__pypy__/test/test_magic.py
@@ -30,4 +30,20 @@
 """ in d
         finally:
             __pypy__.set_code_callback(None)
-        assert d['f'].__code__ in l
\ No newline at end of file
+        assert d['f'].__code__ in l
+
+    def test_decode_long(self):
+        from __pypy__ import decode_long
+        assert decode_long('') == 0
+        assert decode_long('\xff\x00') == 255
+        assert decode_long('\xff\x7f') == 32767
+        assert decode_long('\x00\xff') == -256
+        assert decode_long('\x00\x80') == -32768
+        assert decode_long('\x80') == -128
+        assert decode_long('\x7f') == 127
+        assert decode_long('\x55' * 97) == (1 << (97 * 8)) // 3
+        assert decode_long('\x00\x80', 'big') == 128
+        assert decode_long('\xff\x7f', 'little', False) == 32767
+        assert decode_long('\x00\x80', 'little', False) == 32768
+        assert decode_long('\x00\x80', 'little', True) == -32768
+        raises(ValueError, decode_long, '', 'foo')
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to