[pypy-svn] r46704 - in pypy/dist/pypy/rpython/lltypesystem: . test
arigo at codespeak.net
arigo at codespeak.net
Tue Sep 18 09:56:09 CEST 2007
Author: arigo
Date: Tue Sep 18 09:56:08 2007
New Revision: 46704
Modified:
pypy/dist/pypy/rpython/lltypesystem/ll2ctypes.py
pypy/dist/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
Log:
Support for recursive types in ll2ctypes.
Modified: pypy/dist/pypy/rpython/lltypesystem/ll2ctypes.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/ll2ctypes.py (original)
+++ pypy/dist/pypy/rpython/lltypesystem/ll2ctypes.py Tue Sep 18 09:56:08 2007
@@ -21,6 +21,8 @@
_ctypes_cache = {}
+_delayed_ptrs = []
+_gettype_recursion = 0
def _setup_ctypes_cache():
from pypy.rpython.lltypesystem import rffi
@@ -129,32 +131,58 @@
try:
return _ctypes_cache[T]
except KeyError:
- if isinstance(T, lltype.Ptr):
- if isinstance(T.TO, lltype.FuncType):
- argtypes = [get_ctypes_type(ARG) for ARG in T.TO.ARGS]
- if T.TO.RESULT is lltype.Void:
- restype = None
- else:
- restype = get_ctypes_type(T.TO.RESULT)
- cls = ctypes.CFUNCTYPE(restype, *argtypes)
+ global _gettype_recursion
+ _gettype_recursion += 1
+ try:
+ cls = build_new_ctypes_type(T)
+ if T not in _ctypes_cache:
+ _ctypes_cache[T] = cls
else:
- cls = ctypes.POINTER(get_ctypes_type(T.TO))
- elif isinstance(T, lltype.Struct):
- cls = build_ctypes_struct(T)
- elif isinstance(T, lltype.Array):
- cls = build_ctypes_array(T)
- elif isinstance(T, lltype.OpaqueType):
- if T.hints.get('external', None) != 'C':
- raise TypeError("%s is not external" % T)
- cls = ctypes.c_char * T.hints['getsize']()
- else:
- _setup_ctypes_cache()
- if T in _ctypes_cache:
- return _ctypes_cache[T]
- raise NotImplementedError(T)
- _ctypes_cache[T] = cls
+ # check for buggy recursive structure logic
+ assert _ctypes_cache[T] is cls
+
+ if _gettype_recursion == 1:
+ complete_pointer_types()
+ finally:
+ _gettype_recursion -= 1
return cls
+def build_new_ctypes_type(T):
+ if isinstance(T, lltype.Ptr):
+ if isinstance(T.TO, lltype.FuncType):
+ argtypes = [get_ctypes_type(ARG) for ARG in T.TO.ARGS]
+ if T.TO.RESULT is lltype.Void:
+ restype = None
+ else:
+ restype = get_ctypes_type(T.TO.RESULT)
+ return ctypes.CFUNCTYPE(restype, *argtypes)
+ elif isinstance(T.TO, lltype.Struct):
+ # for recursive structures: build a forward pointer first
+ uniquename = 'ctypes_%s_%d' % (T.TO.__name__, len(_ctypes_cache))
+ pcls = ctypes.POINTER(uniquename)
+ _delayed_ptrs.append((pcls, T.TO))
+ return pcls
+ else:
+ return ctypes.POINTER(get_ctypes_type(T.TO))
+ elif isinstance(T, lltype.Struct):
+ return build_ctypes_struct(T)
+ elif isinstance(T, lltype.Array):
+ return build_ctypes_array(T)
+ elif isinstance(T, lltype.OpaqueType):
+ if T.hints.get('external', None) != 'C':
+ raise TypeError("%s is not external" % T)
+ return ctypes.c_char * T.hints['getsize']()
+ else:
+ _setup_ctypes_cache()
+ if T in _ctypes_cache:
+ return _ctypes_cache[T]
+ raise NotImplementedError(T)
+
+def complete_pointer_types():
+ while _delayed_ptrs:
+ pcls, S = _delayed_ptrs.pop()
+ ctypes.SetPointerType(pcls, get_ctypes_type(S))
+
def convert_struct(container, cstruct=None):
STRUCT = container._TYPE
Modified: pypy/dist/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/test/test_ll2ctypes.py (original)
+++ pypy/dist/pypy/rpython/lltypesystem/test/test_ll2ctypes.py Tue Sep 18 09:56:08 2007
@@ -51,6 +51,28 @@
assert sc.contents.y == 52
lltype.free(s, flavor='raw')
+ def test_struct_ptrs(self):
+ S2 = lltype.Struct('S2', ('y', lltype.Signed))
+ S1 = lltype.Struct('S', ('x', lltype.Signed), ('p', lltype.Ptr(S2)))
+ s1 = lltype.malloc(S1, flavor='raw')
+ s2a = lltype.malloc(S2, flavor='raw')
+ s2b = lltype.malloc(S2, flavor='raw')
+ s2a.y = ord('a')
+ s2b.y = ord('b')
+ sc1 = lltype2ctypes(s1)
+ sc1.contents.x = 50
+ assert s1.x == 50
+ sc1.contents.p = lltype2ctypes(s2a)
+ assert s1.p == s2a
+ s1.p.y -= 32
+ assert sc1.contents.p.contents.y == ord('A')
+ s1.p = s2b
+ sc1.contents.p.contents.y -= 32
+ assert s2b.y == ord('B')
+ lltype.free(s1, flavor='raw')
+ lltype.free(s2a, flavor='raw')
+ lltype.free(s2b, flavor='raw')
+
def test_simple_array(self):
A = lltype.Array(lltype.Signed)
a = lltype.malloc(A, 10, flavor='raw')
@@ -406,9 +428,78 @@
lltype.free(s, flavor='raw')
def test_recursive_struct(self):
- py.test.skip("Not implemented")
SX = lltype.ForwardReference()
- S1 = lltype.Struct('S1', ('x', lltype.Ptr(SX)))
- S1.x.TO.become(S1)
- s = lltype.malloc(S1, flavor='raw')
- sc = lltype2ctypes(s)
+ S1 = lltype.Struct('S1', ('p', lltype.Ptr(SX)), ('x', lltype.Signed))
+ SX.become(S1)
+ # a chained list
+ s1 = lltype.malloc(S1, flavor='raw')
+ s2 = lltype.malloc(S1, flavor='raw')
+ s3 = lltype.malloc(S1, flavor='raw')
+ s1.x = 111
+ s2.x = 222
+ s3.x = 333
+ s1.p = s2
+ s2.p = s3
+ s3.p = lltype.nullptr(S1)
+ sc1 = lltype2ctypes(s1)
+ sc2 = sc1.contents.p
+ sc3 = sc2.contents.p
+ assert not sc3.contents.p
+ assert sc1.contents.x == 111
+ assert sc2.contents.x == 222
+ assert sc3.contents.x == 333
+ sc3.contents.x += 1
+ assert s3.x == 334
+ s3.x += 2
+ assert sc3.contents.x == 336
+ lltype.free(s1, flavor='raw')
+ lltype.free(s2, flavor='raw')
+ lltype.free(s3, flavor='raw')
+ # a self-cycle
+ s1 = lltype.malloc(S1, flavor='raw')
+ s1.x = 12
+ s1.p = s1
+ sc1 = lltype2ctypes(s1)
+ assert sc1.contents.x == 12
+ assert (ctypes.addressof(sc1.contents.p.contents) ==
+ ctypes.addressof(sc1.contents))
+ s1.x *= 5
+ assert sc1.contents.p.contents.p.contents.p.contents.x == 60
+ lltype.free(s1, flavor='raw')
+ # a longer cycle
+ s1 = lltype.malloc(S1, flavor='raw')
+ s2 = lltype.malloc(S1, flavor='raw')
+ s1.x = 111
+ s1.p = s2
+ s2.x = 222
+ s2.p = s1
+ sc1 = lltype2ctypes(s1)
+ assert sc1.contents.x == 111
+ assert sc1.contents.p.contents.x == 222
+ assert (ctypes.addressof(sc1.contents.p.contents) !=
+ ctypes.addressof(sc1.contents))
+ assert (ctypes.addressof(sc1.contents.p.contents.p.contents) ==
+ ctypes.addressof(sc1.contents))
+ lltype.free(s1, flavor='raw')
+ lltype.free(s2, flavor='raw')
+
+ def test_indirect_recursive_struct(self):
+ S2Forward = lltype.ForwardReference()
+ S1 = lltype.Struct('S1', ('p', lltype.Ptr(S2Forward)))
+ A2 = lltype.Array(lltype.Ptr(S1), hints={'nolength': True})
+ S2 = lltype.Struct('S2', ('a', lltype.Ptr(A2)))
+ S2Forward.become(S2)
+ s1 = lltype.malloc(S1, flavor='raw')
+ a2 = lltype.malloc(A2, 10, flavor='raw')
+ s2 = lltype.malloc(S2, flavor='raw')
+ s2.a = a2
+ a2[5] = s1
+ s1.p = s2
+ ac2 = lltype2ctypes(a2, normalize=False)
+ sc1 = ac2.contents.items[5]
+ sc2 = sc1.contents.p
+ assert (ctypes.addressof(sc2.contents.a.contents) ==
+ ctypes.addressof(ac2.contents))
+ lltype.free(s1, flavor='raw')
+ lltype.free(a2, flavor='raw')
+ lltype.free(s2, flavor='raw')
More information about the Pypy-commit
mailing list