[pypy-svn] r27013 - in pypy/dist/pypy/rpython: . lltypesystem rctypes rctypes/test

ac at codespeak.net ac at codespeak.net
Tue May 9 18:29:38 CEST 2006


Author: ac
Date: Tue May  9 18:29:35 2006
New Revision: 27013

Added:
   pypy/dist/pypy/rpython/rctypes/rcarithmetic.py   (contents, props changed)
   pypy/dist/pypy/rpython/rctypes/test/test_rcarithmetic.py   (contents, props changed)
Modified:
   pypy/dist/pypy/rpython/lltypesystem/lltype.py
   pypy/dist/pypy/rpython/rarithmetic.py
   pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py
Log:
(pedronis, arre)
Generalized rarithmetic to really support various integer sizes.
Add rcarrithmetic that defines primitive types needed for ctypes.
Generalized how to build Primitive lltypes for numbers.
Added (skipped) test for missing support of proper rctypes.



Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lltype.py	Tue May  9 18:29:35 2006
@@ -1,5 +1,5 @@
 import py
-from pypy.rpython.rarithmetic import r_uint, r_ulonglong, r_longlong
+from pypy.rpython.rarithmetic import r_int, r_uint, r_ulonglong, r_longlong, base_int
 from pypy.rpython.objectmodel import Symbolic
 from pypy.tool.uid import Hashable
 from pypy.tool.tls import tlsobject
@@ -480,16 +480,25 @@
 
     _example = _defl
 
+_numbertypes = {int: Primitive("Signed", 0)}
+_numbertypes[r_int] = _numbertypes[int]
+
+def build_number(name, type):
+    try:
+        return _numbertypes[type]
+    except KeyError:
+        pass
+    if name is None:
+        raise ValueError('No matching lowlevel type for %r'%type)
+    number = _numbertypes[type] = Primitive(name, type())
+    return number
+
+Signed   = build_number("Signed", int)
+Unsigned = build_number("Unsigned", r_uint)
+SignedLongLong = build_number("SignedLongLong", r_longlong)
+UnsignedLongLong = build_number("UnsignedLongLong", r_ulonglong)
+Float    = build_number("Float", float)
 
-Signed   = Primitive("Signed", 0)
-Unsigned = Primitive("Unsigned", r_uint(0))
-if maxint == 2**31-1:
-    SignedLongLong = Primitive("SignedLongLong", r_longlong(0))
-    UnsignedLongLong = Primitive("UnsignedLongLong", r_ulonglong(0))
-else:
-    SignedLongLong = Signed
-    UnsignedLongLong = Unsigned
-Float    = Primitive("Float", 0.0)
 Char     = Primitive("Char", '\x00')
 Bool     = Primitive("Bool", False)
 Void     = Primitive("Void", None)
@@ -539,12 +548,8 @@
             return Signed
         if tp is bool:
             return Bool
-        if tp is r_uint:
-            return Unsigned
-        if tp is r_ulonglong:
-            return UnsignedLongLong
-        if tp is r_longlong:
-            return SignedLongLong
+        if issubclass(tp, base_int):
+            return build_number(None, tp)
         if tp is float:
             return Float
         if tp is str:

Modified: pypy/dist/pypy/rpython/rarithmetic.py
==============================================================================
--- pypy/dist/pypy/rpython/rarithmetic.py	(original)
+++ pypy/dist/pypy/rpython/rarithmetic.py	Tue May  9 18:29:35 2006
@@ -17,8 +17,10 @@
          catering to 2.3/2.4 differences about <<
 ovfcheck_float_to_int
          convert to an integer or raise OverflowError
-r_ushort like r_uint but half word size
-r_ulong  like r_uint but double word size
+r_longlong
+         like r_int but double word size
+r_ulonglong
+         like r_uint but double word size
 
 These are meant to be erased by translation, r_uint
 in the process should mark unsigned values, ovfcheck should
@@ -81,6 +83,17 @@
         return int(intp)
     raise OverflowError
 
+def compute_restype(self_type, other_type):
+    if other_type in (int, long):
+        return self_type
+    if self_type.SIGNED != other_type.SIGNED:
+        raise TypeError('Can not mix %r and %r'%(self_type, other_type))
+    if self_type.BITS > other_type.BITS:
+        return self_type
+    if self_type.BITS < other_type.BITS:
+        return other_type
+    return self_type
+
 
 class base_int(long):
     """ fake unsigned integer implementation """
@@ -91,7 +104,15 @@
         if one argument is int or long, the other type wins.
         otherwise, produce the largest class to hold the result.
         """
-        return self.typemap[ type(self), type(other) ](value)
+        self_type = type(self)
+        other_type = type(other)
+        try:
+            return self.typemap[ self_type, other_type ](value)
+        except KeyError:
+            pass
+        restype = compute_restype(self_type, other_type)
+        self.typemap[self_type, other_type] = restype
+        return restype(value)
 
     def __new__(klass, val):
         if klass is base_int:
@@ -225,7 +246,8 @@
         return self._widen(other, res)
 
 class signed_int(base_int):
-    def __new__(klass, val):
+    SIGNED = True
+    def __new__(klass, val=0):
         if val > klass.MASK>>1 or val < -(klass.MASK>>1)-1:
             raise OverflowError("%s does not fit in signed %d-bit integer"%(val, klass.BITS))
         if val < 0:
@@ -234,53 +256,33 @@
     typemap = {}
 
 class unsigned_int(base_int):
-    def __new__(klass, val):
+    SIGNED = False
+    def __new__(klass, val=0):
         return super(unsigned_int, klass).__new__(klass, val & klass.MASK)
     typemap = {}
 
-class r_int(signed_int):
-    MASK = LONG_MASK
-    BITS = LONG_BIT
-
+_inttypes = {}
 
-class r_uint(unsigned_int):
-    MASK = LONG_MASK
-    BITS = LONG_BIT
-
-
-if LONG_BIT == 64:
-    r_ulonglong = r_uint
-    r_longlong = r_int
-else:
-    assert LONG_BIT == 32
-    
-    class r_longlong(signed_int):
-        BITS = LONG_BIT * 2
-        MASK = 2**BITS-1
-
-    class r_ulonglong(unsigned_int):
-        BITS = LONG_BIT * 2
-        MASK = 2**BITS-1
-
-def setup_typemap(typemap, types):
-    for left in types:
-        for right in types:
-            if left in (int, long):
-                restype = right
-            elif right in (int, long):
-                restype = left
-            else:
-                if left.BITS > right.BITS:
-                    restype = left
-                else:
-                    restype = right
-            if restype not in (int, long):
-                typemap[ left, right ] = restype
+def build_int(name, sign, bits):
+    sign = bool(sign)
+    try:
+        return _inttypes[sign, bits]
+    except KeyError:
+        pass
+    if sign:
+        int_type = signed_int
+    else:
+        int_type = unsigned_int
+    mask = (1 << bits) - 1
+    ret = _inttypes[sign, bits] = type(name, (int_type,), {'MASK': mask,
+                                                           'BITS': bits})
+    return ret
 
-setup_typemap(unsigned_int.typemap, (int, long, r_uint, r_ulonglong))
-setup_typemap(signed_int.typemap, (int, long, r_int, r_longlong))
+r_int = build_int('r_int', True, LONG_BIT)
+r_uint = build_int('r_uint', False, LONG_BIT)
 
-del setup_typemap
+r_longlong = build_int('r_longlong', True, 64)
+r_ulonglong = build_int('r_ulonglong', False, 64)
 
 # string -> float helper
 

Added: pypy/dist/pypy/rpython/rctypes/rcarithmetic.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/rctypes/rcarithmetic.py	Tue May  9 18:29:35 2006
@@ -0,0 +1,27 @@
+from pypy.rpython import rarithmetic
+from pypy.rpython.lltypesystem import lltype
+import ctypes
+
+def c_type_size(c_type):
+    bits = 0
+    while c_type(1<<bits).value != 0:
+        bits += 1
+    sign = c_type(-1).value < 0
+    return sign, bits
+
+def setup():
+    for _name in 'byte short int long longlong'.split():
+        for name in (_name, 'u' + _name):
+            c_type = getattr(ctypes, 'c_' + name)
+            sign, bits = c_type_size(c_type)
+            inttype = rarithmetic.build_int('rc' + name, sign, bits)
+            globals()['rc'+name] = inttype 
+            if name[0] == 'u':
+                llname = 'CU' + name[1:].title()
+            else:
+                llname = 'C' + name.title()
+            globals()[llname] = lltype.build_number(llname, inttype)
+setup()
+del setup
+
+

Added: pypy/dist/pypy/rpython/rctypes/test/test_rcarithmetic.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/rctypes/test/test_rcarithmetic.py	Tue May  9 18:29:35 2006
@@ -0,0 +1,32 @@
+import py.test
+from pypy.rpython.rctypes.rcarithmetic import *
+from pypy.rpython.lltypesystem import lltype
+from pypy.rpython import rarithmetic
+
+def test_signedness():
+    assert rcbyte(-1) < 0
+    assert rcubyte(-1) > 0
+
+def test_promotion():
+    assert type(rcbyte(1) + 1) is rcbyte
+    assert type(1 + rcbyte(1)) is rcbyte
+    
+    assert type(rcbyte(1) + rcshort(1)) is rcshort
+    assert type(rcshort(1) + rcbyte(1)) is rcshort
+
+    py.test.raises(TypeError, 'rcubyte(1) + rcshort(1)')
+    py.test.raises(TypeError, 'rcshort(1) + rcubyte(1)')
+
+    
+def test_typeof():
+    assert lltype.typeOf(rarithmetic.r_int(0)) == lltype.Signed
+    assert lltype.typeOf(rclong(0)) == lltype.Signed
+    assert lltype.Signed == CLong
+    assert lltype.typeOf(rarithmetic.r_uint(0)) == lltype.Unsigned
+    assert lltype.typeOf(rculong(0)) == lltype.Unsigned
+    assert lltype.Unsigned == CULong
+
+    assert lltype.typeOf(rcbyte(0)) == CByte
+    assert lltype.typeOf(rcshort(0)) == CShort
+
+    assert lltype.typeOf(rcushort(0)) == CUShort

Modified: pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py	(original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_rprimitive.py	Tue May  9 18:29:35 2006
@@ -15,7 +15,7 @@
 
 from ctypes import c_char, c_byte, c_ubyte, c_short, c_ushort, c_int, c_uint
 from ctypes import c_long, c_ulong, c_longlong, c_ulonglong, c_float
-from ctypes import c_double, c_wchar, c_char_p, pointer
+from ctypes import c_double, c_wchar, c_char_p, pointer, sizeof
 
 class Test_annotation:
     def test_simple(self):
@@ -319,3 +319,11 @@
 
         fn = compile(access_c_float, [])
         assert fn() == 5.2
+
+    def test_compile_short(self):
+        py.test.skip('In-progress')
+        def sizeof_c_short():
+            return sizeof(c_short)
+        fn = compile(sizeof_c_short, [])
+        assert fn() == sizeof(c_short)
+        



More information about the Pypy-commit mailing list