[pypy-svn] r50583 - in pypy/branch/applevel-ctypes2/pypy/module/_rawffi: . test

arigo at codespeak.net arigo at codespeak.net
Mon Jan 14 13:06:16 CET 2008


Author: arigo
Date: Mon Jan 14 13:06:16 2008
New Revision: 50583

Modified:
   pypy/branch/applevel-ctypes2/pypy/module/_rawffi/array.py
   pypy/branch/applevel-ctypes2/pypy/module/_rawffi/interp_rawffi.py
   pypy/branch/applevel-ctypes2/pypy/module/_rawffi/structure.py
   pypy/branch/applevel-ctypes2/pypy/module/_rawffi/test/test__rawffi.py
Log:
(fijal, arigo)
A first passing test in _rawffi! :-)
Basically, _rawffi function pointers can only be called
with arguments that are _array's of length 1.


Modified: pypy/branch/applevel-ctypes2/pypy/module/_rawffi/array.py
==============================================================================
--- pypy/branch/applevel-ctypes2/pypy/module/_rawffi/array.py	(original)
+++ pypy/branch/applevel-ctypes2/pypy/module/_rawffi/array.py	Mon Jan 14 13:06:16 2008
@@ -9,7 +9,8 @@
 from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.interpreter.error import OperationError, wrap_oserror
-from pypy.module._rawffi.structure import segfault_exception
+from pypy.module._rawffi.interp_rawffi import segfault_exception
+from pypy.module._rawffi.interp_rawffi import W_DataInstance
 from pypy.module._rawffi.interp_rawffi import unwrap_value, wrap_value, _get_type,\
      TYPEMAP
 from pypy.rlib.rarithmetic import intmask
@@ -31,79 +32,83 @@
         self.of = of
         self.itemsize = intmask(TYPEMAP[of].c_size)
 
-    def descr_call(self, space, w_length_or_iterable):
-        if space.is_true(space.isinstance(w_length_or_iterable, space.w_int)):
-            length = space.int_w(w_length_or_iterable)
-            return space.wrap(W_ArrayInstance(space, self, length))
-        else:
-            items_w = space.unpackiterable(w_length_or_iterable)
-            length = len(items_w)
-            result = W_ArrayInstance(space, self, length)
-            for num in range(len(items_w)):
+    def allocate(self, space, length):
+        return W_ArrayInstance(space, self, length)
+
+    def descr_call(self, space, length, w_iterable=None):
+        result = self.allocate(space, length)
+        if not space.is_w(w_iterable, space.w_None):
+            items_w = space.unpackiterable(w_iterable)
+            iterlength = len(items_w)
+            if iterlength > length:
+                raise OperationError(space.w_ValueError,
+                                     space.wrap("too many items for specified"
+                                                " array length"))
+            for num in range(iterlength):
                 w_item = items_w[num]
-                unwrap_value(space, push_elem, result.ll_array, num, self.of,
-                             w_item, None)
-            return space.wrap(result)
+                unwrap_value(space, push_elem, result.ll_buffer, num, self.of,
+                             w_item)
+        return space.wrap(result)
 
     def fromaddress(self, space, address, length):
         return space.wrap(W_ArrayInstance(space, self, length, address))
     fromaddress.unwrap_spec = ['self', ObjSpace, int, int]
 
+class ArrayCache:
+    def __init__(self, space):
+        self.space = space
+        self.cache = {}
+        self.array_of_ptr = self.get_array_type('P')
+
+    def get_array_type(self, of):
+        try:
+            return self.cache[of]
+        except KeyError:
+            _get_type(self.space, of)
+            result = W_Array(self.space, of)
+            self.cache[of] = result
+            return result
+
+def get_array_cache(space):
+    return space.fromcache(ArrayCache)
+
 def descr_new_array(space, w_type, of):
-    _get_type(space, of)
-    return space.wrap(W_Array(space, of))
+    array_type = get_array_cache(space).get_array_type(of)
+    return space.wrap(array_type)
 
 W_Array.typedef = TypeDef(
     'Array',
     __new__  = interp2app(descr_new_array, unwrap_spec=[ObjSpace, W_Root, str]),
     __call__ = interp2app(W_Array.descr_call,
-                          unwrap_spec=['self', ObjSpace, W_Root]),
+                          unwrap_spec=['self', ObjSpace, int, W_Root]),
     fromaddress = interp2app(W_Array.fromaddress),
     of = interp_attrproperty('of', W_Array),
 )
 W_Array.typedef.acceptable_as_base_class = False
 
 
-class W_ArrayInstance(Wrappable):
+class W_ArrayInstance(W_DataInstance):
     def __init__(self, space, shape, length, address=0):
-        self.ll_array = lltype.nullptr(rffi.VOIDP.TO)
-        self.alloced = False
+        W_DataInstance.__init__(self, space, shape.itemsize * length, address)
         self.length = length
         self.shape = shape
-        if address != 0:
-            self.ll_array = rffi.cast(rffi.VOIDP, address)
-        else:
-            size = shape.itemsize * length
-            self.ll_array = lltype.malloc(rffi.VOIDP.TO, size, flavor='raw',
-                                          zero=True)
-
 
     # XXX don't allow negative indexes, nor slices
 
     def setitem(self, space, num, w_value):
         if num >= self.length or num < 0:
             raise OperationError(space.w_IndexError, space.w_None)
-        unwrap_value(space, push_elem, self.ll_array, num, self.shape.of, w_value,
-                   None)
+        unwrap_value(space, push_elem, self.ll_buffer, num, self.shape.of,
+                     w_value)
     setitem.unwrap_spec = ['self', ObjSpace, int, W_Root]
 
     def getitem(self, space, num):
         if num >= self.length or num < 0:
             raise OperationError(space.w_ValueError, space.wrap(
                 "Getting element %d of array sized %d" % (num, self.length)))
-        return wrap_value(space, get_elem, self.ll_array, num, self.shape.of)
+        return wrap_value(space, get_elem, self.ll_buffer, num, self.shape.of)
     getitem.unwrap_spec = ['self', ObjSpace, int]
 
-    def getbuffer(space, self):
-        return space.wrap(rffi.cast(rffi.INT, self.ll_array))
-
-    def free(self, space):
-        if not self.ll_array:
-            raise segfault_exception(space, "freeing NULL pointer")
-        lltype.free(self.ll_array, flavor='raw')
-        self.ll_array = lltype.nullptr(rffi.VOIDP.TO)
-    free.unwrap_spec = ['self', ObjSpace]
-
 W_ArrayInstance.typedef = TypeDef(
     'ArrayInstance',
     __setitem__ = interp2app(W_ArrayInstance.setitem),
@@ -111,6 +116,6 @@
     buffer      = GetSetProperty(W_ArrayInstance.getbuffer),
     shape       = interp_attrproperty('shape', W_ArrayInstance),
     free        = interp2app(W_ArrayInstance.free),
+    byptr       = interp2app(W_ArrayInstance.byptr),
 )
-
-
+W_ArrayInstance.typedef.acceptable_as_base_class = False

Modified: pypy/branch/applevel-ctypes2/pypy/module/_rawffi/interp_rawffi.py
==============================================================================
--- pypy/branch/applevel-ctypes2/pypy/module/_rawffi/interp_rawffi.py	(original)
+++ pypy/branch/applevel-ctypes2/pypy/module/_rawffi/interp_rawffi.py	Mon Jan 14 13:06:16 2008
@@ -52,6 +52,7 @@
     'z' : ffi_type_pointer,
     'O' : ffi_type_pointer,
 }
+TYPEMAP_PTR_LETTERS = "POsz"
 
 LL_TYPEMAP = {
     'c' : rffi.CHAR,
@@ -122,8 +123,8 @@
         argtypes = [space.str_w(w_arg) for w_arg in argtypes_w]
         ffi_argtypes = [self.get_type(arg) for arg in argtypes]
         try:
-            ptr = self.cdll.getpointer(name, ffi_argtypes, ffi_restype)
-            w_funcptr = W_FuncPtr(ptr, argtypes, restype)
+            ptr = self.cdll.getrawpointer(name, ffi_argtypes, ffi_restype)
+            w_funcptr = W_FuncPtr(space, ptr, argtypes, restype)
             space.setitem(self.w_cache, w_key, w_funcptr)
             return w_funcptr
         except KeyError:
@@ -190,45 +191,53 @@
     SIZE_CHECKERS[c] = make_size_checker(c, native_fmttable[c]['size'], signed)
 unroll_size_checkers = unrolling_iterable(SIZE_CHECKERS.items())
 
-def unwrap_value(space, push_func, add_arg, argdesc, tp, w_arg, to_free):
-    w = space.wrap
-    if tp == "d" or tp == "f":
-        if tp == "d":
-            push_func(add_arg, argdesc, space.float_w(w_arg))
+def segfault_exception(space, reason):
+    w_mod = space.getbuiltinmodule("_rawffi")
+    w_exception = space.getattr(w_mod, space.wrap("SegfaultException"))
+    return OperationError(w_exception, space.wrap(reason))
+
+
+class W_DataInstance(Wrappable):
+    def __init__(self, space, size, address=0):
+        if address != 0:
+            self.ll_buffer = rffi.cast(rffi.VOIDP, address)
         else:
-            push_func(add_arg, argdesc, rffi.cast(rffi.FLOAT,
-                                                  space.float_w(w_arg)))
-    elif tp == "s" or tp =="z":
-        ll_str = rffi.str2charp(space.str_w(w_arg))
-        if to_free is not None:
-            to_free.append(ll_str)
-        push_func(add_arg, argdesc, ll_str)
-    elif tp == "P" or tp == "O":
+            self.ll_buffer = lltype.malloc(rffi.VOIDP.TO, size, flavor='raw',
+                                           zero=True)
+
+    def getbuffer(space, self):
+        return space.wrap(rffi.cast(rffi.INT, self.ll_buffer))
+
+    def byptr(self, space):
+        from pypy.module._rawffi.array import get_array_cache
+        array_of_ptr = get_array_cache(space).array_of_ptr
+        array = array_of_ptr.allocate(space, 1)
+        array.setitem(space, 0, space.wrap(self))
+        return space.wrap(array)
+    byptr.unwrap_spec = ['self', ObjSpace]
+
+    def free(self, space):
+        if not self.ll_buffer:
+            raise segfault_exception(space, "freeing NULL pointer")
+        lltype.free(self.ll_buffer, flavor='raw')
+        self.ll_buffer = lltype.nullptr(rffi.VOIDP.TO)
+    free.unwrap_spec = ['self', ObjSpace]
+
+
+def unwrap_value(space, push_func, add_arg, argdesc, tp, w_arg):
+    w = space.wrap
+    if tp == "d":
+        push_func(add_arg, argdesc, space.float_w(w_arg))
+    elif tp == "f":
+        push_func(add_arg, argdesc, rffi.cast(rffi.FLOAT,
+                                              space.float_w(w_arg)))
+    elif tp in TYPEMAP_PTR_LETTERS:
         # check for NULL ptr
-        if space.is_w(w_arg, space.w_None):
-            push_func(add_arg, argdesc, lltype.nullptr(rffi.VOIDP.TO))
-        elif space.is_true(space.isinstance(w_arg, space.w_int)):
+        if space.is_true(space.isinstance(w_arg, space.w_int)):
             push_func(add_arg, argdesc, rffi.cast(rffi.VOIDP, space.int_w(w_arg)))
-        elif space.is_true(space.isinstance(w_arg, space.w_basestring)):
-            if to_free is not None:
-                to_free.append(pack_pointer(space, add_arg, argdesc, w_arg, push_func))
         else:
-            mod = space.getbuiltinmodule('_rawffi')
-            w_StructureInstance = space.getattr(mod, w('StructureInstance'))
-            w_ArrayInstance = space.getattr(mod, w('ArrayInstance'))
-            #w_CallbackPtr = space.getattr(mod, w('CallbackPtr'))
-            if space.is_true(space.isinstance(w_arg, w_StructureInstance)) or\
-                   space.is_true(space.isinstance(w_arg, w_ArrayInstance)):
-                ptr = rffi.cast(rffi.VOIDP, space.int_w(space.getattr(w_arg, w('buffer'))))
-                push_func(add_arg, argdesc, ptr)
-            #elif space.is_true(space.isinstance(w_arg, w_CallbackPtr)):
-            #    TP = lltype.FuncType([lltype.Signed, lltype.Signed], lltype.Signed)
-            #    ptr = rffi.cast(TP, space.int_w(space.getattr(w_arg, w('buffer'))))
-            #    push_func(add_arg, argdesc, ptr)
-
-            else:
-                raise OperationError(space.w_TypeError, w(
-                    "Expected structure, array or simple type"))
+            datainstance = space.interp_w(W_DataInstance, w_arg)
+            push_func(add_arg, argdesc, datainstance.ll_buffer)
     elif tp == "c":
         s = space.str_w(w_arg)
         if len(s) != 1:
@@ -298,30 +307,35 @@
 push._annspecialcase_ = 'specialize:argtype(2)'
 
 class W_FuncPtr(Wrappable):
-    def __init__(self, ptr, argtypes, restype):
+    def __init__(self, space, ptr, argtypes, restype):
+        from pypy.module._rawffi.array import get_array_cache
         self.ptr = ptr
-        self.restype = restype
+        cache = get_array_cache(space)
+        self.resarray = cache.get_array_type(restype)
         self.argtypes = argtypes
 
-    def call(self, space, arguments):
-        args_w, kwds_w = arguments.unpack()
-        # C has no keyword arguments
-        if kwds_w:
-            raise OperationError(space.w_TypeError, space.wrap(
-                "Provided keyword arguments for C function call"))
-        to_free = []
-        i = 0
-        for i in range(len(self.argtypes)):
+    def call(self, space, args_w):
+        from pypy.module._rawffi.array import W_ArrayInstance
+        argnum = len(args_w)
+        if argnum != len(self.argtypes):
+            msg = "Wrong number of argument: expected %d, got %d" % (
+                len(self.argtypes), argnum)
+            raise OperationError(space.w_TypeError, space.wrap(msg))
+        args_ll = []
+        for i in range(argnum):
             argtype = self.argtypes[i]
             w_arg = args_w[i]
-            unwrap_value(space, push, self.ptr, i, argtype, w_arg, to_free)
-            i += 1
-        try:
-            return wrap_value(space, ptr_call, self.ptr, None, self.restype)
-        finally:
-            for elem in to_free:
-                lltype.free(elem, flavor='raw')
-    call.unwrap_spec = ['self', ObjSpace, Arguments]
+            arg = space.interp_w(W_ArrayInstance, w_arg)
+            if arg.shape.of != argtype:
+                msg = "Argument %d should be typecode %s, got %s" % (
+                    i+1, argtype, arg.shape.of)
+                raise OperationError(space.w_TypeError, space.wrap(msg))
+            args_ll.append(arg.ll_buffer)
+            # XXX we could avoid the intermediate list args_ll
+        result = self.resarray.allocate(space, 1)
+        self.ptr.call(args_ll, result.ll_buffer)
+        return space.wrap(result)
+    call.unwrap_spec = ['self', ObjSpace, 'args_w']
 
 W_FuncPtr.typedef = TypeDef(
     'FuncPtr',

Modified: pypy/branch/applevel-ctypes2/pypy/module/_rawffi/structure.py
==============================================================================
--- pypy/branch/applevel-ctypes2/pypy/module/_rawffi/structure.py	(original)
+++ pypy/branch/applevel-ctypes2/pypy/module/_rawffi/structure.py	Mon Jan 14 13:06:16 2008
@@ -10,6 +10,8 @@
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.interpreter.error import OperationError, wrap_oserror
+from pypy.module._rawffi.interp_rawffi import segfault_exception
+from pypy.module._rawffi.interp_rawffi import W_DataInstance
 from pypy.module._rawffi.interp_rawffi import wrap_value, unwrap_value, _get_type,\
      TYPEMAP
 from pypy.rlib.rarithmetic import intmask
@@ -96,20 +98,10 @@
     return rffi.cast(TP, pos)[0]
 cast_pos._annspecialcase_ = 'specialize:arg(2)'
 
-def segfault_exception(space, reason):
-    w_mod = space.getbuiltinmodule("_rawffi")
-    w_exception = space.getattr(w_mod, space.wrap("SegfaultException"))
-    return OperationError(w_exception, space.wrap(reason))
-
-class W_StructureInstance(Wrappable):
+class W_StructureInstance(W_DataInstance):
     def __init__(self, space, shape, address, fieldinits_w):
-        self.free_afterwards = False
+        W_DataInstance.__init__(self, space, shape.size, address)
         self.shape = shape
-        if address != 0:
-            self.ll_buffer = rffi.cast(rffi.VOIDP, address)
-        else:
-            self.ll_buffer = lltype.malloc(rffi.VOIDP.TO, shape.size, flavor='raw',
-                                           zero=True)
         if fieldinits_w:
             for field, w_value in fieldinits_w.iteritems():
                 self.setattr(space, field, w_value)
@@ -138,16 +130,6 @@
         unwrap_value(space, push_field, self, i, c, w_value, None)
     setattr.unwrap_spec = ['self', ObjSpace, str, W_Root]
 
-    def free(self, space):
-        if not self.ll_buffer:
-            raise segfault_exception(space, "freeing NULL pointer")
-        lltype.free(self.ll_buffer, flavor='raw')
-        self.ll_buffer = lltype.nullptr(rffi.VOIDP.TO)
-    free.unwrap_spec = ['self', ObjSpace]
-
-    def getbuffer(space, self):
-        return space.wrap(rffi.cast(rffi.INT, self.ll_buffer))
-
 
 W_StructureInstance.typedef = TypeDef(
     'StructureInstance',
@@ -156,6 +138,7 @@
     buffer      = GetSetProperty(W_StructureInstance.getbuffer),
     free        = interp2app(W_StructureInstance.free),
     shape       = interp_attrproperty('shape', W_StructureInstance),
+    byptr       = interp2app(W_StructureInstance.byptr),
 )
 W_StructureInstance.typedef.acceptable_as_base_class = False
 

Modified: pypy/branch/applevel-ctypes2/pypy/module/_rawffi/test/test__rawffi.py
==============================================================================
--- pypy/branch/applevel-ctypes2/pypy/module/_rawffi/test/test__rawffi.py	(original)
+++ pypy/branch/applevel-ctypes2/pypy/module/_rawffi/test/test__rawffi.py	Mon Jan 14 13:06:16 2008
@@ -131,13 +131,20 @@
     def test_getchar(self):
         import _rawffi
         lib = _rawffi.CDLL(self.lib_name)
-        get_char = lib.ptr('get_char', ['s', 'H'], 'c')
-        assert get_char('dupa', 2) == 'p'
-        assert get_char('dupa', 1) == 'u'
-        raises(ValueError, "get_char('xxx', 2 ** 17)")
-        raises(ValueError, "get_char('xxx', -1)")
-        get_char = lib.ptr('get_char', ['z', 'H'], 'c')
-        assert get_char('dupa', 2) == 'p'
+        get_char = lib.ptr('get_char', ['P', 'H'], 'c')
+        A = _rawffi.Array('c')
+        B = _rawffi.Array('H')
+        dupa = A(5, 'dupa')
+        dupaptr = dupa.byptr()
+        for i in range(4):
+            intptr = B(1)
+            intptr[0] = i
+            res = get_char(dupaptr, intptr)
+            assert res[0] == 'dupa'[i]
+            res.free()
+            intptr.free()
+        dupaptr.free()
+        dupa.free()
 
     def test_returning_str(self):
         import _rawffi



More information about the Pypy-commit mailing list