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

Reply via email to