Author: Wim Lavrijsen <[email protected]>
Branch: cppyy-packaging
Changeset: r94611:eb16b0aff1e3
Date: 2018-05-17 09:39 -0700
http://bitbucket.org/pypy/pypy/changeset/eb16b0aff1e3/
Log: add support for unsigned char arrays and general cleanup of array
binding code + tests
diff --git a/pypy/module/_cppyy/capi/__init__.py
b/pypy/module/_cppyy/capi/__init__.py
--- a/pypy/module/_cppyy/capi/__init__.py
+++ b/pypy/module/_cppyy/capi/__init__.py
@@ -11,6 +11,3 @@
assert lltype.typeOf(ptr) == C_OBJECT
address = rffi.cast(rffi.CCHARP, ptr)
return rffi.cast(C_OBJECT, lltype.direct_ptradd(address, offset))
-
-def exchange_address(ptr, cif_descr, index):
- return rffi.ptradd(ptr, cif_descr.exchange_args[index])
diff --git a/pypy/module/_cppyy/converter.py b/pypy/module/_cppyy/converter.py
--- a/pypy/module/_cppyy/converter.py
+++ b/pypy/module/_cppyy/converter.py
@@ -7,7 +7,7 @@
from rpython.rlib import rfloat, rawrefcount
from pypy.module._rawffi.interp_rawffi import letter2tp
-from pypy.module._rawffi.array import W_Array, W_ArrayInstance
+from pypy.module._rawffi.array import W_ArrayInstance
from pypy.module._cppyy import helper, capi, ffitypes
@@ -130,20 +130,6 @@
pass
-class ArrayCache(object):
- def __init__(self, space):
- self.space = space
- def __getattr__(self, name):
- if name.startswith('array_'):
- typecode = name[len('array_'):]
- arr = self.space.interp_w(W_Array, letter2tp(self.space, typecode))
- setattr(self, name, arr)
- return arr
- raise AttributeError(name)
-
- def _freeze_(self):
- return True
-
class ArrayTypeConverterMixin(object):
_mixin_ = True
_immutable_fields_ = ['size']
@@ -162,9 +148,7 @@
# read access, so no copy needed
address_value = self._get_raw_address(space, w_obj, offset)
address = rffi.cast(rffi.ULONG, address_value)
- cache = space.fromcache(ArrayCache)
- arr = getattr(cache, 'array_' + self.typecode)
- return arr.fromaddress(space, address, self.size)
+ return W_ArrayInstance(space, letter2tp(space, self.typecode),
self.size, address)
def to_memory(self, space, w_obj, w_value, offset):
# copy the full array (uses byte copy for now)
@@ -205,17 +189,15 @@
# read access, so no copy needed
address_value = self._get_raw_address(space, w_obj, offset)
address = rffi.cast(rffi.ULONGP, address_value)
- cache = space.fromcache(ArrayCache)
- arr = getattr(cache, 'array_' + self.typecode)
- return arr.fromaddress(space, address[0], self.size)
+ return W_ArrayInstance(space, letter2tp(space, self.typecode),
self.size, address[0])
def to_memory(self, space, w_obj, w_value, offset):
# copy only the pointer value
rawobject = get_rawobject_nonnull(space, w_obj)
- byteptr = rffi.cast(rffi.CCHARPP, capi.direct_ptradd(rawobject,
offset))
+ byteptr = rffi.cast(rffi.VOIDPP, capi.direct_ptradd(rawobject, offset))
buf = space.getarg_w('s*', w_value)
try:
- byteptr[0] = buf.get_raw_address()
+ byteptr[0] = rffi.cast(rffi.VOIDP, buf.get_raw_address())
except ValueError:
raise oefmt(space.w_TypeError,
"raw buffer interface not supported")
@@ -337,6 +319,10 @@
address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj,
offset))
address[0] = self._unwrap_object(space, w_value)
+
+class UCharConverter(ffitypes.typeid(rffi.UCHAR), CharConverter):
+ pass
+
class FloatConverter(ffitypes.typeid(rffi.FLOAT), FloatTypeConverterMixin,
TypeConverter):
_immutable_fields_ = ['default']
@@ -449,12 +435,12 @@
# returned as a long value for the address (INTPTR_T is not proper
# per se, but rffi does not come with a PTRDIFF_T)
address = self._get_raw_address(space, w_obj, offset)
- ptrval = rffi.cast(rffi.ULONG, rffi.cast(rffi.VOIDPP, address)[0])
- if ptrval == 0:
+ ptrval = rffi.cast(rffi.ULONGP, address)[0]
+ if ptrval == rffi.cast(rffi.ULONG, 0):
from pypy.module._cppyy import interp_cppyy
return interp_cppyy.get_nullptr(space)
- arr = space.interp_w(W_Array, letter2tp(space, 'P'))
- return arr.fromaddress(space, ptrval, sys.maxint)
+ shape = letter2tp(space, 'P')
+ return W_ArrayInstance(space, shape, sys.maxint/shape.size, ptrval)
def to_memory(self, space, w_obj, w_value, offset):
address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj,
offset))
@@ -797,6 +783,7 @@
_converters["bool"] = BoolConverter
_converters["char"] = CharConverter
+_converters["unsigned char"] = UCharConverter
_converters["float"] = FloatConverter
_converters["const float&"] = ConstFloatRefConverter
_converters["double"] = DoubleConverter
@@ -886,6 +873,7 @@
"NOT_RPYTHON"
array_info = (
('b', rffi.sizeof(rffi.UCHAR), ("bool",)), # is debatable, but
works ...
+ ('B', rffi.sizeof(rffi.UCHAR), ("unsigned char",)),
('h', rffi.sizeof(rffi.SHORT), ("short int", "short")),
('H', rffi.sizeof(rffi.USHORT), ("unsigned short int", "unsigned
short")),
('i', rffi.sizeof(rffi.INT), ("int",)),
@@ -901,9 +889,11 @@
for tcode, tsize, names in array_info:
class ArrayConverter(ArrayTypeConverterMixin, TypeConverter):
+ _immutable_fields_ = ['typecode', 'typesize']
typecode = tcode
typesize = tsize
class PtrConverter(PtrTypeConverterMixin, TypeConverter):
+ _immutable_fields_ = ['typecode', 'typesize']
typecode = tcode
typesize = tsize
for name in names:
@@ -919,7 +909,6 @@
def _add_aliased_converters():
"NOT_RPYTHON"
aliases = (
- ("char", "unsigned char"), # TODO: check
("char", "signed char"), # TODO: check
("const char*", "char*"),
diff --git a/pypy/module/_cppyy/executor.py b/pypy/module/_cppyy/executor.py
--- a/pypy/module/_cppyy/executor.py
+++ b/pypy/module/_cppyy/executor.py
@@ -5,7 +5,7 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from rpython.rlib import jit_libffi
-from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
+from pypy.module._rawffi.interp_rawffi import letter2tp
from pypy.module._rawffi.array import W_Array, W_ArrayInstance
from pypy.module._cppyy import helper, capi, ffitypes
@@ -56,11 +56,11 @@
raise NotImplementedError
lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args)
ptrval = rffi.cast(rffi.ULONG, lresult)
- arr = space.interp_w(W_Array, unpack_simple_shape(space,
space.newtext(self.typecode)))
- if ptrval == 0:
+ if ptrval == rffi.cast(rffi.ULONG, 0):
from pypy.module._cppyy import interp_cppyy
return interp_cppyy.get_nullptr(space)
- return arr.fromaddress(space, ptrval, sys.maxint)
+ shape = letter2tp(space, self.typecode)
+ return W_ArrayInstance(space, shape, sys.maxint/shape.size, ptrval)
class VoidExecutor(FunctionExecutor):
diff --git a/pypy/module/_cppyy/ffitypes.py b/pypy/module/_cppyy/ffitypes.py
--- a/pypy/module/_cppyy/ffitypes.py
+++ b/pypy/module/_cppyy/ffitypes.py
@@ -74,6 +74,37 @@
# allow int to pass to char and make sure that str is of length 1
if space.isinstance_w(w_value, space.w_int):
ival = space.c_int_w(w_value)
+ if ival < -128 or 127 < ival:
+ raise oefmt(space.w_ValueError, "char arg not in
range(-128,128)")
+
+ value = rffi.cast(rffi.CHAR, space.c_int_w(w_value))
+ else:
+ value = space.text_w(w_value)
+ if len(value) != 1:
+ raise oefmt(space.w_ValueError,
+ "char expected, got string of size %d", len(value))
+
+ value = rffi.cast(rffi.CHAR, value[0])
+ return value # turn it into a "char" to the annotator
+
+ def cffi_type(self, space):
+ state = space.fromcache(State)
+ return state.c_char
+
+class UCharTypeMixin(object):
+ _mixin_ = True
+ _immutable_fields_ = ['c_type', 'c_ptrtype']
+
+ c_type = rffi.UCHAR
+ c_ptrtype = rffi.CCHARP # there's no such thing as rffi.UCHARP
+
+ def _wrap_object(self, space, obj):
+ return space.newbytes(obj)
+
+ def _unwrap_object(self, space, w_value):
+ # allow int to pass to char and make sure that str is of length 1
+ if space.isinstance_w(w_value, space.w_int):
+ ival = space.c_int_w(w_value)
if ival < 0 or 256 <= ival:
raise oefmt(space.w_ValueError, "char arg not in range(256)")
@@ -277,6 +308,7 @@
"NOT_RPYTHON"
if c_type == bool: return BoolTypeMixin
if c_type == rffi.CHAR: return CharTypeMixin
+ if c_type == rffi.UCHAR: return UCharTypeMixin
if c_type == rffi.SHORT: return ShortTypeMixin
if c_type == rffi.USHORT: return UShortTypeMixin
if c_type == rffi.INT: return IntTypeMixin
diff --git a/pypy/module/_cppyy/interp_cppyy.py
b/pypy/module/_cppyy/interp_cppyy.py
--- a/pypy/module/_cppyy/interp_cppyy.py
+++ b/pypy/module/_cppyy/interp_cppyy.py
@@ -267,11 +267,12 @@
def do_fast_call(self, cppthis, args_w, call_local):
if self.cif_descr == lltype.nullptr(jit_libffi.CIF_DESCRIPTION):
raise FastCallNotPossible
+ jit.promote(self)
cif_descr = self.cif_descr
buffer = lltype.malloc(rffi.CCHARP.TO, cif_descr.exchange_size,
flavor='raw')
try:
# this pointer
- data = capi.exchange_address(buffer, cif_descr, 0)
+ data = rffi.ptradd(buffer, cif_descr.exchange_args[0])
x = rffi.cast(rffi.LONGP, data) # LONGP needed for
test_zjit.py
x[0] = rffi.cast(rffi.LONG, cppthis)
@@ -280,11 +281,11 @@
for i in range(len(args_w)):
conv = self.converters[i]
w_arg = args_w[i]
- data = capi.exchange_address(buffer, cif_descr, i+1)
+ data = rffi.ptradd(buffer, cif_descr.exchange_args[i+1])
conv.convert_argument_libffi(self.space, w_arg, data,
call_local)
for j in range(i+1, len(self.arg_defs)):
conv = self.converters[j]
- data = capi.exchange_address(buffer, cif_descr, j+1)
+ data = rffi.ptradd(buffer, cif_descr.exchange_args[j+1])
conv.default_argument_libffi(self.space, data)
assert self._funcaddr
@@ -296,7 +297,7 @@
return w_res
# from ctypefunc; have my own version for annotater purposes and to disable
- # memory tracking (method live time is longer than the tests)
+ # memory tracking (method life time is longer than the tests)
@jit.dont_look_inside
def _rawallocate(self, builder):
builder.space = self.space
@@ -309,7 +310,7 @@
# allocate the buffer
if we_are_translated():
rawmem = lltype.malloc(rffi.CCHARP.TO, builder.nb_bytes,
- flavor='raw', track_allocation=False)
+ flavor='raw')
rawmem = rffi.cast(jit_libffi.CIF_DESCRIPTION_P, rawmem)
else:
# gross overestimation of the length below, but too bad
@@ -352,7 +353,7 @@
# has been offset to the matching class. Hence, the libffi pointer is
# uniquely defined and needs to be setup only once.
funcaddr = capi.c_function_address_from_index(self.space, self.scope,
self.index)
- if funcaddr and cppthis: # methods only for now
+ if funcaddr and cppthis: # TODO: methods only for now
state = self.space.fromcache(ffitypes.State)
# argument type specification (incl. cppthis)
diff --git a/pypy/module/_cppyy/test/datatypes.cxx
b/pypy/module/_cppyy/test/datatypes.cxx
--- a/pypy/module/_cppyy/test/datatypes.cxx
+++ b/pypy/module/_cppyy/test/datatypes.cxx
@@ -29,6 +29,7 @@
m_voidp = (void*)0;
m_bool_array2 = new bool[N];
+ m_uchar_array2 = new unsigned char[N];
m_short_array2 = new short[N];
m_ushort_array2 = new unsigned short[N];
m_int_array2 = new int[N];
@@ -42,6 +43,8 @@
for (int i = 0; i < N; ++i) {
m_bool_array[i] = bool(i%2);
m_bool_array2[i] = bool((i+1)%2);
+ m_uchar_array[i] = 1u*i;
+ m_uchar_array2[i] = 2u*i;
m_short_array[i] = -1*i;
m_short_array2[i] = -2*i;
m_ushort_array[i] = 3u*i;
@@ -114,6 +117,8 @@
bool* CppyyTestData::get_bool_array() { return m_bool_array; }
bool* CppyyTestData::get_bool_array2() { return m_bool_array2; }
+unsigned char* CppyyTestData::get_uchar_array() { return m_uchar_array; }
+unsigned char* CppyyTestData::get_uchar_array2() { return m_uchar_array2; }
short* CppyyTestData::get_short_array() { return m_short_array; }
short* CppyyTestData::get_short_array2() { return m_short_array2; }
unsigned short* CppyyTestData::get_ushort_array() { return m_ushort_array; }
@@ -233,6 +238,7 @@
void CppyyTestData::set_enum_cr(const EWhat& w) { m_enum =
w; }
//- passers -----------------------------------------------------------------
+unsigned char* CppyyTestData::pass_array(unsigned char* a) { return a; }
short* CppyyTestData::pass_array(short* a) { return a; }
unsigned short* CppyyTestData::pass_array(unsigned short* a) { return a; }
int* CppyyTestData::pass_array(int* a) { return a; }
diff --git a/pypy/module/_cppyy/test/datatypes.h
b/pypy/module/_cppyy/test/datatypes.h
--- a/pypy/module/_cppyy/test/datatypes.h
+++ b/pypy/module/_cppyy/test/datatypes.h
@@ -99,6 +99,8 @@
bool* get_bool_array();
bool* get_bool_array2();
+ unsigned char* get_uchar_array();
+ unsigned char* get_uchar_array2();
short* get_short_array();
short* get_short_array2();
unsigned short* get_ushort_array();
@@ -217,6 +219,7 @@
void set_enum_cr(const EWhat&);
// passers
+ unsigned char* pass_array(unsigned char*);
short* pass_array(short*);
unsigned short* pass_array(unsigned short*);
int* pass_array(int*);
@@ -226,6 +229,7 @@
float* pass_array(float*);
double* pass_array(double*);
+ unsigned char* pass_void_array_B(void* a) { return pass_array((unsigned
char*)a); }
short* pass_void_array_h(void* a) { return pass_array((short*)a);
}
unsigned short* pass_void_array_H(void* a) { return pass_array((unsigned
short*)a); }
int* pass_void_array_i(void* a) { return pass_array((int*)a); }
@@ -265,6 +269,8 @@
// array types
bool m_bool_array[N];
bool* m_bool_array2;
+ unsigned char m_uchar_array[N];
+ unsigned char* m_uchar_array2;
short m_short_array[N];
short* m_short_array2;
unsigned short m_ushort_array[N];
diff --git a/pypy/module/_cppyy/test/test_datatypes.py
b/pypy/module/_cppyy/test/test_datatypes.py
--- a/pypy/module/_cppyy/test/test_datatypes.py
+++ b/pypy/module/_cppyy/test/test_datatypes.py
@@ -73,8 +73,8 @@
assert c.get_bool_array2()[i] == bool((i+1)%2)
# reading of integer array types
- names = [ 'short', 'ushort', 'int', 'uint', 'long', 'ulong']
- alpha = [(-1, -2), (3, 4), (-5, -6), (7, 8), (-9, -10), (11, 12)]
+ names = ['uchar', 'short', 'ushort', 'int', 'uint', 'long',
'ulong']
+ alpha = [ (1, 2), (-1, -2), (3, 4), (-5, -6), (7, 8), (-9, -10),
(11, 12)]
for j in range(self.N):
assert getattr(c, 'm_%s_array' % names[i])[i] == alpha[i][0]*i
assert getattr(c, 'get_%s_array' % names[i])()[i] == alpha[i][0]*i
@@ -89,6 +89,7 @@
assert round(c.m_double_array2[k] + 16.*k, 8) == 0
# out-of-bounds checks
+ raises(IndexError, c.m_uchar_array.__getitem__, self.N)
raises(IndexError, c.m_short_array.__getitem__, self.N)
raises(IndexError, c.m_ushort_array.__getitem__, self.N)
raises(IndexError, c.m_int_array.__getitem__, self.N)
@@ -177,10 +178,10 @@
c.destroy_arrays()
# integer arrays
- names = ['short', 'ushort', 'int', 'uint', 'long', 'ulong']
+ names = ['uchar', 'short', 'ushort', 'int', 'uint', 'long', 'ulong']
import array
a = range(self.N)
- atypes = ['h', 'H', 'i', 'I', 'l', 'L' ]
+ atypes = ['B', 'h', 'H', 'i', 'I', 'l', 'L' ]
for j in range(len(names)):
b = array.array(atypes[j], a)
setattr(c, 'm_'+names[j]+'_array', b) # buffer copies
@@ -188,7 +189,7 @@
assert eval('c.m_%s_array[i]' % names[j]) == b[i]
setattr(c, 'm_'+names[j]+'_array2', b) # pointer copies
- b[i] = 28
+ b[3] = 28
for i in range(self.N):
assert eval('c.m_%s_array2[i]' % names[j]) == b[i]
@@ -681,6 +682,7 @@
c = CppyyTestData()
for func in ['get_bool_array', 'get_bool_array2',
+ 'get_uchar_array', 'get_uchar_array2',
'get_ushort_array', 'get_ushort_array2',
'get_int_array', 'get_int_array2',
'get_uint_array', 'get_uint_array2',
diff --git a/pypy/module/_cppyy/test/test_zjit.py
b/pypy/module/_cppyy/test/test_zjit.py
--- a/pypy/module/_cppyy/test/test_zjit.py
+++ b/pypy/module/_cppyy/test/test_zjit.py
@@ -17,19 +17,6 @@
# (note that the module is not otherwise used in the test itself)
import pypy.module.cpyext
-# change capi's direct_ptradd and exchange_address to being jit-opaque
[email protected]_look_inside
-def _opaque_direct_ptradd(ptr, offset):
- address = rffi.cast(rffi.CCHARP, ptr)
- return rffi.cast(capi.C_OBJECT, lltype.direct_ptradd(address, offset))
-capi.direct_ptradd = _opaque_direct_ptradd
-
[email protected]_look_inside
-def _opaque_exchange_address(ptr, cif_descr, index):
- offset = rffi.cast(rffi.LONG, cif_descr.exchange_args[index])
- return rffi.ptradd(ptr, offset)
-capi.exchange_address = _opaque_exchange_address
-
# add missing alt_errno (??)
def get_tlobj(self):
try:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit