Author: Armin Rigo <[email protected]>
Branch:
Changeset: r1039:86564854139f
Date: 2012-11-12 18:18 +0100
http://bitbucket.org/cffi/cffi/changeset/86564854139f/
Log: Fix issue #32: turn types like "size_t" into primitive types from
the point of view of CFFI.
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -2954,51 +2954,6 @@
/************************************************************/
-static PyObject *b_nonstandard_integer_types(PyObject *self, PyObject *noarg)
-{
-#define UNSIGNED 0x1000
- static const struct descr_s { const char *name; int size; } types[] = {
- { "int8_t", 1 },
- { "uint8_t", 1 | UNSIGNED },
- { "int16_t", 2 },
- { "uint16_t", 2 | UNSIGNED },
- { "int32_t", 4 },
- { "uint32_t", 4 | UNSIGNED },
- { "int64_t", 8 },
- { "uint64_t", 8 | UNSIGNED },
-
- { "intptr_t", sizeof(intptr_t) },
- { "uintptr_t", sizeof(uintptr_t) | UNSIGNED },
- { "ptrdiff_t", sizeof(ptrdiff_t) },
- { "size_t", sizeof(size_t) | UNSIGNED },
- { "ssize_t", sizeof(ssize_t) },
- { NULL }
- };
-#undef UNSIGNED
- const struct descr_s *ptypes;
- PyObject *d;
-
- d = PyDict_New();
- if (d == NULL)
- return NULL;
-
- for (ptypes=types; ptypes->name; ptypes++) {
- int err;
- PyObject *obj = PyInt_FromLong(ptypes->size);
- if (obj == NULL)
- goto error;
- err = PyDict_SetItemString(d, ptypes->name, obj);
- Py_DECREF(obj);
- if (err != 0)
- goto error;
- }
- return d;
-
- error:
- Py_DECREF(d);
- return NULL;
-}
-
static PyObject *b_new_primitive_type(PyObject *self, PyObject *args)
{
#define ENUM_PRIMITIVE_TYPES \
@@ -3017,7 +2972,21 @@
EPTYPE(d, double, CT_PRIMITIVE_FLOAT ) \
EPTYPE(ld, long double, CT_PRIMITIVE_FLOAT | CT_IS_LONGDOUBLE ) \
ENUM_PRIMITIVE_TYPES_WCHAR \
- EPTYPE(b, _Bool, CT_PRIMITIVE_UNSIGNED | CT_IS_BOOL )
+ EPTYPE(b, _Bool, CT_PRIMITIVE_UNSIGNED | CT_IS_BOOL ) \
+ /* the following types are not primitive in the C sense */ \
+ EPTYPE(i8, int8_t, CT_PRIMITIVE_SIGNED) \
+ EPTYPE(u8, uint8_t, CT_PRIMITIVE_UNSIGNED) \
+ EPTYPE(i16, int16_t, CT_PRIMITIVE_SIGNED) \
+ EPTYPE(u16, uint16_t, CT_PRIMITIVE_UNSIGNED) \
+ EPTYPE(i32, int32_t, CT_PRIMITIVE_SIGNED) \
+ EPTYPE(u32, uint32_t, CT_PRIMITIVE_UNSIGNED) \
+ EPTYPE(i64, int64_t, CT_PRIMITIVE_SIGNED) \
+ EPTYPE(u64, uint64_t, CT_PRIMITIVE_UNSIGNED) \
+ EPTYPE(ip, intptr_t, CT_PRIMITIVE_SIGNED) \
+ EPTYPE(up, uintptr_t, CT_PRIMITIVE_UNSIGNED) \
+ EPTYPE(pd, ptrdiff_t, CT_PRIMITIVE_SIGNED) \
+ EPTYPE(sz, size_t, CT_PRIMITIVE_UNSIGNED) \
+ EPTYPE(ssz, ssize_t, CT_PRIMITIVE_SIGNED)
#ifdef HAVE_WCHAR_H
# define ENUM_PRIMITIVE_TYPES_WCHAR \
@@ -4732,7 +4701,6 @@
}
static PyMethodDef FFIBackendMethods[] = {
- {"nonstandard_integer_types", b_nonstandard_integer_types, METH_NOARGS},
{"load_library", b_load_library, METH_VARARGS},
{"new_primitive_type", b_new_primitive_type, METH_VARARGS},
{"new_pointer_type", b_new_pointer_type, METH_VARARGS},
@@ -4776,45 +4744,34 @@
return NULL;
}
-#define _cffi_to_c_PRIMITIVE(TARGETNAME, TARGET) \
-static TARGET _cffi_to_c_##TARGETNAME(PyObject *obj) { \
- PY_LONG_LONG tmp = _my_PyLong_AsLongLong(obj); \
- if (tmp != (TARGET)tmp && !PyErr_Occurred()) \
- return (TARGET)_convert_overflow(obj, #TARGET); \
- return (TARGET)tmp; \
+#define _cffi_to_c_SIGNED_FN(RETURNTYPE, SIZE) \
+static RETURNTYPE _cffi_to_c_i##SIZE(PyObject *obj) { \
+ PY_LONG_LONG tmp = _my_PyLong_AsLongLong(obj); \
+ if ((tmp > (PY_LONG_LONG)((1ULL<<(SIZE-1)) - 1)) || \
+ (tmp < (PY_LONG_LONG)(-(1ULL<<(SIZE-1))))) \
+ if (!PyErr_Occurred()) \
+ return (RETURNTYPE)_convert_overflow(obj, #SIZE "-bit int"); \
+ return (RETURNTYPE)tmp; \
}
-_cffi_to_c_PRIMITIVE(signed_char, signed char)
-_cffi_to_c_PRIMITIVE(unsigned_char, unsigned char)
-_cffi_to_c_PRIMITIVE(short, short)
-_cffi_to_c_PRIMITIVE(unsigned_short, unsigned short)
-#if SIZEOF_INT == SIZEOF_LONG
-#define _cffi_to_c_int _cffi_to_c_long
-#define _cffi_to_c_unsigned_int _cffi_to_c_unsigned_long
-#else
-_cffi_to_c_PRIMITIVE(int, int)
-_cffi_to_c_PRIMITIVE(unsigned_int, unsigned int)
-#endif
-_cffi_to_c_PRIMITIVE(long, long)
-
-#if SIZEOF_LONG < SIZEOF_LONG_LONG
-static unsigned long _cffi_to_c_unsigned_long(PyObject *obj)
-{
- unsigned PY_LONG_LONG value = _my_PyLong_AsUnsignedLongLong(obj, 1);
- if (value != (unsigned long)value)
- return (unsigned long)_convert_overflow(obj, "unsigned long");
- return (unsigned long)value;
+#define _cffi_to_c_UNSIGNED_FN(RETURNTYPE, SIZE) \
+static RETURNTYPE _cffi_to_c_u##SIZE(PyObject *obj) { \
+ unsigned PY_LONG_LONG tmp = _my_PyLong_AsUnsignedLongLong(obj, 1); \
+ if (tmp > ~(((unsigned PY_LONG_LONG)-2) << (SIZE-1))) \
+ if (!PyErr_Occurred()) \
+ return (RETURNTYPE)_convert_overflow(obj, \
+ #SIZE "-bit unsigned int"); \
+ return (RETURNTYPE)tmp; \
}
-#else
-# define _cffi_to_c_unsigned_long _cffi_to_c_unsigned_long_long
-#endif
-
-#define _cffi_to_c_long_long _my_PyLong_AsLongLong
-
-static unsigned PY_LONG_LONG _cffi_to_c_unsigned_long_long(PyObject *obj)
-{
- return _my_PyLong_AsUnsignedLongLong(obj, 1);
-}
+
+_cffi_to_c_SIGNED_FN(int, 8)
+_cffi_to_c_SIGNED_FN(int, 16)
+_cffi_to_c_SIGNED_FN(int, 32)
+_cffi_to_c_SIGNED_FN(PY_LONG_LONG, 64)
+_cffi_to_c_UNSIGNED_FN(int, 8)
+_cffi_to_c_UNSIGNED_FN(int, 16)
+_cffi_to_c_UNSIGNED_FN(unsigned int, 32)
+_cffi_to_c_UNSIGNED_FN(unsigned PY_LONG_LONG, 64)
static char _cffi_to_c_char(PyObject *obj)
{
@@ -4900,14 +4857,14 @@
static void *cffi_exports[] = {
_cffi_to_c_char_p,
- _cffi_to_c_signed_char,
- _cffi_to_c_unsigned_char,
- _cffi_to_c_short,
- _cffi_to_c_unsigned_short,
- _cffi_to_c_int,
- _cffi_to_c_unsigned_int,
- _cffi_to_c_long,
- _cffi_to_c_unsigned_long,
+ _cffi_to_c_i8,
+ _cffi_to_c_u8,
+ _cffi_to_c_i16,
+ _cffi_to_c_u16,
+ _cffi_to_c_i32,
+ _cffi_to_c_u32,
+ _cffi_to_c_i64,
+ _cffi_to_c_u64,
_cffi_to_c_char,
_cffi_from_c_pointer,
_cffi_to_c_pointer,
@@ -4927,8 +4884,6 @@
#endif
_cffi_to_c_long_double,
_cffi_to_c__Bool,
- _cffi_to_c_long_long,
- _cffi_to_c_unsigned_long_long,
};
/************************************************************/
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -70,13 +70,6 @@
RTLD_NOLOAD
RTLD_DEEPBIND
-def test_nonstandard_integer_types():
- d = nonstandard_integer_types()
- assert type(d) is dict
- assert 'char' not in d
- assert d['size_t'] in (0x1004, 0x1008)
- assert d['size_t'] == d['ssize_t'] + 0x1000
-
def test_new_primitive_type():
py.test.raises(KeyError, new_primitive_type, "foo")
p = new_primitive_type("signed char")
@@ -2503,3 +2496,9 @@
#
res = GetLastError()
assert res == 42
+
+def test_nonstandard_integer_types():
+ for typename in ['int8_t', 'uint8_t', 'int16_t', 'uint16_t', 'int32_t',
+ 'uint32_t', 'int64_t', 'uint64_t', 'intptr_t',
+ 'uintptr_t', 'ptrdiff_t', 'size_t', 'ssize_t']:
+ new_primitive_type(typename) # works
diff --git a/cffi/api.py b/cffi/api.py
--- a/cffi/api.py
+++ b/cffi/api.py
@@ -59,18 +59,7 @@
if name.startswith('RTLD_'):
setattr(self, name, getattr(backend, name))
#
- lines = ['typedef struct _IO_FILE FILE;']
- by_size = {}
- for cname in ['long long', 'long', 'int', 'short', 'char']:
- by_size[self.sizeof(cname)] = cname
- for name, size in self._backend.nonstandard_integer_types().items():
- if size & 0x1000: # unsigned
- equiv = 'unsigned %s'
- size &= ~0x1000
- else:
- equiv = 'signed %s'
- lines.append('typedef %s %s;' % (equiv % by_size[size], name))
- self.cdef('\n'.join(lines))
+ self.cdef('typedef struct _IO_FILE FILE;')
del self._cdefsources[:]
#
self.NULL = self.cast("void *", 0)
diff --git a/cffi/backend_ctypes.py b/cffi/backend_ctypes.py
--- a/cffi/backend_ctypes.py
+++ b/cffi/backend_ctypes.py
@@ -285,7 +285,26 @@
'float': ctypes.c_float,
'double': ctypes.c_double,
'_Bool': ctypes.c_bool,
- }
+ }
+
+ for _name in ['unsigned long long', 'unsigned long',
+ 'unsigned int', 'unsigned short', 'unsigned char']:
+ _size = ctypes.sizeof(PRIMITIVE_TYPES[_name])
+ PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name]
+ if _size == ctypes.sizeof(ctypes.c_void_p):
+ PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name]
+ if _size == ctypes.sizeof(ctypes.c_size_t):
+ PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name]
+
+ for _name in ['long long', 'long', 'int', 'short', 'signed char']:
+ _size = ctypes.sizeof(PRIMITIVE_TYPES[_name])
+ PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name]
+ if _size == ctypes.sizeof(ctypes.c_void_p):
+ PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name]
+ PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name]
+ if _size == ctypes.sizeof(ctypes.c_size_t):
+ PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name]
+
def __init__(self):
self.RTLD_LAZY = 0 # not supported anyway by ctypes
@@ -299,22 +318,6 @@
def _get_types(self):
return CTypesData, CTypesType
- def nonstandard_integer_types(self):
- UNSIGNED = 0x1000
- result = {}
- for name in ['long long', 'long', 'int', 'short', 'char']:
- size = ctypes.sizeof(self.PRIMITIVE_TYPES[name])
- result['int%d_t' % (8*size)] = size
- result['uint%d_t' % (8*size)] = size | UNSIGNED
- if size == ctypes.sizeof(ctypes.c_void_p):
- result['intptr_t'] = size
- result['uintptr_t'] = size | UNSIGNED
- result['ptrdiff_t'] = result['intptr_t']
- if size == ctypes.sizeof(ctypes.c_size_t):
- result['size_t'] = size | UNSIGNED
- result['ssize_t'] = size
- return result
-
def load_library(self, path, flags=0):
cdll = ctypes.CDLL(path, flags)
return CTypesLibrary(self, cdll)
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -59,6 +59,10 @@
return csource.replace('...', ' __dotdotdot__ '), macros
class Parser(object):
+ TYPEDEFS = sorted(
+ [_name for _name in model.PrimitiveType.ALL_PRIMITIVE_TYPES
+ if _name.endswith('_t')])
+
def __init__(self):
self._declarations = {}
self._anonymous_counter = 0
@@ -70,10 +74,11 @@
# internals of CParser... the following registers the
# typedefs, because their presence or absence influences the
# parsing itself (but what they are typedef'ed to plays no role)
- csourcelines = ['typedef int wchar_t;']
+ typenames = self.TYPEDEFS[:]
for name in sorted(self._declarations):
if name.startswith('typedef '):
- csourcelines.append('typedef int %s;' % (name[8:],))
+ typenames.append(name[8:])
+ csourcelines = ['typedef int %s;' % typename for typename in typenames]
csourcelines.append('typedef int __dotdotdot__;')
csource, macros = _preprocess(csource)
csourcelines.append(csource)
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -55,22 +55,56 @@
class PrimitiveType(BaseType):
_attrs_ = ('name',)
+ ALL_PRIMITIVE_TYPES = {
+ 'char': 'c',
+ 'short': 'i',
+ 'int': 'i',
+ 'long': 'i',
+ 'long long': 'i',
+ 'signed char': 'i',
+ 'unsigned char': 'u',
+ 'unsigned short': 'u',
+ 'unsigned int': 'u',
+ 'unsigned long': 'u',
+ 'unsigned long long': 'u',
+ 'float': 'f',
+ 'double': 'f',
+ 'long double': 'f',
+ 'wchar_t': 'c',
+ '_Bool': 'u',
+ # the following types are not primitive in the C sense
+ 'int8_t': 'i',
+ 'uint8_t': 'u',
+ 'int16_t': 'i',
+ 'uint16_t': 'u',
+ 'int32_t': 'i',
+ 'uint32_t': 'u',
+ 'int64_t': 'i',
+ 'uint64_t': 'u',
+ 'intptr_t': 'i',
+ 'uintptr_t': 'u',
+ 'ptrdiff_t': 'i',
+ 'size_t': 'u',
+ 'ssize_t': 'i',
+ }
+
def __init__(self, name):
+ assert name in self.ALL_PRIMITIVE_TYPES
self.name = name
def _get_c_name(self, replace_with):
return self.name + replace_with
def is_char_type(self):
- return self.name in ('char', 'wchar_t')
+ return self.ALL_PRIMITIVE_TYPES[self.name] == 'c'
def is_signed_type(self):
- return self.is_integer_type() and not self.is_unsigned_type()
+ return self.ALL_PRIMITIVE_TYPES[self.name] == 'i'
def is_unsigned_type(self):
- return self.name.startswith('unsigned ')
+ return self.ALL_PRIMITIVE_TYPES[self.name] == 'u'
def is_integer_type(self):
- return not self.is_float_type() and not self.is_char_type()
+ return self.ALL_PRIMITIVE_TYPES[self.name] in 'iu'
def is_float_type(self):
- return self.name in ('double', 'float')
+ return self.ALL_PRIMITIVE_TYPES[self.name] == 'f'
def build_backend_type(self, ffi, finishlist):
return global_cache(self, ffi, 'new_primitive_type', self.name)
diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py
--- a/cffi/vengine_cpy.py
+++ b/cffi/vengine_cpy.py
@@ -179,7 +179,14 @@
def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode):
extraarg = ''
if isinstance(tp, model.PrimitiveType):
- converter = '_cffi_to_c_%s' % (tp.name.replace(' ', '_'),)
+ if tp.is_integer_type() and tp.name != '_Bool':
+ if tp.is_signed_type():
+ converter = '_cffi_to_c_SIGNED'
+ else:
+ converter = '_cffi_to_c_UNSIGNED'
+ extraarg = ', %s' % tp.name
+ else:
+ converter = '_cffi_to_c_%s' % (tp.name.replace(' ', '_'),)
errvalue = '-1'
#
elif isinstance(tp, model.PointerType):
@@ -213,7 +220,12 @@
def _convert_expr_from_c(self, tp, var):
if isinstance(tp, model.PrimitiveType):
- if tp.name != 'long double':
+ if tp.is_integer_type():
+ if tp.is_signed_type():
+ return '_cffi_from_c_SIGNED(%s, %s)' % (var, tp.name)
+ else:
+ return '_cffi_from_c_UNSIGNED(%s, %s)' % (var, tp.name)
+ elif tp.name != 'long double':
return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var)
else:
return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % (
@@ -676,49 +688,53 @@
#define _cffi_from_c_double PyFloat_FromDouble
#define _cffi_from_c_float PyFloat_FromDouble
-#define _cffi_from_c_signed_char PyInt_FromLong
-#define _cffi_from_c_short PyInt_FromLong
-#define _cffi_from_c_int PyInt_FromLong
#define _cffi_from_c_long PyInt_FromLong
-#define _cffi_from_c_unsigned_char PyInt_FromLong
-#define _cffi_from_c_unsigned_short PyInt_FromLong
-#define _cffi_from_c_unsigned_long PyLong_FromUnsignedLong
-#define _cffi_from_c_unsigned_long_long PyLong_FromUnsignedLongLong
-#define _cffi_from_c__Bool PyInt_FromLong
-
-#if SIZEOF_INT < SIZEOF_LONG
-# define _cffi_from_c_unsigned_int PyInt_FromLong
-#else
-# define _cffi_from_c_unsigned_int PyLong_FromUnsignedLong
-#endif
-
-#if SIZEOF_LONG < SIZEOF_LONG_LONG
-# define _cffi_from_c_long_long PyLong_FromLongLong
-#else
-# define _cffi_from_c_long_long PyInt_FromLong
-#endif
+#define _cffi_from_c_ulong PyLong_FromUnsignedLong
+#define _cffi_from_c_longlong PyLong_FromLongLong
+#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong
#define _cffi_to_c_double PyFloat_AsDouble
#define _cffi_to_c_float PyFloat_AsDouble
+#define _cffi_from_c_SIGNED(x, type) \
+ (sizeof(type) <= sizeof(long) ? PyInt_FromLong(x) : \
+ PyLong_FromLongLong(x))
+#define _cffi_from_c_UNSIGNED(x, type) \
+ (sizeof(type) < sizeof(long) ? PyInt_FromLong(x) : \
+ sizeof(type) == sizeof(long) ? PyLong_FromUnsignedLong(x) : \
+ PyLong_FromUnsignedLongLong(x))
+
+#define _cffi_to_c_SIGNED(o, type) \
+ (sizeof(type) == 1 ? _cffi_to_c_i8(o) : \
+ sizeof(type) == 2 ? _cffi_to_c_i16(o) : \
+ sizeof(type) == 4 ? _cffi_to_c_i32(o) : \
+ sizeof(type) == 8 ? _cffi_to_c_i64(o) : \
+ (Py_FatalError("unsupported size for type " #type), 0))
+#define _cffi_to_c_UNSIGNED(o, type) \
+ (sizeof(type) == 1 ? _cffi_to_c_u8(o) : \
+ sizeof(type) == 2 ? _cffi_to_c_u16(o) : \
+ sizeof(type) == 4 ? _cffi_to_c_u32(o) : \
+ sizeof(type) == 8 ? _cffi_to_c_u64(o) : \
+ (Py_FatalError("unsupported size for type " #type), 0))
+
#define _cffi_to_c_char_p \
((char *(*)(PyObject *))_cffi_exports[0])
-#define _cffi_to_c_signed_char \
- ((signed char(*)(PyObject *))_cffi_exports[1])
-#define _cffi_to_c_unsigned_char \
- ((unsigned char(*)(PyObject *))_cffi_exports[2])
-#define _cffi_to_c_short \
- ((short(*)(PyObject *))_cffi_exports[3])
-#define _cffi_to_c_unsigned_short \
- ((unsigned short(*)(PyObject *))_cffi_exports[4])
-#define _cffi_to_c_int \
+#define _cffi_to_c_i8 \
+ ((int(*)(PyObject *))_cffi_exports[1])
+#define _cffi_to_c_u8 \
+ ((int(*)(PyObject *))_cffi_exports[2])
+#define _cffi_to_c_i16 \
+ ((int(*)(PyObject *))_cffi_exports[3])
+#define _cffi_to_c_u16 \
+ ((int(*)(PyObject *))_cffi_exports[4])
+#define _cffi_to_c_i32 \
((int(*)(PyObject *))_cffi_exports[5])
-#define _cffi_to_c_unsigned_int \
+#define _cffi_to_c_u32 \
((unsigned int(*)(PyObject *))_cffi_exports[6])
-#define _cffi_to_c_long \
- ((long(*)(PyObject *))_cffi_exports[7])
-#define _cffi_to_c_unsigned_long \
- ((unsigned long(*)(PyObject *))_cffi_exports[8])
+#define _cffi_to_c_i64 \
+ ((long long(*)(PyObject *))_cffi_exports[7])
+#define _cffi_to_c_u64 \
+ ((unsigned long long(*)(PyObject *))_cffi_exports[8])
#define _cffi_to_c_char \
((char(*)(PyObject *))_cffi_exports[9])
#define _cffi_from_c_pointer \
@@ -747,11 +763,7 @@
((long double(*)(PyObject *))_cffi_exports[21])
#define _cffi_to_c__Bool \
((_Bool(*)(PyObject *))_cffi_exports[22])
-#define _cffi_to_c_long_long \
- ((long long(*)(PyObject *))_cffi_exports[23])
-#define _cffi_to_c_unsigned_long_long \
- ((unsigned long long(*)(PyObject *))_cffi_exports[24])
-#define _CFFI_NUM_EXPORTS 25
+#define _CFFI_NUM_EXPORTS 23
typedef struct _ctypedescr CTypeDescrObject;
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -549,12 +549,12 @@
``static char *const FOO;``).
Currently, finding automatically the size of an integer type is not
-supported. You need to declare them with ``typedef int myint;`` or
-``typedef long myint;`` or ``typedef long long myint;`` or their
-unsigned equivalent. Depending on the usage, the C compiler might give
-warnings if you misdeclare ``myint`` as the wrong type even if it is
-equivalent on this platform (e.g. using ``long`` instead of ``long
-long`` or vice-versa on 64-bit Linux).
+supported. You need to declare them with ``typedef EXACTTYPE myint;``.
+The ``EXACTTYPE`` might be a built-in C type like ``int`` or ``unsigned
+long long``, or one of the standard integer types like ``size_t`` (see
+the complete list above__).
+
+.. __: `Declaring types and functions`_
Note that ``verify()`` is meant to call C libraries that are *not* using
``#include <Python.h>``. The C functions are called without the GIL,
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -137,60 +137,145 @@
py.test.skip("don't know the very exact precision of 'long
double'")
-all_integer_types = ['short', 'int', 'long', 'long long',
- 'signed char', 'unsigned char',
- 'unsigned short', 'unsigned int',
- 'unsigned long', 'unsigned long long']
-all_signed_integer_types = [_typename for _typename in all_integer_types
- if not _typename.startswith('unsigned ')]
-all_unsigned_integer_types = [_typename for _typename in all_integer_types
- if _typename.startswith('unsigned ')]
-all_float_types = ['float', 'double']
+all_primitive_types = model.PrimitiveType.ALL_PRIMITIVE_TYPES
+all_signed_integer_types = sorted(tp for tp in all_primitive_types
+ if all_primitive_types[tp] == 'i')
+all_unsigned_integer_types = sorted(tp for tp in all_primitive_types
+ if all_primitive_types[tp] == 'u')
+all_float_types = sorted(tp for tp in all_primitive_types
+ if all_primitive_types[tp] == 'f')
def test_primitive_category():
- for typename in all_integer_types + all_float_types + ['char', 'wchar_t']:
+ for typename in all_primitive_types:
tp = model.PrimitiveType(typename)
- assert tp.is_char_type() == (typename in ('char', 'wchar_t'))
- assert tp.is_signed_type() == (typename in all_signed_integer_types)
- assert tp.is_unsigned_type()== (typename in all_unsigned_integer_types)
- assert tp.is_integer_type() == (typename in all_integer_types)
- assert tp.is_float_type() == (typename in all_float_types)
+ C = tp.is_char_type()
+ U = tp.is_unsigned_type()
+ S = tp.is_signed_type()
+ F = tp.is_float_type()
+ I = tp.is_integer_type()
+ assert C == (typename in ('char', 'wchar_t'))
+ assert U == (typename.startswith('unsigned ') or
+ typename == '_Bool' or typename == 'size_t' or
+ typename == 'uintptr_t' or typename.startswith('uint'))
+ assert F == (typename in ('float', 'double', 'long double'))
+ assert S + U + F + C == 1 # one and only one of them is true
+ assert I == (S or U)
def test_all_integer_and_float_types():
- for typename in all_integer_types + all_float_types:
- ffi = FFI()
- ffi.cdef("%s foo(%s);" % (typename, typename))
- lib = ffi.verify("%s foo(%s x) { return x+1; }" % (typename, typename))
- assert lib.foo(42) == 43
+ typenames = []
+ for typename in all_primitive_types:
+ if (all_primitive_types[typename] == 'c' or
+ typename == '_Bool' or typename == 'long double'):
+ pass
+ else:
+ typenames.append(typename)
+ #
+ ffi = FFI()
+ ffi.cdef('\n'.join(["%s foo_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
+ for tp in typenames]))
+ lib = ffi.verify('\n'.join(["%s foo_%s(%s x) { return x+1; }" %
+ (tp, tp.replace(' ', '_'), tp)
+ for tp in typenames]))
+ for typename in typenames:
+ foo = getattr(lib, 'foo_%s' % typename.replace(' ', '_'))
+ assert foo(42) == 43
if sys.version < '3':
- assert lib.foo(long(44)) == 45
- assert lib.foo(ffi.cast(typename, 46)) == 47
- py.test.raises(TypeError, lib.foo, ffi.NULL)
+ assert foo(long(44)) == 45
+ assert foo(ffi.cast(typename, 46)) == 47
+ py.test.raises(TypeError, foo, ffi.NULL)
#
# check for overflow cases
- if typename in all_float_types:
+ if all_primitive_types[typename] == 'f':
continue
for value in [-2**80, -2**40, -2**20, -2**10, -2**5, -1,
2**5, 2**10, 2**20, 2**40, 2**80]:
overflows = int(ffi.cast(typename, value)) != value
if overflows:
- py.test.raises(OverflowError, lib.foo, value)
+ py.test.raises(OverflowError, foo, value)
else:
- assert lib.foo(value) == value + 1
+ assert foo(value) == value + 1
-def test_nonstandard_integer_types():
+def test_var_signed_integer_types():
ffi = FFI()
- lst = ffi._backend.nonstandard_integer_types().items()
- lst = sorted(lst)
- verify_lines = []
- for key, value in lst:
- ffi.cdef("static const int expected_%s;" % key)
- verify_lines.append("static const int expected_%s =" % key)
- verify_lines.append(" sizeof(%s) | (((%s)-1) <= 0 ? 0 : 0x1000);"
- % (key, key))
- lib = ffi.verify('\n'.join(verify_lines))
- for key, value in lst:
- assert getattr(lib, 'expected_%s' % key) == value
+ lst = all_signed_integer_types
+ csource = "\n".join(["%s somevar_%s;" % (tp, tp.replace(' ', '_'))
+ for tp in lst])
+ ffi.cdef(csource)
+ lib = ffi.verify(csource)
+ for tp in lst:
+ varname = 'somevar_%s' % tp.replace(' ', '_')
+ sz = ffi.sizeof(tp)
+ max = (1 << (8*sz-1)) - 1
+ min = -(1 << (8*sz-1))
+ setattr(lib, varname, max)
+ assert getattr(lib, varname) == max
+ setattr(lib, varname, min)
+ assert getattr(lib, varname) == min
+ py.test.raises(OverflowError, setattr, lib, varname, max+1)
+ py.test.raises(OverflowError, setattr, lib, varname, min-1)
+
+def test_var_unsigned_integer_types():
+ ffi = FFI()
+ lst = all_unsigned_integer_types
+ csource = "\n".join(["%s somevar_%s;" % (tp, tp.replace(' ', '_'))
+ for tp in lst])
+ ffi.cdef(csource)
+ lib = ffi.verify(csource)
+ for tp in lst:
+ varname = 'somevar_%s' % tp.replace(' ', '_')
+ sz = ffi.sizeof(tp)
+ if tp != '_Bool':
+ max = (1 << (8*sz)) - 1
+ else:
+ max = 1
+ setattr(lib, varname, max)
+ assert getattr(lib, varname) == max
+ setattr(lib, varname, 0)
+ assert getattr(lib, varname) == 0
+ py.test.raises(OverflowError, setattr, lib, varname, max+1)
+ py.test.raises(OverflowError, setattr, lib, varname, -1)
+
+def test_fn_signed_integer_types():
+ ffi = FFI()
+ lst = all_signed_integer_types
+ cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
+ for tp in lst])
+ ffi.cdef(cdefsrc)
+ verifysrc = "\n".join(["%s somefn_%s(%s x) { return x; }" %
+ (tp, tp.replace(' ', '_'), tp) for tp in lst])
+ lib = ffi.verify(verifysrc)
+ for tp in lst:
+ fnname = 'somefn_%s' % tp.replace(' ', '_')
+ sz = ffi.sizeof(tp)
+ max = (1 << (8*sz-1)) - 1
+ min = -(1 << (8*sz-1))
+ fn = getattr(lib, fnname)
+ assert fn(max) == max
+ assert fn(min) == min
+ py.test.raises(OverflowError, fn, max + 1)
+ py.test.raises(OverflowError, fn, min - 1)
+
+def test_fn_unsigned_integer_types():
+ ffi = FFI()
+ lst = all_unsigned_integer_types
+ cdefsrc = "\n".join(["%s somefn_%s(%s);" % (tp, tp.replace(' ', '_'), tp)
+ for tp in lst])
+ ffi.cdef(cdefsrc)
+ verifysrc = "\n".join(["%s somefn_%s(%s x) { return x; }" %
+ (tp, tp.replace(' ', '_'), tp) for tp in lst])
+ lib = ffi.verify(verifysrc)
+ for tp in lst:
+ fnname = 'somefn_%s' % tp.replace(' ', '_')
+ sz = ffi.sizeof(tp)
+ if tp != '_Bool':
+ max = (1 << (8*sz)) - 1
+ else:
+ max = 1
+ fn = getattr(lib, fnname)
+ assert fn(max) == max
+ assert fn(0) == 0
+ py.test.raises(OverflowError, fn, max + 1)
+ py.test.raises(OverflowError, fn, -1)
def test_char_type():
ffi = FFI()
@@ -348,8 +433,8 @@
"%s != %s" % (typename, real))
def test_struct_bad_sized_integer():
- for typename in all_signed_integer_types:
- for real in all_signed_integer_types:
+ for typename in ['int8_t', 'int16_t', 'int32_t', 'int64_t']:
+ for real in ['int8_t', 'int16_t', 'int32_t', 'int64_t']:
_check_field_match(typename, real, "by_size")
def test_struct_bad_sized_float():
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit