Author: Wim Lavrijsen <wlavrij...@lbl.gov>
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
-@jit.dont_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
-
-@jit.dont_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
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to