[pypy-commit] cffi cffi-1.0: subclassing of the FFI class

arigo noreply at buildbot.pypy.org
Wed Apr 15 15:14:58 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1712:dc08ca1cf470
Date: 2015-04-15 15:15 +0200
http://bitbucket.org/cffi/cffi/changeset/dc08ca1cf470/

Log:	subclassing of the FFI class

diff --git a/new/cffi1_module.c b/new/cffi1_module.c
--- a/new/cffi1_module.c
+++ b/new/cffi1_module.c
@@ -46,7 +46,8 @@
     if (m == NULL)
         return -1;
 
-    FFIObject *ffi = ffi_internal_new(ctx);
+    FFIObject *ffi = ffi_internal_new(NULL, ctx);
+    Py_XINCREF(ffi);    /* make the ffi object really immortal */
     if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0)
         return -1;
 
diff --git a/new/ffi_obj.c b/new/ffi_obj.c
--- a/new/ffi_obj.c
+++ b/new/ffi_obj.c
@@ -26,13 +26,22 @@
     _cffi_opcode_t internal_output[FFI_COMPLEXITY_OUTPUT];
 };
 
-static FFIObject *ffi_internal_new(const struct _cffi_type_context_s *ctx)
+static FFIObject *ffi_internal_new(PyTypeObject *ffitype,
+                                   const struct _cffi_type_context_s *ctx)
 {
     PyObject *dict = PyDict_New();
     if (dict == NULL)
         return NULL;
 
-    FFIObject *ffi = PyObject_GC_New(FFIObject, &FFI_Type);
+    FFIObject *ffi;
+    if (ffitype == NULL) {
+        ffi = (FFIObject *)PyObject_New(FFIObject, &FFI_Type);
+        /* we don't call PyObject_GC_Track() here: from _cffi_init_module()
+           it is not needed, because in this case the ffi object is immortal */
+    }
+    else {
+        ffi = (FFIObject *)ffitype->tp_alloc(ffitype, 0);
+    }
     if (ffi == NULL) {
         Py_DECREF(dict);
         return NULL;
@@ -42,8 +51,6 @@
     ffi->info.ctx = ctx;
     ffi->info.output = ffi->internal_output;
     ffi->info.output_size = FFI_COMPLEXITY_OUTPUT;
-
-    PyObject_GC_Track(ffi);
     return ffi;
 }
 
@@ -52,7 +59,23 @@
     PyObject_GC_UnTrack(ffi);
     Py_DECREF(ffi->types_dict);
     Py_XDECREF(ffi->gc_wrefs);
-    PyObject_GC_Del(ffi);
+
+    {
+        const void *mem[] = {ffi->info.ctx->types,
+                             ffi->info.ctx->globals,
+                             ffi->info.ctx->constants,
+                             ffi->info.ctx->structs_unions,
+                             ffi->info.ctx->fields,
+                             ffi->info.ctx->enums,
+                             ffi->info.ctx->typenames,
+                             ffi->info.ctx};
+        int i;
+        for (i = 0; i < sizeof(mem) / sizeof(*mem); i++) {
+            if (mem[i] != NULL)
+                PyMem_Free((void *)mem[i]);
+        }
+    }
+    Py_TYPE(ffi)->tp_free((PyObject *)ffi);
 }
 
 static int ffi_traverse(FFIObject *ffi, visitproc visit, void *arg)
@@ -65,13 +88,30 @@
 static PyObject *ffiobj_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
     /* user-facing initialization code, for explicit FFI() calls */
-    static const struct _cffi_type_context_s empty_ctx = { 0 };
+    struct _cffi_type_context_s *ctx;
+    PyObject *result;
 
+    ctx = PyMem_Malloc(sizeof(struct _cffi_type_context_s));
+    if (ctx == NULL) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+    memset(ctx, 0, sizeof(struct _cffi_type_context_s));
+
+    result = (PyObject *)ffi_internal_new(type, ctx);
+    if (result == NULL) {
+        PyMem_Free(ctx);
+        return NULL;
+    }
+    return result;
+}
+
+static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds)
+{
     char *keywords[] = {NULL};
     if (!PyArg_ParseTupleAndKeywords(args, kwds, ":FFI", keywords))
-        return NULL;
-
-    return (PyObject *)ffi_internal_new(&empty_ctx);
+        return -1;
+    return 0;
 }
 
 #define ACCEPT_STRING   1
@@ -519,7 +559,8 @@
     PyObject_GenericGetAttr,                    /* tp_getattro */
     0,                                          /* tp_setattro */
     0,                                          /* tp_as_buffer */
-    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,    /* tp_flags */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+        Py_TPFLAGS_BASETYPE,                    /* tp_flags */
     0,                                          /* tp_doc */
     (traverseproc)ffi_traverse,                 /* tp_traverse */
     0,                                          /* tp_clear */
@@ -535,7 +576,7 @@
     0,                                          /* tp_descr_get */
     0,                                          /* tp_descr_set */
     0,                                          /* tp_dictoffset */
-    0,                                          /* tp_init */
+    ffiobj_init,                                /* tp_init */
     0,                                          /* tp_alloc */
     ffiobj_new,                                 /* tp_new */
     PyObject_GC_Del,                            /* tp_free */
diff --git a/new/test_ffi_obj.py b/new/test_ffi_obj.py
--- a/new/test_ffi_obj.py
+++ b/new/test_ffi_obj.py
@@ -1,7 +1,21 @@
+import py
 import _cffi1_backend
 
+
 def test_ffi_new():
     ffi = _cffi1_backend.FFI()
     p = ffi.new("int *")
     p[0] = -42
     assert p[0] == -42
+
+def test_ffi_subclass():
+    class FOO(_cffi1_backend.FFI):
+        def __init__(self, x):
+            self.x = x
+    foo = FOO(42)
+    assert foo.x == 42
+    p = foo.new("int *")
+    assert p[0] == 0
+
+def test_ffi_no_argument():
+    py.test.raises(TypeError, _cffi1_backend.FFI, 42)


More information about the pypy-commit mailing list