Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r207:4783e7b29a9b
Date: 2014-12-19 16:29 +0100
http://bitbucket.org/cffi/creflect/changeset/4783e7b29a9b/

Log:    Change ffi.new/ffi.cast on primitive types. Now ffi.cast()
        generally returns the Python object; to get a cdata object, use
        ffi.new().

diff --git a/zeffir/cdata.c b/zeffir/cdata.c
--- a/zeffir/cdata.c
+++ b/zeffir/cdata.c
@@ -1762,10 +1762,9 @@
     return res;
 }
 
-static CDataObject *cast_to_integer_or_char(CTypeDescrObject *ct, PyObject *ob)
+static PyObject *cast_to_integer_or_char(CTypeDescrObject *ct, PyObject *ob)
 {
     unsigned PY_LONG_LONG value;
-    CDataObject *cd;
 
     if (CData_Check(ob) &&
             ((CDataObject *)ob)->c_type->ct_flags & (CT_POINTER | CT_ARRAY)) {
@@ -1791,12 +1790,42 @@
         if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
             return NULL;
     }
-    if (ct->ct_flags & CT_IS_BOOL)
-        value = !!value;
-    cd = _new_casted_primitive(ct);
-    if (cd != NULL)
-        write_raw_integer_data(cd->c_data, value, ct->ct_size);
-    return cd;
+    if (ct->ct_flags & CT_PRIMITIVE_SIGNED) {
+        switch (ct->ct_size) {
+        case sizeof(char):
+            if (ct->ct_flags & CT_IS_BOOL)
+                return PyBool_FromLong(value != 0);
+            return PyInt_FromLong((signed char)value);
+        case sizeof(short):
+            return PyInt_FromLong((short)value);
+        case sizeof(int):
+            return PyInt_FromLong((int)value);
+        case sizeof(long):
+            return PyInt_FromLong((long)value);
+        default:
+            return PyLong_FromLongLong((PY_LONG_LONG)value);
+        }
+    }
+    else if (ct->ct_flags & CT_PRIMITIVE_CHAR) {
+        char c = (char)value;
+        return PyString_FromStringAndSize(&c, 1);
+    }
+    else {
+        switch (ct->ct_size) {
+        case sizeof(char):
+            return PyInt_FromLong((unsigned char)value);
+        case sizeof(short):
+            return PyInt_FromLong((unsigned short)value);
+        case sizeof(int):
+            if (sizeof(int) < sizeof(long))
+                return PyInt_FromLong((unsigned int)value);
+            /* else, fall-through */
+        case sizeof(long):
+            return PyLong_FromUnsignedLong((unsigned long)value);
+        default:
+            return PyLong_FromUnsignedLongLong(value);
+        }
+    }
 }
 
 static PyObject *do_cast(CTypeDescrObject *ct, PyObject *ob)
@@ -1826,7 +1855,7 @@
                              CT_PRIMITIVE_UNSIGNED |
                              CT_PRIMITIVE_CHAR)) {
         /* cast to an integer type or a char */
-        return (PyObject *)cast_to_integer_or_char(ct, ob);
+        return cast_to_integer_or_char(ct, ob);
     }
     else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) {
         /* cast to a float */
@@ -1847,40 +1876,38 @@
             Py_INCREF(io);
         }
 
+        if ((ct->ct_flags & CT_IS_LONGDOUBLE) &&
+            (CData_Check(io) &&
+             (((CDataObject *)io)->c_type->ct_flags & CT_IS_LONGDOUBLE))) {
+            return io;   /* no more convertion needed; don't loose precision */
+        }
+
         if (PyBytes_Check(io)) {
             if (PyBytes_GET_SIZE(io) != 1) {
                 Py_DECREF(io);
                 goto cannot_cast;
             }
             value = (unsigned char)PyBytes_AS_STRING(io)[0];
+            Py_DECREF(io);
         }
-        else if ((ct->ct_flags & CT_IS_LONGDOUBLE) &&
-                 CData_Check(io) &&
-                 (((CDataObject *)io)->c_type->ct_flags & CT_IS_LONGDOUBLE)) {
-            long double lvalue;
-            char *data = ((CDataObject *)io)->c_data;
-            /*READ(data, sizeof(long double)*/
-            lvalue = read_raw_longdouble_data(data);
+        else {
+            value = PyFloat_AsDouble(io);
+            Py_DECREF(io);
+            if (value == -1.0 && PyErr_Occurred())
+                return NULL;
+        }
+
+        if (ct->ct_flags & CT_IS_LONGDOUBLE) {
             cd = _new_casted_primitive(ct);
             if (cd != NULL)
-                write_raw_longdouble_data(cd->c_data, lvalue);
+                write_raw_longdouble_data(cd->c_data, value);
             return (PyObject *)cd;
         }
         else {
-            value = PyFloat_AsDouble(io);
+            if (ct->ct_size < sizeof(double))
+                value = (float)value;   /* explicitly loose precision */
+            return PyFloat_FromDouble(value);
         }
-        Py_DECREF(io);
-        if (value == -1.0 && PyErr_Occurred())
-            return NULL;
-
-        cd = _new_casted_primitive(ct);
-        if (cd != NULL) {
-            if (!(ct->ct_flags & CT_IS_LONGDOUBLE))
-                write_raw_float_data(cd->c_data, value, ct->ct_size);
-            else
-                write_raw_longdouble_data(cd->c_data, (long double)value);
-        }
-        return (PyObject *)cd;
     }
     else {
         PyErr_Format(PyExc_TypeError, "cannot cast to ctype '%s'",
diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c
--- a/zeffir/ffi_obj.c
+++ b/zeffir/ffi_obj.c
@@ -240,10 +240,14 @@
             }
         }
     }
+    else if (ct->ct_flags & CT_PRIMITIVE_ANY) {
+        cd = _new_casted_primitive(ct);
+        datasize = ct->ct_size;
+        goto initialize_casted_primitive;
+    }
     else {
         PyErr_Format(PyExc_TypeError,
-                     "expected a pointer, struct, union, or array ctype, "
-                     "got '%s'", ct->ct_name);
+                     "cannot create cdata '%s' objects", ct->ct_name);
         return NULL;
     }
 
@@ -255,6 +259,7 @@
     if (explicitlength >= 0)
         ((CDataObject_own_length*)cd)->length = explicitlength;
 
+ initialize_casted_primitive:
     memset(cd->c_data, 0, datasize);
     if (init != Py_None) {
         if (convert_from_object(cd->c_data,
diff --git a/zeffir/test/test_basic.py b/zeffir/test/test_basic.py
--- a/zeffir/test/test_basic.py
+++ b/zeffir/test/test_basic.py
@@ -55,6 +55,20 @@
     q = ffi.cast("int *", p)
     assert q[1] in [0x61626364, 0x64636261]
 
+    q = ffi.cast("int", 42)
+    assert type(q) is int and q == 42
+    q = ffi.cast("float", 42)
+    assert type(q) is float and q == 42.0
+    q = ffi.cast("long double", 42)
+    assert repr(q).startswith("<cdata 'long double' ")
+
+    q = ffi.new("int", 42)
+    assert repr(q) == "<cdata 'int' 42>"
+    q = ffi.new("float", 42)
+    assert repr(q) == "<cdata 'float' 42.0>"
+    q = ffi.new("long double", 42)
+    assert repr(q).startswith("<cdata 'long double' ")
+
 def test_getctype():
     ffi = support.new_ffi()
     assert ffi.getctype("int") == "int"
diff --git a/zeffir/test/test_c.py b/zeffir/test/test_c.py
--- a/zeffir/test/test_c.py
+++ b/zeffir/test/test_c.py
@@ -60,16 +60,17 @@
     ffi = support.new_ffi()
     t = ffi.typeof("signed char")
     x = ffi.cast(t, -65 + 17*256)
-    assert repr(x) == "<cdata 'signed char' -65>"
+    assert type(x) is int and x == -65
+    x = ffi.cast(t, -66 + (1<<199)*256)
+    assert type(x) is int and x == -66
+    x = ffi.new(t, -66)
+    assert repr(x) == "<cdata 'signed char' -66>"
     assert repr(type(x)) == "<%s 'zeffir.CData'>" % type_or_class
-    assert int(x) == -65
-    x = ffi.cast(t, -66 + (1<<199)*256)
-    assert repr(x) == "<cdata 'signed char' -66>"
     assert int(x) == -66
-    assert (x == ffi.cast(t, -66)) is False
-    assert (x != ffi.cast(t, -66)) is True
-    assert (x == ffi.cast("short", -66)) is False
-    assert (x != ffi.cast("short", -66)) is True
+    assert (x == ffi.new(t, -66)) is False
+    assert (x != ffi.new(t, -66)) is True
+    assert (x == ffi.new("short", -66)) is False
+    assert (x != ffi.new("short", -66)) is True
 
 def test_sizeof_type():
     ffi = support.new_ffi()
@@ -84,75 +85,120 @@
         size = ffi.sizeof(p)
         min = -(1 << (8*size-1))
         max = (1 << (8*size-1)) - 1
-        assert int(ffi.cast(p, min)) == min
-        assert int(ffi.cast(p, max)) == max
-        assert int(ffi.cast(p, min - 1)) == max
-        assert int(ffi.cast(p, max + 1)) == min
+        assert type(ffi.cast(p, min)) in (int, long)
+        assert ffi.cast(p, min) == min
+        assert ffi.cast(p, max) == max
+        assert ffi.cast(p, min - 1) == max
+        assert ffi.cast(p, max + 1) == min
         py.test.raises(TypeError, ffi.cast, p, None)
-        assert long(ffi.cast(p, min - 1)) == max
-        assert int(ffi.cast(p, b'\x08')) == 8
+        assert ffi.cast(p, b'\x08') == 8
     for name in ['char', 'short', 'int', 'long', 'long long']:
         p = ffi.typeof('unsigned ' + name)
         size = ffi.sizeof(p)
         max = (1 << (8*size)) - 1
-        assert int(ffi.cast(p, 0)) == 0
-        assert int(ffi.cast(p, max)) == max
-        assert int(ffi.cast(p, -1)) == max
-        assert int(ffi.cast(p, max + 1)) == 0
-        assert long(ffi.cast(p, -1)) == max
-        assert int(ffi.cast(p, b'\xFE')) == 254
+        assert type(ffi.cast(p, min)) in (int, long)
+        assert ffi.cast(p, 0) == 0
+        assert ffi.cast(p, max) == max
+        assert ffi.cast(p, -1) == max
+        assert ffi.cast(p, max + 1) == 0
+        assert ffi.cast(p, b'\xFE') == 254
+
+def test_integer_types_new():
+    ffi = support.new_ffi()
+    for name in ['signed char', 'short', 'int', 'long', 'long long']:
+        p = ffi.typeof(name)
+        size = ffi.sizeof(p)
+        min = -(1 << (8*size-1))
+        max = (1 << (8*size-1)) - 1
+        assert bool(ffi.new(p, 0))
+        assert int(ffi.new(p, min)) == min
+        assert int(ffi.new(p, max)) == max
+        py.test.raises(OverflowError, ffi.new, p, min - 1)
+        py.test.raises(OverflowError, ffi.new, p, max + 1)
+        py.test.raises(TypeError, ffi.new, p, b'\x08')
+    for name in ['char', 'short', 'int', 'long', 'long long']:
+        p = ffi.typeof('unsigned ' + name)
+        size = ffi.sizeof(p)
+        max = (1 << (8*size)) - 1
+        assert bool(ffi.new(p, 0))
+        assert int(ffi.new(p, 0)) == 0
+        assert int(ffi.new(p, max)) == max
+        py.test.raises(OverflowError, ffi.new, p, -1)
+        py.test.raises(OverflowError, ffi.new, p, max + 1)
+        py.test.raises(TypeError, ffi.new, p, b'\xFE')
 
 def test_no_float_on_int_types():
     ffi = support.new_ffi()
-    py.test.raises(TypeError, float, ffi.cast('long', 42))
-    py.test.raises(TypeError, complex, ffi.cast('long', 42))
+    py.test.raises(TypeError, float, ffi.new('long', 42))
+    py.test.raises(TypeError, complex, ffi.new('long', 42))
 
 def test_float_types():
     ffi = support.new_ffi()
     INF = 1E200 * 1E200
     for name in ["float", "double"]:
         p = ffi.typeof(name)
-        assert bool(ffi.cast(p, 0))
-        assert bool(ffi.cast(p, INF))
-        assert bool(ffi.cast(p, -INF))
-        assert int(ffi.cast(p, -150)) == -150
-        assert int(ffi.cast(p, 61.91)) == 61
-        assert long(ffi.cast(p, 61.91)) == 61
-        assert type(int(ffi.cast(p, 61.91))) is int
-        assert type(int(ffi.cast(p, 1E22))) is long
-        assert type(long(ffi.cast(p, 61.91))) is long
-        assert type(long(ffi.cast(p, 1E22))) is long
-        py.test.raises(OverflowError, int, ffi.cast(p, INF))
-        py.test.raises(OverflowError, int, ffi.cast(p, -INF))
-        assert float(ffi.cast(p, 1.25)) == 1.25
-        assert float(ffi.cast(p, INF)) == INF
-        assert float(ffi.cast(p, -INF)) == -INF
+        assert type(ffi.cast(p, 0)) is float
+        assert ffi.cast(p, 0) == 0.0
+        assert ffi.cast(p, INF) == INF
+        assert ffi.cast(p, -INF) == -INF
+        assert ffi.cast(p, -150) == -150
         if name == "float":
-            assert float(ffi.cast(p, 1.1)) != 1.1     # rounding error
-            assert float(ffi.cast(p, 1E200)) == INF   # limited range
+            assert ffi.cast(p, 1.1) != 1.1     # rounding error
+            assert ffi.cast(p, 1E200) == INF   # limited range
+        else:
+            assert ffi.cast(p, 61.91) == 61.91
 
-        assert ffi.cast(p, -1.1) != ffi.cast(p, -1.1)
-        assert repr(float(ffi.cast(p, -0.0))) == '-0.0'
-        assert float(ffi.cast(p, b'\x09')) == 9.0
-        assert float(ffi.cast(p, True)) == 1.0
+        assert repr(ffi.cast(p, -0.0)) == '-0.0'
+        assert ffi.cast(p, b'\x09') == 9.0
+        assert ffi.cast(p, True) == 1.0
         py.test.raises(TypeError, ffi.cast, p, None)
 
+def test_float_types_new():
+    ffi = support.new_ffi()
+    INF = 1E200 * 1E200
+    for name in ["float", "double"]:
+        p = ffi.typeof(name)
+        assert bool(ffi.new(p, 0))
+        assert bool(ffi.new(p, INF))
+        assert bool(ffi.new(p, -INF))
+        assert int(ffi.new(p, -150)) == -150
+        assert int(ffi.new(p, 61.91)) == 61
+        assert long(ffi.new(p, 61.91)) == 61
+        assert type(int(ffi.new(p, 61.91))) is int
+        assert type(int(ffi.new(p, 1E22))) is long
+        assert type(long(ffi.new(p, 61.91))) is long
+        assert type(long(ffi.new(p, 1E22))) is long
+        py.test.raises(OverflowError, int, ffi.new(p, INF))
+        py.test.raises(OverflowError, int, ffi.new(p, -INF))
+        assert float(ffi.new(p, 1.25)) == 1.25
+        assert float(ffi.new(p, INF)) == INF
+        assert float(ffi.new(p, -INF)) == -INF
+        if name == "float":
+            assert float(ffi.new(p, 1.1)) != 1.1     # rounding error
+            assert float(ffi.new(p, 1E200)) == INF   # limited range
+
+        assert ffi.new(p, -1.1) != ffi.new(p, -1.1)
+        assert repr(float(ffi.new(p, -0.0))) == '-0.0'
+        py.test.raises(TypeError, ffi.new, p, b'\x09')
+        assert float(ffi.new(p, True)) == 1.0
+
 def test_complex_types():
     py.test.skip("later")
 
 def test_character_type():
     ffi = support.new_ffi()
     p = ffi.typeof("char")
-    assert bool(ffi.cast(p, '\x00'))
-    assert ffi.cast(p, '\x00') != ffi.cast(p, -17*256)
-    assert int(ffi.cast(p, 'A')) == 65
-    assert long(ffi.cast(p, 'A')) == 65
-    assert type(int(ffi.cast(p, 'A'))) is int
-    assert type(long(ffi.cast(p, 'A'))) is long
-    assert str(ffi.cast(p, 'A')) == repr(ffi.cast(p, 'A'))
-    assert repr(ffi.cast(p, 'A')) == "<cdata 'char' %s'A'>" % 
mandatory_b_prefix
-    assert repr(ffi.cast(p, 255)) == r"<cdata 'char' %s'\xff'>" % 
mandatory_b_prefix
-    assert repr(ffi.cast(p, 0)) == r"<cdata 'char' %s'\x00'>" % 
mandatory_b_prefix
+    assert bool(ffi.new(p, '\x00'))
+    assert type(ffi.cast(p, 50505)) is bytes
+    assert ffi.new(p, '\x00') != ffi.new(p, '\x00')
+    assert ffi.cast(p, 65 + 1233*256) == 'A'
+    assert int(ffi.new(p, 'A')) == 65
+    assert long(ffi.new(p, 'A')) == 65
+    assert type(int(ffi.new(p, 'A'))) is int
+    assert type(long(ffi.new(p, 'A'))) is long
+    py.test.raises(TypeError, ffi.new, p, 65)
+    assert str(ffi.new(p, 'A')) == repr(ffi.new(p, 'A'))
+    assert repr(ffi.new(p, '\xff')) == r"<cdata 'char' %s'\xff'>" % 
mandatory_b_prefix
 
 def test_pointer_type():
     ffi = support.new_ffi()
@@ -178,9 +224,6 @@
 
 def test_pointer_to_int():
     ffi = support.new_ffi()
-    py.test.raises(TypeError, ffi.new, "int")
-    py.test.raises(TypeError, ffi.new, "int", None)
-    py.test.raises(TypeError, ffi.new, "int", 42)
     p = ffi.new("int*")
     assert repr(p) == "<cdata 'int *' owning %d bytes>" % size_of_int()
     p = ffi.new("int*", None)
@@ -215,7 +258,6 @@
 
 def test_reading_pointer_to_float():
     ffi = support.new_ffi()
-    py.test.raises(TypeError, ffi.new, "float")
     p = ffi.new("float *", None)
     assert p[0] == 0.0 and type(p[0]) is float
     p = ffi.new("float *", 1.25)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to