[pypy-svn] r25727 - in pypy/dist/pypy: annotation rpython/lltypesystem rpython/lltypesystem/test

arigo at codespeak.net arigo at codespeak.net
Wed Apr 12 19:26:08 CEST 2006


Author: arigo
Date: Wed Apr 12 19:26:06 2006
New Revision: 25727

Modified:
   pypy/dist/pypy/annotation/builtin.py
   pypy/dist/pypy/rpython/lltypesystem/llmemory.py
   pypy/dist/pypy/rpython/lltypesystem/lltype.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py
   pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py
Log:
Add a new lltype function: cast_subarray_pointer().  Allows casting from
a regular Array to a FixedSizeArray that represents a slice of the
original Array.  (Motivation: rctypes.)

Implementation-wise, this requires a new class _subarray in lltype.py.
There is no new ll operation to support this, as it is rare and we
shouldn't burden the back-end about it.  Instead, it can be done with
a sequence of address manipulations.



Modified: pypy/dist/pypy/annotation/builtin.py
==============================================================================
--- pypy/dist/pypy/annotation/builtin.py	(original)
+++ pypy/dist/pypy/annotation/builtin.py	Wed Apr 12 19:26:06 2006
@@ -421,6 +421,14 @@
     cast_p = lltype.cast_pointer(PtrT.const, s_p.ll_ptrtype._defl())
     return SomePtr(ll_ptrtype=lltype.typeOf(cast_p))
 
+def cast_subarray_pointer(PtrT, s_p, s_offset):
+    assert isinstance(s_p, SomePtr), "casting of non-pointer: %r" % s_p
+    assert PtrT.is_constant()
+    cast_p = lltype.cast_subarray_pointer(PtrT.const,
+                                          s_p.ll_ptrtype._example(),
+                                          0)
+    return SomePtr(ll_ptrtype=lltype.typeOf(cast_p))
+
 def cast_ptr_to_int(s_ptr): # xxx
     return SomeInteger()
 
@@ -437,6 +445,7 @@
 BUILTIN_ANALYZERS[lltype.cast_primitive] = cast_primitive
 BUILTIN_ANALYZERS[lltype.nullptr] = nullptr
 BUILTIN_ANALYZERS[lltype.cast_pointer] = cast_pointer
+BUILTIN_ANALYZERS[lltype.cast_subarray_pointer] = cast_subarray_pointer
 BUILTIN_ANALYZERS[lltype.cast_ptr_to_int] = cast_ptr_to_int
 BUILTIN_ANALYZERS[lltype.getRuntimeTypeInfo] = getRuntimeTypeInfo
 BUILTIN_ANALYZERS[lltype.runtime_type_info] = runtime_type_info

Modified: pypy/dist/pypy/rpython/lltypesystem/llmemory.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/llmemory.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/llmemory.py	Wed Apr 12 19:26:06 2006
@@ -215,7 +215,18 @@
         self.ref().set(value)
 
     def _cast_to_ptr(self, EXPECTED_TYPE):
-        return lltype.cast_pointer(EXPECTED_TYPE, self.get())
+        ref = self.ref()
+        if (isinstance(ref, _arrayitemref) and
+            isinstance(EXPECTED_TYPE.TO, lltype.FixedSizeArray) and
+            isinstance(lltype.typeOf(ref.array).TO, lltype.Array)):
+            # special case that requires cast_subarray_pointer
+            return lltype.cast_subarray_pointer(EXPECTED_TYPE,
+                                                ref.array,
+                                                ref.index)
+        else:
+            # regular case
+            assert isinstance(ref.type(), lltype.ContainerType)
+            return lltype.cast_pointer(EXPECTED_TYPE, ref.get())
 
     def _cast_to_int(self):
         return self.get()._cast_to_int()

Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lltype.py	Wed Apr 12 19:26:06 2006
@@ -6,6 +6,7 @@
 from pypy.tool.picklesupport import getstate_with_slots, setstate_with_slots, pickleable_weakref
 from types import NoneType
 from sys import maxint
+import weakref
 
 log = py.log.Producer('lltype')
 
@@ -612,6 +613,29 @@
         raise TypeError, "can only cast pointers to other pointers"
     return ptr._cast_to(PTRTYPE)
 
+def cast_subarray_pointer(ARRAYPTRTYPE, arrayptr, baseoffset):
+    CURPTRTYPE = typeOf(arrayptr)
+    if not isinstance(CURPTRTYPE, Ptr) or not isinstance(ARRAYPTRTYPE, Ptr):
+        raise TypeError, "can only cast pointers to other pointers"
+    ARRAYTYPE = ARRAYPTRTYPE.TO
+    if (not isinstance(CURPTRTYPE.TO, Array) or
+        not isinstance(ARRAYTYPE, FixedSizeArray)):
+        raise TypeError, "for now, can only cast Array to FixedSizeArray"
+    if CURPTRTYPE.TO.OF != ARRAYTYPE.OF:
+        raise TypeError, "mismatching array item types"
+    if not arrayptr:
+        raise RuntimeError("cast_subarray_pointer: NULL argument")
+    try:
+        cache = _subarray._cache[arrayptr._obj]
+    except KeyError:
+        cache = _subarray._cache[arrayptr._obj] = {}
+    key = (ARRAYTYPE, baseoffset)
+    try:
+        subarray = cache[key]
+    except KeyError:
+        subarray = cache[key] = _subarray(ARRAYTYPE, arrayptr._obj, baseoffset)
+    return _ptr(ARRAYPTRTYPE, subarray)
+
 def _expose(val, solid=False):
     """XXX A nice docstring here"""
     T = typeOf(val)
@@ -762,9 +786,9 @@
 
     def __getitem__(self, i): # ! can only return basic or ptr !
         if isinstance(self._T, (Array, FixedSizeArray)):
-            if not (0 <= i < self._obj.getlength()):
-                if (self._T._hints.get('isrpystring', False) and
-                    i == self._obj.getlength()):
+            start, stop = self._obj.getbounds()
+            if not (start <= i < stop):
+                if self._T._hints.get('isrpystring', False) and i == stop:
                     # special hack for the null terminator
                     assert self._T.OF == Char
                     return '\x00'
@@ -782,8 +806,9 @@
             if T2 != T1:
                     raise TypeError("%r items:\n"
                                     "expect %r\n"
-                                    "   got %r" % (self._T, T1, T2))                
-            if not (0 <= i < self._obj.getlength()):
+                                    "   got %r" % (self._T, T1, T2))
+            start, stop = self._obj.getbounds()
+            if not (start <= i < stop):
                 raise IndexError("array index out of bounds")
             self._obj.setitem(i, val)
             return
@@ -971,6 +996,9 @@
         assert isinstance(self._TYPE, FixedSizeArray)
         return self._TYPE.length
 
+    def getbounds(self):
+        return 0, self.getlength()
+
     def getitem(self, index):         # for FixedSizeArray kind of structs
         assert isinstance(self._TYPE, FixedSizeArray)
         return getattr(self, 'item%d' % index)
@@ -1015,6 +1043,9 @@
     def getlength(self):
         return len(self.items)
 
+    def getbounds(self):
+        return 0, self.getlength()
+
     def getitem(self, index):
         return self.items[index]
 
@@ -1025,6 +1056,32 @@
 assert not '__dict__' in dir(_struct)
 
 
+class _subarray(_parentable):     # only for cast_subarray_pointer()
+    _kind = "subarray"
+    _cache = weakref.WeakKeyDictionary()  # parentarray -> {subarrays}
+
+    def __init__(self, TYPE, arrayobj, baseoffset):
+        _parentable.__init__(self, TYPE)
+        self._setparentstructure(arrayobj, baseoffset)
+
+    def getlength(self):
+        assert isinstance(self._TYPE, FixedSizeArray)
+        return self._TYPE.length
+
+    def getbounds(self):
+        baseoffset = self._parent_index
+        start, stop = self._parentstructure().getbounds()
+        return start - baseoffset, stop - baseoffset
+
+    def getitem(self, index):
+        baseoffset = self._parent_index
+        return self._parentstructure().getitem(baseoffset + index)
+
+    def setitem(self, index, value):
+        baseoffset = self._parent_index
+        self._parentstructure().setitem(baseoffset + index, value)
+
+
 class _func(object):
     def __init__(self, TYPE, **attrs):
         self._TYPE = TYPE

Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_llmemory.py	Wed Apr 12 19:26:06 2006
@@ -160,3 +160,15 @@
     assert adr1 != adr2
     adr2 += ItemOffset(lltype.Char, -1)
     assert adr1 == adr2
+
+def test_cast_subarray_pointer():
+    A = lltype.GcArray(lltype.Signed)
+    a = lltype.malloc(A, 5)
+    a[3] = 132
+
+    SUBARRAY = lltype.FixedSizeArray(lltype.Signed, 1)
+    adr = cast_ptr_to_adr(a) + itemoffsetof(A, 3)
+    subarray = cast_adr_to_ptr(adr, lltype.Ptr(SUBARRAY))
+    assert subarray[0] == 132
+    subarray[0] += 2
+    assert a[3] == 134

Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_lltype.py	Wed Apr 12 19:26:06 2006
@@ -577,3 +577,36 @@
     assert s.a[3] == 17
     assert len(s.a) == 5
     py.test.raises(TypeError, "s.a = a")
+
+def test_cast_subarray_pointer():
+    A = GcArray(Signed)
+    a = malloc(A, 5)
+    a[0] = 0
+    a[1] = 10
+    a[2] = 20
+    a[3] = 30
+    a[4] = 40
+    BOX = Ptr(FixedSizeArray(Signed, 2))
+    b01 = cast_subarray_pointer(BOX, a, 0)
+    b12 = cast_subarray_pointer(BOX, a, 1)
+    b23 = cast_subarray_pointer(BOX, a, 2)
+    b34 = cast_subarray_pointer(BOX, a, 3)
+    assert b01[0] == 0
+    assert b01[1] == 10
+    assert b12[0] == 10
+    assert b12[1] == 20
+    assert b23[0] == 20
+    assert b23[1] == 30
+    assert b34[0] == 30
+    assert b34[1] == 40
+    b23[0] = 23
+    assert a[2] == 23
+    b12[1] += 1
+    assert a[2] == 24
+    # out-of-bound access is allowed, if it's within the parent's bounds
+    assert len(b23) == 2
+    assert b23[-1] == 10
+    assert b12[3] == 40
+    py.test.raises(IndexError, "b01[-1]")
+    py.test.raises(IndexError, "b34[2]")
+    py.test.raises(IndexError, "b12[4]")



More information about the Pypy-commit mailing list