[pypy-svn] r37199 - in pypy/dist/pypy: doc interpreter objspace objspace/cpy objspace/cpy/test objspace/std objspace/std/test
cfbolz at codespeak.net
cfbolz at codespeak.net
Tue Jan 23 16:14:35 CET 2007
Author: cfbolz
Date: Tue Jan 23 16:14:31 2007
New Revision: 37199
Modified:
pypy/dist/pypy/doc/objspace.txt
pypy/dist/pypy/interpreter/baseobjspace.py
pypy/dist/pypy/objspace/cpy/capi.py
pypy/dist/pypy/objspace/cpy/objspace.py
pypy/dist/pypy/objspace/cpy/test/test_objspace.py
pypy/dist/pypy/objspace/dump.py
pypy/dist/pypy/objspace/logic.py
pypy/dist/pypy/objspace/std/intobject.py
pypy/dist/pypy/objspace/std/longobject.py
pypy/dist/pypy/objspace/std/objspace.py
pypy/dist/pypy/objspace/std/test/test_intobject.py
pypy/dist/pypy/objspace/std/test/test_longobject.py
pypy/dist/pypy/objspace/thunk.py
Log:
(janzert): Add a bigint_w method to object spaces to unwrap python longs to
rbigints.
thanks a lot, janzert!
Modified: pypy/dist/pypy/doc/objspace.txt
==============================================================================
--- pypy/dist/pypy/doc/objspace.txt (original)
+++ pypy/dist/pypy/doc/objspace.txt Tue Jan 23 16:14:31 2007
@@ -160,6 +160,9 @@
**int_w(w_x):**
If w_x is an application-level integer or long which can be converted without overflow to an integer, return an interpreter-level integer. Otherwise raise TypeError or OverflowError.
+**bigint_w(w_x):**
+ If w_x is an application-level integer or long, return an interpreter-level rbigint. Otherwise raise TypeError.
+
**str_w(w_x):**
If w_x is an application-level string, return an interpreter-level string. Otherwise raise TypeError.
Modified: pypy/dist/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/dist/pypy/interpreter/baseobjspace.py (original)
+++ pypy/dist/pypy/interpreter/baseobjspace.py Tue Jan 23 16:14:31 2007
@@ -904,6 +904,7 @@
# int_w(w_ival or w_long_ival) -> ival
# float_w(w_floatval) -> floatval
# uint_w(w_ival or w_long_ival) -> r_uint_val (unsigned int value)
+# bigint_w(w_ival or w_long_ival) -> rbigint
#interpclass_w(w_interpclass_inst or w_obj) -> interpclass_inst|w_obj
# unwrap(w_x) -> x
# is_true(w_x) -> True or False
@@ -921,6 +922,7 @@
'int_w',
'float_w',
'uint_w',
+ 'bigint_w',
'interpclass_w',
'unwrap',
'is_true',
Modified: pypy/dist/pypy/objspace/cpy/capi.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/capi.py (original)
+++ pypy/dist/pypy/objspace/cpy/capi.py Tue Jan 23 16:14:31 2007
@@ -268,6 +268,19 @@
PyLong_FromUnsignedLongLong.argtypes = [c_ulonglong]
PyLong_FromUnsignedLongLong.restype = W_Object
+_PyLong_Sign = cpyapi._PyLong_Sign
+_PyLong_Sign.argtypes = [W_Object]
+_PyLong_Sign.restype = c_long
+
+_PyLong_NumBits = cpyapi._PyLong_NumBits
+_PyLong_NumBits.argtypes = [W_Object]
+_PyLong_NumBits.restype = c_size_t
+
+_PyLong_AsByteArray = cpyapi._PyLong_AsByteArray
+_PyLong_AsByteArray.argtypes = [W_Object, POINTER(c_ubyte), c_size_t,
+ c_long, c_long]
+_PyLong_AsByteArray.restype = c_long
+
# a version of PyLong_FromVoidPtr() that pretends to take a PyObject* arg
PyLong_FromVoidPtr_PYOBJ = cpyapi.PyLong_FromVoidPtr
PyLong_FromVoidPtr_PYOBJ.argtypes = [W_Object]
Modified: pypy/dist/pypy/objspace/cpy/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/objspace.py (original)
+++ pypy/dist/pypy/objspace/cpy/objspace.py Tue Jan 23 16:14:31 2007
@@ -1,6 +1,7 @@
import types
from pypy.objspace.cpy.capi import *
from pypy.objspace.cpy.capi import _PyType_Lookup
+from pypy.objspace.cpy.capi import _PyLong_Sign, _PyLong_NumBits, _PyLong_AsByteArray
from pypy.objspace.cpy.refcount import Py_Incref
from pypy.objspace.cpy.appsupport import W_AppLevel
from pypy.interpreter import baseobjspace
@@ -8,6 +9,7 @@
from pypy.interpreter.function import Function
from pypy.interpreter.typedef import GetSetProperty
from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
+from pypy.rlib.rbigint import rbigint
from pypy.rlib.objectmodel import we_are_translated, instantiate
@@ -146,6 +148,25 @@
repr = staticmethod(PyObject_Repr)
id = staticmethod(PyLong_FromVoidPtr_PYOBJ)
+ def bigint_w(self, w_obj):
+ if self.is_true(self.isinstance(w_obj, self.w_long)):
+ sign = _PyLong_Sign(w_obj)
+ #XXX Can throw exception if long larger than size_t bits
+ numbits = _PyLong_NumBits(w_obj)
+ numbytes = (numbits+1) / 8 # +1 sign bit cpython always adds
+ if (numbits+1) % 8 != 0:
+ numbytes += 1
+ ByteArray = c_ubyte * numbytes
+ cbytes = ByteArray()
+ _PyLong_AsByteArray(w_obj, cbytes, numbytes, 1, 1) # little endian, signed
+ rdigits = _cpylongarray_to_bigintarray(cbytes, numbytes, numbits, sign)
+ return rbigint(rdigits, sign)
+ elif self.is_true(self.isinstance(w_obj, self.w_int)):
+ value = self.int_w(w_obj)
+ return rbigint.fromint(value)
+ else:
+ raise OperationError(self.w_TypeError, self.wrap("Expected type int or long"))
+
def len(self, w_obj):
return self.wrap(PyObject_Size(w_obj))
@@ -335,6 +356,45 @@
w_res = w_res.force()
return w_res
+def _cpylongarray_to_bigintarray(cbytes, numbytes, numbits, sign):
+ """
+ helper function to convert an array of bytes from a cpython long to
+ the 15 bit digits needed by the rbigint implementation.
+ """
+ # convert from 2's complement to unsigned
+ if sign == -1:
+ add = 1
+ for i in xrange(numbytes):
+ cbytes[i] = (cbytes[i] ^ 0xFF) + add
+ if add and cbytes[i] != 0:
+ add = 0
+ elif add and cbytes[i] == 0:
+ cbytes[i] == 0xFF
+ # convert 8 bit digits from cpython into 15 bit digits for rbigint
+ rdigits = []
+ digitbits = 0
+ usedbits = r_uint(0) # XXX: Will break on platforms where size_t > uint
+ digit = 0
+ for i in xrange(numbytes):
+ cdigit = cbytes[i]
+ digit |= (cdigit << digitbits)
+ digitbits += 8
+ usedbits += 8
+ if digitbits >= 15: # XXX: 15 should be the same as rbigint.SHIFT
+ rdigits.append(digit & 0x7FFF) # need to mask off rbigint.SHIFT bits
+ digit = 0
+ digitbits = digitbits-15
+ usedbits -= digitbits
+ if digitbits > 0 and usedbits < numbits:
+ digit = cdigit >> (8-digitbits)
+ usedbits += digitbits
+ else:
+ # digitbits is either zero or we have used all the bits
+ # set it to zero so we don't append an extra rpython digit
+ digitbits = 0
+ if digitbits != 0:
+ rdigits.append(digit)
+ return rdigits
# Register add, sub, neg, etc...
for _name, _cname in UnaryOps.items() + BinaryOps.items():
Modified: pypy/dist/pypy/objspace/cpy/test/test_objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/test/test_objspace.py (original)
+++ pypy/dist/pypy/objspace/cpy/test/test_objspace.py Tue Jan 23 16:14:31 2007
@@ -1,6 +1,7 @@
from pypy.objspace.cpy.objspace import CPyObjSpace
from pypy.tool.pytest.appsupport import raises_w
from pypy.rlib.rarithmetic import r_longlong, r_ulonglong
+from pypy.rlib.rbigint import rbigint
def test_simple():
space = CPyObjSpace()
@@ -147,3 +148,18 @@
i2 = space.newint(42)
assert space.is_true(space.eq(i1, i2))
assert space.is_true(space.ne(space.type(i1), space.type(i2)))
+
+def test_bigint_w():
+ space = CPyObjSpace()
+ r1 = space.bigint_w(space.newlong(42))
+ assert isinstance(r1, rbigint)
+ assert r1.eq(rbigint.fromint(42))
+ # cpython digit size
+ assert space.bigint_w(space.newlong(2**8)).eq(rbigint.fromint(2**8))
+ # rpython digit size
+ assert space.bigint_w(space.newlong(2**15)).eq(rbigint.fromint(2**15))
+ # and negative numbers
+ assert space.bigint_w(space.newlong(-1)).eq(rbigint.fromint(-1))
+ assert space.bigint_w(space.newlong(-2**8)).eq(rbigint.fromint(-2**8))
+ assert space.bigint_w(space.newlong(-2**15)).eq(rbigint.fromlong(-2**15))
+
Modified: pypy/dist/pypy/objspace/dump.py
==============================================================================
--- pypy/dist/pypy/objspace/dump.py (original)
+++ pypy/dist/pypy/objspace/dump.py Tue Jan 23 16:14:31 2007
@@ -145,6 +145,7 @@
'int_w': 1,
'float_w': 1,
'uint_w': 1,
+ 'bigint_w': 1,
'interpclass_w': 1,
'unwrap': 1,
'is_true': 1,
Modified: pypy/dist/pypy/objspace/logic.py
==============================================================================
--- pypy/dist/pypy/objspace/logic.py (original)
+++ pypy/dist/pypy/objspace/logic.py Tue Jan 23 16:14:31 2007
@@ -69,6 +69,7 @@
'int_w': 1,
'float_w': 1,
'uint_w': 1,
+ 'bigint_w': 1,
'interpclass_w': 1,
'unwrap': 1,
'is_true': 1,
Modified: pypy/dist/pypy/objspace/std/intobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/intobject.py (original)
+++ pypy/dist/pypy/objspace/std/intobject.py Tue Jan 23 16:14:31 2007
@@ -1,6 +1,7 @@
from pypy.objspace.std.objspace import *
from pypy.objspace.std.noneobject import W_NoneObject
from pypy.rlib.rarithmetic import ovfcheck, ovfcheck_lshift, LONG_BIT, r_uint
+from pypy.rlib.rbigint import rbigint
from pypy.objspace.std.inttype import wrapint
"""
@@ -46,6 +47,9 @@
else:
return r_uint(intval)
+def bigint_w__Int(space, w_int1):
+ return rbigint.fromint(w_int1.intval)
+
def repr__Int(space, w_int1):
a = w_int1.intval
res = str(a)
Modified: pypy/dist/pypy/objspace/std/longobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/longobject.py (original)
+++ pypy/dist/pypy/objspace/std/longobject.py Tue Jan 23 16:14:31 2007
@@ -104,6 +104,9 @@
raise OperationError(space.w_OverflowError, space.wrap(
"long int too large to convert to unsigned int"))
+def bigint_w__Long(space, w_value):
+ return w_value.num
+
def repr__Long(space, w_long):
return space.wrap(w_long.num.repr())
Modified: pypy/dist/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/std/objspace.py (original)
+++ pypy/dist/pypy/objspace/std/objspace.py Tue Jan 23 16:14:31 2007
@@ -563,6 +563,7 @@
str_w = StdObjSpaceMultiMethod('str_w', 1, []) # returns an unwrapped string
float_w = StdObjSpaceMultiMethod('float_w', 1, []) # returns an unwrapped float
uint_w = StdObjSpaceMultiMethod('uint_w', 1, []) # returns an unwrapped unsigned int (r_uint)
+ bigint_w = StdObjSpaceMultiMethod('bigint_w', 1, []) # returns an unwrapped rbigint
marshal_w = StdObjSpaceMultiMethod('marshal_w', 1, [], extra_args=['marshaller'])
log = StdObjSpaceMultiMethod('log', 1, [], extra_args=['base'])
Modified: pypy/dist/pypy/objspace/std/test/test_intobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_intobject.py (original)
+++ pypy/dist/pypy/objspace/std/test/test_intobject.py Tue Jan 23 16:14:31 2007
@@ -3,6 +3,7 @@
from pypy.objspace.std import intobject as iobj
from pypy.objspace.std.objspace import FailedToImplement
from pypy.rlib.rarithmetic import r_uint
+from pypy.rlib.rbigint import rbigint
class TestW_IntObject:
@@ -34,6 +35,11 @@
assert space.uint_w(space.wrap(42)) == 42
assert isinstance(space.uint_w(space.wrap(42)), r_uint)
space.raises_w(space.w_ValueError, space.uint_w, space.wrap(-1))
+
+ def test_bigint_w(self):
+ space = self.space
+ assert isinstance(space.bigint_w(space.wrap(42)), rbigint)
+ assert space.bigint_w(space.wrap(42)).eq(rbigint.fromint(42))
def test_repr(self):
x = 1
Modified: pypy/dist/pypy/objspace/std/test/test_longobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/test/test_longobject.py (original)
+++ pypy/dist/pypy/objspace/std/test/test_longobject.py Tue Jan 23 16:14:31 2007
@@ -5,6 +5,16 @@
from pypy.objspace.std.objspace import FailedToImplement
from pypy.interpreter.error import OperationError
from pypy.rlib.rarithmetic import r_uint
+from pypy.rlib.rbigint import rbigint
+
+class TestW_LongObject:
+
+ def test_bigint_w(self):
+ space = self.space
+ fromlong = lobj.W_LongObject.fromlong
+ assert isinstance(space.bigint_w(fromlong(42)), rbigint)
+ assert space.bigint_w(fromlong(42)).eq(rbigint.fromint(42))
+ assert space.bigint_w(fromlong(-1)).eq(rbigint.fromint(-1))
class AppTestLong:
def test_add(self):
Modified: pypy/dist/pypy/objspace/thunk.py
==============================================================================
--- pypy/dist/pypy/objspace/thunk.py (original)
+++ pypy/dist/pypy/objspace/thunk.py Tue Jan 23 16:14:31 2007
@@ -100,6 +100,7 @@
'int_w': 1,
'float_w': 1,
'uint_w': 1,
+ 'bigint_w': 1,
'interpclass_w': 1,
'unwrap': 1,
'is_true': 1,
More information about the Pypy-commit
mailing list