[pypy-commit] creflect default: copy cdata_as_number from _cffi_backend

arigo noreply at buildbot.pypy.org
Fri Dec 5 21:41:57 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r182:7f8cb0c71de4
Date: 2014-12-05 21:42 +0100
http://bitbucket.org/cffi/creflect/changeset/7f8cb0c71de4/

Log:	copy cdata_as_number from _cffi_backend

diff --git a/zeffir/cdata.c b/zeffir/cdata.c
--- a/zeffir/cdata.c
+++ b/zeffir/cdata.c
@@ -1050,6 +1050,85 @@
     }
 }
 
+//1699
+static int cdata_nonzero(CDataObject *cd)
+{
+    return cd->c_data != NULL;
+}
+
+
+//1751
+static PyObject *cdata_float(CDataObject *cd)
+{
+    if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) {
+        double value;
+        /*READ(cd->c_data, cd->c_type->ct_size)*/
+        if (!(cd->c_type->ct_flags & CT_IS_LONGDOUBLE)) {
+            value = read_raw_float_data(cd->c_data, cd->c_type->ct_size);
+        }
+        else {
+            value = (double)read_raw_longdouble_data(cd->c_data);
+        }
+        return PyFloat_FromDouble(value);
+    }
+    PyErr_Format(PyExc_TypeError, "float() not supported on cdata '%s'",
+                 cd->c_type->ct_name);
+    return NULL;
+}
+
+//1700
+static PyObject *cdata_int(CDataObject *cd)
+{
+    if ((cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_FITS_LONG))
+                             == (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_FITS_LONG)) {
+        /* this case is to handle enums, but also serves as a slight
+           performance improvement for some other primitive types */
+        long value;
+        /*READ(cd->c_data, cd->c_type->ct_size)*/
+        value = (long)read_raw_signed_data(cd->c_data, cd->c_type->ct_size);
+        return PyInt_FromLong(value);
+    }
+    if (cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) {
+        return convert_to_object(cd->c_data, cd->c_type);
+    }
+    else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) {
+        /*READ(cd->c_data, cd->c_type->ct_size)*/
+        if (cd->c_type->ct_size == sizeof(char))
+            return PyInt_FromLong((unsigned char)cd->c_data[0]);
+#ifdef HAVE_WCHAR_H
+        else
+            return PyInt_FromLong((long)*(wchar_t *)cd->c_data);
+#endif
+    }
+    else if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) {
+        PyObject *o = cdata_float(cd);
+#if PY_MAJOR_VERSION < 3
+        PyObject *r = o ? PyNumber_Int(o) : NULL;
+#else
+        PyObject *r = o ? PyNumber_Long(o) : NULL;
+#endif
+        Py_XDECREF(o);
+        return r;
+    }
+    PyErr_Format(PyExc_TypeError, "int() not supported on cdata '%s'",
+                 cd->c_type->ct_name);
+    return NULL;
+}
+
+#if PY_MAJOR_VERSION < 3
+//1739
+static PyObject *cdata_long(CDataObject *cd)
+{
+    PyObject *res = cdata_int(cd);
+    if (res != NULL && PyInt_CheckExact(res)) {
+        PyObject *o = PyLong_FromLong(PyInt_AS_LONG(res));
+        Py_DECREF(res);
+        res = o;
+    }
+    return res;
+}
+#endif
+
 //1769
 static PyObject *cdata_richcompare(PyObject *v, PyObject *w, int op)
 {
@@ -1337,6 +1416,97 @@
     return convert_from_object(c, ctitem, v);
 }
 
+//2081
+static PyObject *_cdata_add_or_sub(PyObject *v, PyObject *w, int sign)
+{
+    Py_ssize_t i, itemsize;
+    CDataObject *cd;
+    CTypeDescrObject *ctptr;
+
+    if (!CData_Check(v)) {
+        PyObject *swap;
+        assert(CData_Check(w));
+        if (sign != 1)
+            goto not_implemented;
+        swap = v;
+        v = w;
+        w = swap;
+    }
+
+    i = PyNumber_AsSsize_t(w, PyExc_OverflowError);
+    if (i == -1 && PyErr_Occurred())
+        return NULL;
+    i *= sign;
+
+    cd = (CDataObject *)v;
+    if (cd->c_type->ct_flags & CT_POINTER)
+        ctptr = cd->c_type;
+    else if (cd->c_type->ct_flags & CT_ARRAY) {
+        ctptr = (CTypeDescrObject *)cd->c_type->ct_stuff;
+    }
+    else {
+        PyErr_Format(PyExc_TypeError, "cannot add a cdata '%s' and a number",
+                     cd->c_type->ct_name);
+        return NULL;
+    }
+    itemsize = ctptr->ct_itemdescr->ct_size;
+    if (itemsize < 0) {
+        if (ctptr->ct_flags & CT_IS_VOID_PTR) {
+            itemsize = 1;
+        }
+        else {
+            PyErr_Format(PyExc_TypeError,
+                         "ctype '%s' points to items of unknown size",
+                         cd->c_type->ct_name);
+            return NULL;
+        }
+    }
+    return new_simple_cdata(cd->c_data + i * itemsize, ctptr);
+
+ not_implemented:
+    Py_INCREF(Py_NotImplemented);
+    return Py_NotImplemented;
+}
+
+//2133
+static PyObject *cdata_add(PyObject *v, PyObject *w)
+{
+    return _cdata_add_or_sub(v, w, +1);
+}
+
+//2139
+static PyObject *cdata_sub(PyObject *v, PyObject *w)
+{
+    if (CData_Check(v) && CData_Check(w)) {
+        CDataObject *cdv = (CDataObject *)v;
+        CDataObject *cdw = (CDataObject *)w;
+        CTypeDescrObject *ct = cdw->c_type;
+        Py_ssize_t diff, itemsize;
+
+        if (ct->ct_flags & CT_ARRAY)     /* ptr_to_T - array_of_T: ok */
+            ct = (CTypeDescrObject *)ct->ct_stuff;
+
+        if (ct != cdv->c_type || !(ct->ct_flags & CT_POINTER) ||
+                (ct->ct_itemdescr->ct_size <= 0 &&
+                 !(ct->ct_flags & CT_IS_VOID_PTR))) {
+            PyErr_Format(PyExc_TypeError,
+                         "cannot subtract cdata '%s' and cdata '%s'",
+                         cdv->c_type->ct_name, ct->ct_name);
+            return NULL;
+        }
+        itemsize = ct->ct_itemdescr->ct_size;
+        if (itemsize <= 0) itemsize = 1;
+        diff = (cdv->c_data - cdw->c_data) / itemsize;
+#if PY_MAJOR_VERSION < 3
+        return PyInt_FromSsize_t(diff);
+#else
+        return PyLong_FromSsize_t(diff);
+#endif
+    }
+
+    return _cdata_add_or_sub(v, w, -1);
+}
+
 //2172
 static PyObject *cdata_getattro(CDataObject *cd, PyObject *attr)
 {
@@ -1390,6 +1560,40 @@
 }
 
 
+static PyNumberMethods CData_as_number = {
+    (binaryfunc)cdata_add,      /*nb_add*/
+    (binaryfunc)cdata_sub,      /*nb_subtract*/
+    0,                          /*nb_multiply*/
+#if PY_MAJOR_VERSION < 3
+    0,                          /*nb_divide*/
+#endif
+    0,                          /*nb_remainder*/
+    0,                          /*nb_divmod*/
+    0,                          /*nb_power*/
+    0,                          /*nb_negative*/
+    0,                          /*nb_positive*/
+    0,                          /*nb_absolute*/
+    (inquiry)cdata_nonzero,     /*nb_nonzero*/
+    0,                          /*nb_invert*/
+    0,                          /*nb_lshift*/
+    0,                          /*nb_rshift*/
+    0,                          /*nb_and*/
+    0,                          /*nb_xor*/
+    0,                          /*nb_or*/
+#if PY_MAJOR_VERSION < 3
+    0,                          /*nb_coerce*/
+#endif
+    (unaryfunc)cdata_int,       /*nb_int*/
+#if PY_MAJOR_VERSION < 3
+    (unaryfunc)cdata_long,      /*nb_long*/
+#else
+    0,
+#endif
+    (unaryfunc)cdata_float,     /*nb_float*/
+    0,                          /*nb_oct*/
+    0,                          /*nb_hex*/
+};
+
 static PyMappingMethods CData_as_mapping = {
     (lenfunc)cdata_length, /*mp_length*/
     (binaryfunc)cdata_subscript, /*mp_subscript*/
@@ -1407,7 +1611,7 @@
     0,                                          /* tp_setattr */
     0,                                          /* tp_compare */
     (reprfunc)cdata_repr,                       /* tp_repr */
-    0,//&CData_as_number,                           /* tp_as_number */
+    &CData_as_number,                           /* tp_as_number */
     0,                                          /* tp_as_sequence */
     &CData_as_mapping,                          /* tp_as_mapping */
     (hashfunc)cdata_hash,                       /* tp_hash */
diff --git a/zeffir/test/test_cdata.py b/zeffir/test/test_cdata.py
--- a/zeffir/test/test_cdata.py
+++ b/zeffir/test/test_cdata.py
@@ -25,3 +25,16 @@
     ffi = support.new_ffi()
     p = ffi.new("int[]", [10, 20, 30])
     assert p[2] == 30
+
+def test_cdata_as_number():
+    ffi = support.new_ffi()
+    p = ffi.new("int[]", [10, 20, 30])
+    assert (p + 2)[0] == 30
+    assert (p + 2) - p == 2
+    assert (p + 2) - (p + 1) == 1
+    assert p
+    assert not ffi.NULL
+    assert int(ffi.cast("short", 40000)) == 40000 - 65536
+    assert long(ffi.cast("short", 40000)) == 40000 - 65536
+    x = float(ffi.cast("float", 1.222))
+    assert 1E-15 < abs(x - 1.222) < 1E-8    # must get rounding errors


More information about the pypy-commit mailing list