Author: Armin Rigo <ar...@tunes.org> 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 pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit