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