Commits

Armin Rigo committed 0f76d74

First rough implementation of pointers.

Comments (0)

Files changed (6)

                     "non-constant array length")
                 length = int(typenode.dim.value)
             bitem = self._get_btype(typenode.type)
-            return self._get_cached_btype('new_array_type', bitem, length)
-        else:
+            return self._backend.get_cached_btype('new_array_type',
+                                                  bitem, length)
+        #
+        elif isinstance(typenode, pycparser.c_ast.TypeDecl):
             # assume a primitive type
             names = typenode.type.names
             if len(names) > 1 and names[-1] == 'int':
                 names = names[:-1]
             ident = ' '.join(names)
-            return self._get_cached_btype('new_primitive_type', ident)
-
-    def _get_cached_btype(self, methname, *args):
-        try:
-            btype = self._cached_btypes[methname, args]
-        except KeyError:
-            btype = getattr(self._backend, methname)(*args)
-            self._cached_btypes[methname, args] = btype
-        return btype
+            return self._backend.get_cached_btype('new_primitive_type', ident)
+        #
+        elif isinstance(typenode, pycparser.c_ast.PtrDecl):
+            bitem = self._get_btype(typenode.type)
+            return self._backend.get_cached_btype("new_pointer_type", bitem)
+        #
+        else:
+            raise FFIError("bad or unsupported type declaration")
 
 
 class FFILibrary(object):

ffi/backend_base.py

+
+
+class BackendBase(object):
+
+    def __init__(self):
+        self._cached_btypes = {}
+
+    def get_cached_btype(self, methname, *args):
+        try:
+            btype = self._cached_btypes[methname, args]
+        except KeyError:
+            btype = getattr(self, methname)(*args)
+            self._cached_btypes[methname, args] = btype
+        return btype

ffi/backend_ctypes.py

 import ctypes, ctypes.util
+from ffi.backend_base import BackendBase
 
 
 class CTypesData(object):
     def _export(ctypes_value):
         raise NotImplementedError
 
+    @classmethod
+    def _get_c_name(cls):
+        return cls._reftypename.replace(' &', '')
 
-class CTypesBackend(object):
+    def __repr__(self):
+        return '<cdata %r>' % (self._get_c_name(),)
+
+    def _cast_to_address_of(self, Class):
+        raise TypeError("cannot cast %r to %r" % (
+            self._get_c_name(), Class._reftypename.replace('&', '*')))
+
+
+class CTypesBackend(BackendBase):
 
     PRIMITIVE_TYPES = {
         'short': ctypes.c_short,
         #
         class CTypesInt(CTypesData):
             _ctype = ctype
+            _reftypename = '%s &' % name
 
             def __init__(self, value=0):
                 if ctype(value).value != value:
         #
         return CTypesInt
 
+    def new_pointer_type(self, bitem):
+        #
+        class CTypesPtr(CTypesData):
+            _ctype = ctypes.POINTER(bitem._ctype)
+            _reftypename = bitem._reftypename.replace('&', '* &')
+
+            def __init__(self, init):
+                if init is None:
+                    address = 0      # null pointer
+                elif isinstance(init, CTypesData):
+                    address = init._cast_to_address_of(bitem)
+                else:
+                    raise TypeError("%r expected, got %r" % (
+                        CTypesPtr._get_c_name(), type(init).__name__))
+                self._address = ctypes.cast(address, self._ctype)
+
+            def __getitem__(self, index):
+                return bitem._export(self._address[index])
+
+            def __setitem__(self, index, value):
+                self._address[index] = bitem._import(value)
+        #
+        return CTypesPtr
+
     def new_array_type(self, bitem, length):
+        if length is None:
+            brackets = '[] &'
+        else:
+            brackets = '[%d] &' % length
+        reftypename = bitem._reftypename.replace(' &', brackets)
         #
         class CTypesArray(CTypesData):
             if length is not None:
                 _ctype = bitem._ctype * length
+            _reftypename = reftypename
 
             def __init__(self, init):
                 if length is not None:
                     raise IndexError
                 self._blob[index] = bitem._import(value)
 
-            @staticmethod
-            def _export(xx):
-                xxx
+            def _cast_to_address_of(self, bexpecteditem):
+                if bitem is bexpecteditem:
+                    return ctypes.addressof(self._blob)
+                else:
+                    return CTypesData._cast_to_address_of(self, bexpecteditem)
         #
         return CTypesArray
 

testing/backend_tests.py

         assert p[1] == -7
         py.test.raises(IndexError, "p[2]")
 
+    def test_cannot_cast(self):
+        ffi = FFI(backend=self.Backend())
+        a = ffi.new("short int[10]")
+        e = py.test.raises(TypeError, ffi.new, "long int *", a)
+        assert str(e.value) == "cannot cast 'short[10]' to 'long *'"
+
+    def test_new_pointer_to_array(self):
+        ffi = FFI(backend=self.Backend())
+        a = ffi.new("int[4]", [100, 102, 104, 106])
+        p = ffi.new("int *", a)
+        assert p[0] == 100
+        assert p[1] == 102
+        assert p[2] == 104
+        assert p[3] == 106
+        # keepalive: a
+
     def test_new_array_of_array(self):
         py.test.skip("in-progress")
         ffi = FFI(backend=self.Backend())

testing/test_cdata.py

 from ffi import FFI
+from ffi.backend_base import BackendBase
 
-class FakeBackend(object):
+class FakeBackend(BackendBase):
 
     def load_library(self):
         return None

testing/test_parsing.py

 from ffi import FFI
+from ffi.backend_base import BackendBase
 
-
-class FakeBackend(object):
+class FakeBackend(BackendBase):
     
     def load_library(self, name=Ellipsis):
         assert name in [Ellipsis, "foobar"]
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.