[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