Commits

Armin Rigo committed 81d9d6f

- arrays of arrays, and generally found the correct arrangement
of classes without using '&' classes explicitly

- integer arithmetic (limited to equality and ordering)

  • Participants
  • Parent commits 05168e9

Comments (0)

Files changed (4)

         return self._get_btype(typenode)
 
     def new(self, cdecl, init=None):
-        btype = self.typeof(cdecl)
-        return btype(init)
+        BType = self.typeof(cdecl)
+        return BType(init)
 
     def _parse_type(self, cdecl):
         try:
                 assert isinstance(typenode.dim, pycparser.c_ast.Constant), (
                     "non-constant array length")
                 length = int(typenode.dim.value)
-            bitem = self._get_btype(typenode.type)
+            BItem = self._get_btype(typenode.type)
             return self._backend.get_cached_btype('new_array_type',
-                                                  bitem, length)
+                                                  BItem, length)
         #
         elif isinstance(typenode, pycparser.c_ast.TypeDecl):
             # assume a primitive type
             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)
+            BItem = self._get_btype(typenode.type)
+            return self._backend.get_cached_btype("new_pointer_type", BItem)
         #
         else:
             raise FFIError("bad or unsupported type declaration")

ffi/backend_base.py

 
     def get_cached_btype(self, methname, *args):
         try:
-            btype = self._cached_btypes[methname, args]
+            BType = self._cached_btypes[methname, args]
         except KeyError:
-            btype = getattr(self, methname)(*args)
-            self._cached_btypes[methname, args] = btype
-        return btype
+            BType = getattr(self, methname)(*args)
+            self._cached_btypes[methname, args] = BType
+        return BType

ffi/backend_ctypes.py

 
     @staticmethod
     def _import(value):
-        x
+        raise NotImplementedError
 
     @staticmethod
     def _export(ctypes_value):
         raise NotImplementedError
 
     @classmethod
-    def _get_c_name(cls):
-        return cls._reftypename.replace(' &', '')
+    def _get_c_name(cls, replace_with=''):
+        return cls._reftypename.replace(' &', replace_with)
 
     @classmethod
     def _fix_class(cls):
     def __repr__(self):
         return '<cdata %r>' % (self._get_c_name(),)
 
-    def _convert_to_address_of(self, Class):
+    def _convert_to_address_of(self, BClass):
         raise TypeError("cannot convert %r to %r" % (
-            self._get_c_name(), Class._reftypename.replace('&', '*')))
+            self._get_c_name(), BClass._get_c_name(' *')))
 
 
 class CTypesBackend(BackendBase):
             def __int__(self):
                 return self._value
 
+            def __nonzero__(self):   return self._value
+            def __lt__(self, other): return self._value <  other
+            def __le__(self, other): return self._value <= other
+            def __eq__(self, other): return self._value == other
+            def __ne__(self, other): return self._value != other
+            def __gt__(self, other): return self._value >  other
+            def __ge__(self, other): return self._value >= other
+            def __hash__(self):      return hash(self._value)
+
             @staticmethod
             def _import(x):
                 if not isinstance(x, (int, long)):
         CTypesInt._fix_class()
         return CTypesInt
 
-    def new_pointer_type(self, bitem):
+    def new_pointer_type(self, BItem):
         #
         class CTypesPtr(CTypesData):
-            _ctype = ctypes.POINTER(bitem._ctype)
-            _reftypename = bitem._reftypename.replace('&', '* &')
+            _ctype = ctypes.POINTER(BItem._ctype)
+            _reftypename = BItem._get_c_name(' * &')
 
             def __init__(self, init):
                 if init is None:
                     address = 0      # null pointer
                 elif isinstance(init, CTypesData):
-                    address = init._convert_to_address_of(bitem)
+                    address = init._convert_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)
+                self._address = address
+                self._as_ctype_ptr = ctypes.cast(address, CTypesPtr._ctype)
+
+            @classmethod
+            def _from_ctype_ptr(cls, ptr):
+                self._address = ctypes.addressof(ptr.contents)
+                self._as_ctype_ptr = ptr
+
+            def __nonzero__(self):
+                return self._address
+
+            def __eq__(self, other):
+                return (isinstance(other, CTypesPtr) and
+                        self._address == other._address)
+
+            def __ne__(self, other):
+                return not (isinstance(other, CTypesPtr) and
+                            self._address == other._address)
 
             def __getitem__(self, index):
-                return bitem._export(self._address[index])
+                return BItem._export(self._as_ctype_ptr[index])
 
             def __setitem__(self, index, value):
-                self._address[index] = bitem._import(value)
+                self._as_ctype_ptr[index] = BItem._import(value)
         #
         CTypesPtr._fix_class()
         return CTypesPtr
 
-    def new_array_type(self, bitem, length):
+    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
+                _ctype = BItem._ctype * length
+            _reftypename = BItem._get_c_name(brackets)
 
             def __init__(self, init):
                 if length is not None:
                     len1 = length
+                    self._blob = self._ctype()
                 else:
                     if isinstance(init, (int, long)):
                         len1 = init
                         init = None
                     else:
                         len1 = len(init)
-                self._blob = (bitem._ctype * len1)()
+                    self._blob = (BItem._ctype * len1)()
                 if init is not None:
                     for i, value in enumerate(init):
                         self[i] = value
             def __getitem__(self, index):
                 if not (0 <= index < len(self._blob)):
                     raise IndexError
-                return bitem._export(self._blob[index])
+                return BItem._export(self._blob[index])
 
             def __setitem__(self, index, value):
                 if not (0 <= index < len(self._blob)):
                     raise IndexError
-                self._blob[index] = bitem._import(value)
+                self._blob[index] = BItem._import(value)
 
-            def _convert_to_address_of(self, bexpecteditem):
-                if bitem is bexpecteditem:
+            def _convert_to_address_of(self, BClass):
+                if BItem is BClass:
                     return ctypes.addressof(self._blob)
-                return CTypesData._convert_to_address_of(self, bexpecteditem)
+                else:
+                    return CTypesData._convert_to_address_of(self, BClass)
+
+            @staticmethod
+            def _export(ctypes_array):
+                self = CTypesArray.__new__(CTypesArray)
+                self._blob = ctypes_array
+                return self
         #
         CTypesArray._fix_class()
         return CTypesArray

testing/backend_tests.py

                 py.test.raises(OverflowError, ffi.new, c_decl, min - 1)
                 py.test.raises(OverflowError, ffi.new, c_decl, max + 1)
 
+    def test_int_equality(self):
+        ffi = FFI(backend=self.Backend())
+        n = ffi.new("short", -123)
+        assert bool(n)
+        assert n == -123
+        assert n == ffi.new("int", -123)
+        assert not bool(ffi.new("short", 0))
+        assert n != ffi.new("short", 123)
+        assert hash(n) == hash(-123)
+        assert n < -122
+        assert n <= -123
+        assert n > -124
+        assert n >= -123
+        assert not (n < -123)
+        assert not (n <= -124)
+        assert not (n > -123)
+        assert not (n >= -122)
+
     def test_new_array_no_arg(self):
         ffi = FFI(backend=self.Backend())
         p = ffi.new("int[10]")
         assert p[3] == 106
         # keepalive: a
 
+    def test_pointer_direct(self):
+        ffi = FFI(backend=self.Backend())
+        p = ffi.new("int*")
+        assert bool(p) is False
+        assert p == ffi.new("int*")
+        a = ffi.new("int[]", [123, 456])
+        p = ffi.new("int*", a)
+        assert bool(p) is True
+        assert p == ffi.new("int*", a)
+        assert p != ffi.new("int*")
+        assert p[0] == 123
+        assert p[1] == 456
+
     def test_repr(self):
         ffi = FFI(backend=self.Backend())
         p = ffi.new("unsigned short int")
         assert repr(type(p)) == "<class 'ffi.CData<int *[2][3]>'>"
 
     def test_new_array_of_array(self):
-        py.test.skip("in-progress")
         ffi = FFI(backend=self.Backend())
         p = ffi.new("int[3][4]")
         p[0][0] = 10