Author: Armin Rigo <[email protected]>
Branch:
Changeset: r157:46722c958fdb
Date: 2014-12-05 10:40 +0100
http://bitbucket.org/cffi/creflect/changeset/46722c958fdb/
Log: starting to port some more cdata logic
diff --git a/zeffir/builder.c b/zeffir/builder.c
--- a/zeffir/builder.c
+++ b/zeffir/builder.c
@@ -269,7 +269,10 @@
if (ct == NULL)
goto done;
+ Py_INCREF(totype);
+ ct->ct_itemdescr = totype;
ct->ct_size = sizeof(void *);
+
ct->ct_flags = CT_POINTER;
if (totype->ct_flags & CT_VOID)
ct->ct_flags |= CT_IS_VOID_PTR;
diff --git a/zeffir/cdata.c b/zeffir/cdata.c
--- a/zeffir/cdata.c
+++ b/zeffir/cdata.c
@@ -1,18 +1,53 @@
-struct CDataObject_s {
+typedef struct {
PyObject_HEAD
CTypeDescrObject *c_type;
char *c_data;
PyObject *c_weakreflist;
-};
+} CDataObject;
-/*
+typedef union {
+ unsigned char m_char;
+ unsigned short m_short;
+ unsigned int m_int;
+ unsigned long m_long;
+ unsigned long long m_longlong;
+ float m_float;
+ double m_double;
+ long double m_longdouble;
+} union_alignment;
+
+typedef struct {
+ CDataObject head;
+ union_alignment alignment;
+} CDataObject_casted_primitive;
+
+typedef struct {
+ CDataObject head;
+ union_alignment alignment;
+} CDataObject_own_nolength;
+
+typedef struct {
+ CDataObject head;
+ Py_ssize_t length;
+ union_alignment alignment;
+} CDataObject_own_length;
+
#define CData_Check(ob) (Py_TYPE(ob) == &CData_Type || \
Py_TYPE(ob) == &CDataOwning_Type || \
Py_TYPE(ob) == &CDataOwningGC_Type)
#define CDataOwn_Check(ob) (Py_TYPE(ob) == &CDataOwning_Type || \
Py_TYPE(ob) == &CDataOwningGC_Type)
-*/
+
+
+static Py_ssize_t get_array_length(CDataObject *cd)
+{
+ if (cd->c_type->ct_length < 0)
+ return ((CDataObject_own_length *)cd)->length;
+ else
+ return cd->c_type->ct_length;
+}
+
static void cdata_dealloc(CDataObject *cd)
{
@@ -25,6 +60,169 @@
#endif
}
+static void cdataowninggc_dealloc(CDataObject *cd)
+{
+ abort();
+#if 0
+ assert(!(cd->c_type->ct_flags & (CT_IS_PTR_TO_OWNED |
+ CT_PRIMITIVE_ANY |
+ CT_STRUCT | CT_UNION)));
+ PyObject_GC_UnTrack(cd);
+
+ if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */
+ PyObject *x = (PyObject *)(cd->c_data + 42);
+ Py_DECREF(x);
+ }
+ else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */
+ ffi_closure *closure = (ffi_closure *)cd->c_data;
+ PyObject *args = (PyObject *)(closure->user_data);
+ Py_XDECREF(args);
+ cffi_closure_free(closure);
+ }
+ cdata_dealloc(cd);
+#endif
+}
+
+static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg)
+{
+ abort();
+#if 0
+ if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */
+ PyObject *x = (PyObject *)(cd->c_data + 42);
+ Py_VISIT(x);
+ }
+ else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */
+ ffi_closure *closure = (ffi_closure *)cd->c_data;
+ PyObject *args = (PyObject *)(closure->user_data);
+ Py_VISIT(args);
+ }
+ return 0;
+#endif
+}
+
+static int cdataowninggc_clear(CDataObject *cd)
+{
+ abort();
+#if 0
+ if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */
+ PyObject *x = (PyObject *)(cd->c_data + 42);
+ Py_INCREF(Py_None);
+ cd->c_data = ((char *)Py_None) - 42;
+ Py_DECREF(x);
+ }
+ else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */
+ ffi_closure *closure = (ffi_closure *)cd->c_data;
+ PyObject *args = (PyObject *)(closure->user_data);
+ closure->user_data = NULL;
+ Py_XDECREF(args);
+ }
+ return 0;
+#endif
+}
+
+static PyObject *cdata_repr(CDataObject *cd)
+{
+ char *extra;
+ PyObject *result, *s;
+
+ if (cd->c_type->ct_flags & CT_PRIMITIVE_ANY) {
+ abort();//XXX
+#if 0
+ if (cd->c_type->ct_flags & CT_IS_ENUM) {
+ s = convert_cdata_to_enum_string(cd, 1);
+ }
+ else if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) {
+ long double lvalue;
+ char buffer[128]; /* big enough */
+ /*READ(cd->c_data, sizeof(long double)*/
+ lvalue = read_raw_longdouble_data(cd->c_data);
+ sprintf(buffer, "%LE", lvalue);
+ s = PyText_FromString(buffer);
+ }
+ else {
+ PyObject *o = convert_to_object(cd->c_data, cd->c_type);
+ if (o == NULL)
+ return NULL;
+ s = PyObject_Repr(o);
+ Py_DECREF(o);
+ }
+#endif
+ }
+ else if ((cd->c_type->ct_flags & CT_ARRAY) && cd->c_type->ct_length < 0) {
+ s = PyString_FromFormat("sliced length %zd", get_array_length(cd));
+ }
+ else {
+ if (cd->c_data != NULL) {
+ s = PyString_FromFormat("%p", cd->c_data);
+ }
+ else
+ s = PyString_FromString("NULL");
+ }
+ if (s == NULL)
+ return NULL;
+ /* it's slightly confusing to get "<cdata 'struct foo' 0x...>" because the
+ struct foo is not owned. Trying to make it clearer, write in this
+ case "<cdata 'struct foo &' 0x...>". */
+ if (cd->c_type->ct_flags & (CT_STRUCT|CT_UNION))
+ extra = " &";
+ else
+ extra = "";
+ result = PyString_FromFormat("<cdata '%s%s' %s>",
+ cd->c_type->ct_name, extra,
+ PyString_AsString(s));
+ Py_DECREF(s);
+ return result;
+}
+
+static PyObject *_cdata_repr2(CDataObject *cd, char *text, PyObject *x)
+{
+ PyObject *res, *s = PyObject_Repr(x);
+ if (s == NULL)
+ return NULL;
+ res = PyString_FromFormat("<cdata '%s' %s %s>",
+ cd->c_type->ct_name, text, PyString_AsString(s));
+ Py_DECREF(s);
+ return res;
+}
+
+static PyObject *cdataowning_repr(CDataObject *cd)
+{
+ Py_ssize_t size;
+ if (cd->c_type->ct_flags & CT_POINTER) {
+ if (cd->c_type->ct_flags & CT_IS_VOID_PTR)
+ goto handle_repr;
+ size = cd->c_type->ct_itemdescr->ct_size;
+ }
+ else if (cd->c_type->ct_flags & CT_ARRAY)
+ size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
+#if 0 // XXX
+ else if (cd->c_type->ct_flags & CT_FUNCTIONPTR)
+ goto callback_repr;
+#endif
+ else
+ size = cd->c_type->ct_size;
+
+ return PyString_FromFormat("<cdata '%s' owning %zd bytes>",
+ cd->c_type->ct_name, size);
+
+#if 0
+ callback_repr:
+ {
+ PyObject *args = (PyObject *)((ffi_closure *)cd->c_data)->user_data;
+ if (args == NULL)
+ return cdata_repr(cd);
+ else
+ return _cdata_repr2(cd, "calling", PyTuple_GET_ITEM(args, 1));
+ }
+#endif
+
+ handle_repr:
+ {
+ PyObject *x = (PyObject *)(cd->c_data + 42);
+ return _cdata_repr2(cd, "handle to", x);
+ }
+}
+
static PyTypeObject CData_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"zeffir.CData",
@@ -35,7 +233,7 @@
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
- 0,//(reprfunc)cdata_repr, /* tp_repr */
+ (reprfunc)cdata_repr, /* tp_repr */
0,//&CData_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0,//&CData_as_mapping, /* tp_as_mapping */
@@ -54,3 +252,86 @@
0,//(getiterfunc)cdata_iter, /* tp_iter */
0, /* tp_iternext */
};
+
+static PyTypeObject CDataOwning_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "zeffir.CDataOwn",
+ sizeof(CDataObject),
+ 0,
+ (destructor)cdata_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)cdataowning_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0,//&CDataOwn_as_mapping, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &CData_Type, /* tp_base */
+};
+
+static PyTypeObject CDataOwningGC_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "zeffir.CDataOwnGC",
+ sizeof(CDataObject),
+ 0,
+ (destructor)cdataowninggc_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 */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */
+ | Py_TPFLAGS_HAVE_GC,
+ 0, /* tp_doc */
+ (traverseproc)cdataowninggc_traverse, /* tp_traverse */
+ (inquiry)cdataowninggc_clear, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ &CDataOwning_Type, /* tp_base */
+};
+
+static CDataObject *allocate_owning_object(Py_ssize_t size,
+ CTypeDescrObject *ct)
+{
+ CDataObject *cd;
+ cd = (CDataObject *)PyObject_Malloc(size);
+ if (PyObject_Init((PyObject *)cd, &CDataOwning_Type) == NULL)
+ return NULL;
+
+ Py_INCREF(ct);
+ cd->c_type = ct;
+ cd->c_weakreflist = NULL;
+ return cd;
+}
diff --git a/zeffir/ctype.c b/zeffir/ctype.c
--- a/zeffir/ctype.c
+++ b/zeffir/ctype.c
@@ -16,7 +16,6 @@
#define CT_CAST_ANYTHING 2048 /* 'char *' and 'void *' only */
#define CT_PRIMITIVE_FITS_LONG 4096
#define CT_IS_ENUM 8192
-#define CT_IS_PTR_TO_OWNED 16384
#define CT_IS_LONGDOUBLE 65536
#define CT_IS_BOOL 131072
#define CT_IS_VOID_PTR 524288
diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c
--- a/zeffir/ffi_obj.c
+++ b/zeffir/ffi_obj.c
@@ -35,7 +35,7 @@
static PyObject *ffiobj_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
char *keywords[] = {NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "", keywords))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, ":FFI", keywords))
return NULL;
PyObject *dict = PyDict_New();
@@ -62,7 +62,7 @@
PyObject *path;
ZefLibObject *lib;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|z", keywords,
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|z:load_library", keywords,
&libname, &relative_to))
return NULL;
@@ -100,7 +100,7 @@
{
ZefLibObject *lib;
- if (!PyArg_ParseTuple(args, "O!", &lib, &ZefLib_Type))
+ if (!PyArg_ParseTuple(args, "O!:close_library", &lib, &ZefLib_Type))
return NULL;
if (lib_close(lib) < 0)
@@ -110,12 +110,18 @@
return Py_None;
}
-static CTypeDescrObject *_ffi_type(ZefFFIObject *ffi, PyObject *arg)
+#define ACCEPT_STRING 1
+#define ACCEPT_CTYPE 2
+#define ACCEPT_CDATA 4
+#define ACCEPT_ALL (ACCEPT_STRING | ACCEPT_CTYPE | ACCEPT_CDATA)
+
+static CTypeDescrObject *_ffi_type(ZefFFIObject *ffi, PyObject *arg,
+ int accept)
{
/* Returns the CTypeDescrObject from the user-supplied 'arg'.
Does not return a new reference!
*/
- if (PyString_Check(arg)) {
+ if ((accept & ACCEPT_STRING) && PyString_Check(arg)) {
PyObject *x = PyDict_GetItem(ffi->types_dict, arg);
if (x != NULL && CTypeDescr_Check(x))
return (CTypeDescrObject *)x;
@@ -130,24 +136,34 @@
Py_DECREF(x);
return ct;
}
- else if (CTypeDescr_Check(arg)) {
+ else if ((accept & ACCEPT_CTYPE) && CTypeDescr_Check(arg)) {
return (CTypeDescrObject *)arg;
}
+ else if ((accept & ACCEPT_CDATA) && CData_Check(arg)) {
+ return ((CDataObject *)arg)->c_type;
+ }
else {
- PyErr_SetString(PyExc_TypeError, "expected a string or a ctype
object");
+ const char *m1 = (accept & ACCEPT_STRING) ? "string" : "";
+ const char *m2 = (accept & ACCEPT_CTYPE) ? "ctype object" : "";
+ const char *m3 = (accept & ACCEPT_CDATA) ? "cdata object" : "";
+ const char *s12 = (*m1 && (*m2 || *m3)) ? " or " : "";
+ const char *s23 = (*m2 && *m3) ? " or " : "";
+ PyErr_Format(PyExc_TypeError, "expected a %s%s%s%s%s, got '%.200s'",
+ m1, s12, m2, s23, m3,
+ Py_TYPE(arg)->tp_name);
return NULL;
}
}
static PyObject *ffi_sizeof(ZefFFIObject *self, PyObject *arg)
{
- CTypeDescrObject *ct = _ffi_type(self, arg);
+ CTypeDescrObject *ct = _ffi_type(self, arg, ACCEPT_ALL);
if (ct == NULL)
return NULL;
if (ct->ct_size < 0) {
- PyErr_Format(ZefError, "don't know the size of ctype '%s': "
- "incomplete type", ct->ct_name);
+ PyErr_Format(ZefError, "don't know the size of ctype '%s'",
+ ct->ct_name);
return NULL;
}
return PyInt_FromSsize_t(ct->ct_size);
@@ -155,20 +171,97 @@
static PyObject *ffi_typeof(ZefFFIObject *self, PyObject *arg)
{
- if (!PyString_Check(arg)) {
- PyErr_SetString(PyExc_TypeError, "expected a string");
+ PyObject *x = (PyObject *)_ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CDATA);
+ Py_XINCREF(x);
+ return x;
+}
+
+static PyObject *ffi_new(ZefFFIObject *self, PyObject *args)
+{
+ CTypeDescrObject *ct, *ctitem;
+ CDataObject *cd;
+ PyObject *arg, *init = Py_None;
+ Py_ssize_t dataoffset, datasize, explicitlength;
+ if (!PyArg_ParseTuple(args, "O|O:new", &arg, &init))
+ return NULL;
+
+ ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE);
+ if (ct == NULL)
+ return NULL;
+
+ explicitlength = -1;
+ if (ct->ct_flags & CT_POINTER) {
+ dataoffset = offsetof(CDataObject_own_nolength, alignment);
+ ctitem = ct->ct_itemdescr;
+ datasize = ctitem->ct_size;
+ if (datasize < 0) {
+ PyErr_Format(PyExc_TypeError,
+ "cannot instantiate ctype '%s' of unknown size",
+ ctitem->ct_name);
+ return NULL;
+ }
+ if (ctitem->ct_flags & CT_PRIMITIVE_CHAR)
+ datasize *= 2; /* forcefully add another character: a null */
+
+ /* XXX
+ if ((ctitem->ct_flags & CT_WITH_VAR_ARRAY) && init != Py_None) {
+ Py_ssize_t optvarsize = datasize;
+ if (convert_struct_from_object(NULL,ctitem, init, &optvarsize) < 0)
+ return NULL;
+ datasize = optvarsize;
+ }*/
+ }
+ /* XXX
+ else if (ct->ct_flags & CT_ARRAY) {
+ dataoffset = offsetof(CDataObject_own_nolength, alignment);
+ datasize = ct->ct_size;
+ if (datasize < 0) {
+ explicitlength = get_new_array_length(&init);
+ if (explicitlength < 0)
+ return NULL;
+ ctitem = ct->ct_itemdescr;
+ dataoffset = offsetof(CDataObject_own_length, alignment);
+ datasize = explicitlength * ctitem->ct_size;
+ if (explicitlength > 0 &&
+ (datasize / explicitlength) != ctitem->ct_size) {
+ PyErr_SetString(PyExc_OverflowError,
+ "array size would overflow a Py_ssize_t");
+ return NULL;
+ }
+ }
+ }*/
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "expected a pointer or array ctype, got '%s'",
+ ct->ct_name);
return NULL;
}
- PyObject *x = (PyObject *)_ffi_type(self, arg);
- Py_XINCREF(x);
- return x;
+ cd = allocate_owning_object(dataoffset + datasize, ct);
+ if (cd == NULL)
+ return NULL;
+
+ cd->c_data = ((char *)cd) + dataoffset;
+ if (explicitlength >= 0)
+ ((CDataObject_own_length*)cd)->length = explicitlength;
+
+ memset(cd->c_data, 0, datasize);
+ if (init != Py_None) {
+ /* XXX
+ if (convert_from_object(cd->c_data,
+ (ct->ct_flags & CT_POINTER) ? ct->ct_itemdescr : ct, init) < 0) {
+ Py_DECREF(cd);
+ return NULL;
+ }*/
+ }
+ return (PyObject *)cd;
}
static PyMethodDef ffi_methods[] = {
{"close_library", ffi_close_library, METH_VARARGS | METH_STATIC},
{"load_library", (PyCFunction)ffi_load_library,
METH_VARARGS | METH_KEYWORDS},
+ {"new", (PyCFunction)ffi_new, METH_VARARGS},
{"sizeof", (PyCFunction)ffi_sizeof, METH_O},
{"typeof", (PyCFunction)ffi_typeof, METH_O},
{NULL}
diff --git a/zeffir/test/test_cdata.py b/zeffir/test/test_cdata.py
new file mode 100644
--- /dev/null
+++ b/zeffir/test/test_cdata.py
@@ -0,0 +1,8 @@
+import py
+import support
+
+
+def test_simple_new():
+ ffi = support.new_ffi()
+ p = ffi.new("short *")
+ assert repr(p) == "<cdata 'short *' owning 2 bytes>"
diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c
--- a/zeffir/zeffir.c
+++ b/zeffir/zeffir.c
@@ -42,6 +42,10 @@
return;
if (PyType_Ready(&CData_Type) < 0)
return;
+ if (PyType_Ready(&CDataOwning_Type) < 0)
+ return;
+ if (PyType_Ready(&CDataOwningGC_Type) < 0)
+ return;
if (PyType_Ready(&ZefFuncSupport_Type) < 0)
return;
if (PyType_Ready(&ZefGlobSupport_Type) < 0)
diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h
--- a/zeffir/zeffir.h
+++ b/zeffir/zeffir.h
@@ -1,6 +1,5 @@
typedef struct _crx_type_s CTypeDescrObject;
-typedef struct CDataObject_s CDataObject;
typedef struct ZefLibObject_s ZefLibObject;
typedef struct ZefFFIObject_s ZefFFIObject;
@@ -8,8 +7,8 @@
static PyTypeObject CTypeDescr_Type;
//static PyTypeObject CField_Type;
static PyTypeObject CData_Type;
-//static PyTypeObject CDataOwning_Type;
-//static PyTypeObject CDataOwningGC_Type;
+static PyTypeObject CDataOwning_Type;
+static PyTypeObject CDataOwningGC_Type;
static PyObject *ZefError;
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit