[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