[pypy-commit] cffi default: Test iteration over array cdatas, and found out that we need more code.

arigo noreply at buildbot.pypy.org
Sun Jun 17 14:47:42 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r402:5a64a124c201
Date: 2012-06-17 14:46 +0200
http://bitbucket.org/cffi/cffi/changeset/5a64a124c201/

Log:	Test iteration over array cdatas, and found out that we need more
	code.

diff --git a/c/_ffi_backend.c b/c/_ffi_backend.c
--- a/c/_ffi_backend.c
+++ b/c/_ffi_backend.c
@@ -1497,6 +1497,8 @@
     goto done;
 }
 
+static PyObject *cdata_iter(CDataObject *);
+
 static PyNumberMethods CData_as_number = {
     (binaryfunc)cdata_add,      /*nb_add*/
     (binaryfunc)cdata_sub,      /*nb_subtract*/
@@ -1554,6 +1556,8 @@
     (traverseproc)cdata_traverse,               /* tp_traverse */
     0,                                          /* tp_clear */
     cdata_richcompare,                          /* tp_richcompare */
+    0,                                          /* tp_weaklistoffset */
+    (getiterfunc)cdata_iter,                    /* tp_iter */
 };
 
 static PyTypeObject CDataOwning_Type = {
@@ -1624,6 +1628,89 @@
     &CData_Type,                                /* tp_base */
 };
 
+/************************************************************/
+
+typedef struct {
+    PyObject_HEAD
+    char *di_next, *di_stop;
+    CDataObject *di_object;
+    CTypeDescrObject *di_itemtype;
+} CDataIterObject;
+
+static PyObject *
+cdataiter_next(CDataIterObject *it)
+{
+    char *result = it->di_next;
+    if (result != it->di_stop) {
+        it->di_next = result + it->di_itemtype->ct_size;
+        return convert_to_object(result, it->di_itemtype);
+    }
+    return NULL;
+}
+
+static void
+cdataiter_dealloc(CDataIterObject *it)
+{
+    Py_DECREF(it->di_object);
+    PyObject_Del(it);
+}
+
+static PyTypeObject CDataIter_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "_ffi_backend.CDataIter",               /* tp_name */
+    sizeof(CDataIterObject),                /* tp_basicsize */
+    0,                                      /* tp_itemsize */
+    /* methods */
+    (destructor)cdataiter_dealloc,          /* tp_dealloc */
+    0,                                      /* tp_print */
+    0,                                      /* tp_getattr */
+    0,                                      /* tp_setattr */
+    0,                                      /* tp_compare */
+    0,                                      /* tp_repr */
+    0,                                      /* tp_as_number */
+    0,                                      /* tp_as_sequence */
+    0,                                      /* tp_as_mapping */
+    0,                                      /* tp_hash */
+    0,                                      /* tp_call */
+    0,                                      /* tp_str */
+    PyObject_GenericGetAttr,                /* tp_getattro */
+    0,                                      /* tp_setattro */
+    0,                                      /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT,                     /* tp_flags */
+    0,                                      /* tp_doc */
+    0,                                      /* tp_traverse */
+    0,                                      /* tp_clear */
+    0,                                      /* tp_richcompare */
+    0,                                      /* tp_weaklistoffset */
+    PyObject_SelfIter,                      /* tp_iter */
+    (iternextfunc)cdataiter_next,           /* tp_iternext */
+};
+
+static PyObject *
+cdata_iter(CDataObject *cd)
+{
+    CDataIterObject *it;
+
+    if (!(cd->c_type->ct_flags & CT_ARRAY)) {
+        PyErr_Format(PyExc_TypeError, "cdata '%s' does not support iteration",
+                     cd->c_type->ct_name);
+        return NULL;
+    }
+
+    it = PyObject_New(CDataIterObject, &CDataIter_Type);
+    if (it == NULL)
+        return NULL;
+
+    Py_INCREF(cd);
+    it->di_object = cd;
+    it->di_itemtype = cd->c_type->ct_itemdescr;
+    it->di_next = cd->c_data;
+    it->di_stop = cd->c_data + get_array_length(cd) * it->di_itemtype->ct_size;
+    return (PyObject *)it;
+}
+
+/************************************************************/
+
 static PyObject *b_newp(PyObject *self, PyObject *args)
 {
     CTypeDescrObject *ct, *ctitem;
@@ -3443,6 +3530,8 @@
         return;
     if (PyType_Ready(&CDataWithDestructor_Type) < 0)
         return;
+    if (PyType_Ready(&CDataIter_Type) < 0)
+        return;
 
     v = PyCObject_FromVoidPtr((void *)cffi_exports, NULL);
     if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0)
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
--- a/cffi/backend_ctypes.py
+++ b/cffi/backend_ctypes.py
@@ -72,6 +72,10 @@
     def _alignment(cls):
         return ctypes.alignment(cls._ctype)
 
+    def __iter__(self):
+        raise TypeError("cdata %r does not support iteration" % (
+            self._get_c_name()),)
+
 
 class CTypesGenericPrimitive(CTypesData):
     __slots__ = []
@@ -80,6 +84,10 @@
 class CTypesGenericArray(CTypesData):
     __slots__ = []
 
+    def __iter__(self):
+        for i in xrange(len(self)):
+            yield self[i]
+
 
 class CTypesGenericPtr(CTypesData):
     __slots__ = ['_address', '_as_ctype_ptr']
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -694,6 +694,17 @@
         p = ffi.new("int(*)[5]")
         assert repr(p) == "<cdata 'int(* *)[5]' owning %d bytes>" % SIZE_OF_PTR
 
+    def test_iterate_array(self):
+        ffi = FFI(backend=self.Backend())
+        a = ffi.new("char[]", "hello")
+        assert list(a) == ["h", "e", "l", "l", "o", chr(0)]
+        assert list(iter(a)) == ["h", "e", "l", "l", "o", chr(0)]
+        #
+        py.test.raises(TypeError, iter, ffi.cast("char *", a))
+        py.test.raises(TypeError, list, ffi.cast("char *", a))
+        py.test.raises(TypeError, iter, ffi.new("int"))
+        py.test.raises(TypeError, list, ffi.new("int"))
+
     def test_offsetof(self):
         ffi = FFI(backend=self.Backend())
         ffi.cdef("struct foo { int a, b, c; };")


More information about the pypy-commit mailing list