Commits

wlav committed f800d0b

stricter handling of r_float and bool and associated tests

  • Participants
  • Parent commits c1ecf89
  • Branches reflex-support

Comments (0)

Files changed (11)

File pypy/module/cppyy/capi/__init__.py

     compilation_info=backend.eci)
 c_call_b = rffi.llexternal(
     "cppyy_call_b",
-    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.INT,
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.UCHAR,
     threadsafe=ts_call,
     compilation_info=backend.eci)
 c_call_c = rffi.llexternal(
     compilation_info=backend.eci)
 c_call_f = rffi.llexternal(
     "cppyy_call_f",
-    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.DOUBLE,
+    [C_METHOD, C_OBJECT, rffi.INT, rffi.VOIDP], rffi.FLOAT,
     threadsafe=ts_call,
     compilation_info=backend.eci)
 c_call_d = rffi.llexternal(

File pypy/module/cppyy/converter.py

                              space.wrap('no converter available for type "%s"' % self.name))
 
 
-class BoolConverter(TypeConverter):
+class BoolConverter(ffitypes.typeid(bool), TypeConverter):
     _immutable_ = True
-    libffitype = libffi.types.schar
-
-    def _unwrap_object(self, space, w_obj):
-        arg = space.c_int_w(w_obj)
-        if arg != False and arg != True:
-            raise OperationError(space.w_ValueError,
-                                 space.wrap("boolean value should be bool, or integer 1 or 0"))
-        return arg
 
     def convert_argument(self, space, w_obj, address, call_local):
         x = rffi.cast(rffi.LONGP, address)

File pypy/module/cppyy/executor.py

     _mixin_ = True
     _immutable_ = True
 
-    def _wrap_result(self, space, result):
-        return space.wrap(rffi.cast(self.c_type, result))
+    def _wrap_object(self, space, obj):
+        return space.wrap(obj)
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
         result = self.c_stubcall(cppmethod, cppthis, num_args, args)
-        return self._wrap_result(space, result)
+        return self._wrap_object(space, rffi.cast(self.c_type, result))
 
     def execute_libffi(self, space, libffifunc, argchain):
         result = libffifunc.call(argchain, self.c_type)
-        return space.wrap(result)
+        return self._wrap_object(space, result)
 
 class NumericRefExecutorMixin(object):
     _mixin_ = True
         self.item = self._unwrap_object(space, w_item)
         self.do_assign = True
 
-    def _wrap_result(self, space, rffiptr):
+    def _wrap_object(self, space, obj):
+        return space.wrap(rffi.cast(self.c_type, obj))
+
+    def _wrap_reference(self, space, rffiptr):
         if self.do_assign:
             rffiptr[0] = self.item
-        return space.wrap(rffiptr[0])   # all paths, for rtyper
+        self.do_assign = False
+        return self._wrap_object(space, rffiptr[0])    # all paths, for rtyper
 
     def execute(self, space, cppmethod, cppthis, num_args, args):
-        result = rffi.cast(self.c_ptrtype, capi.c_call_r(cppmethod, cppthis, num_args, args))
-        return self._wrap_result(space, result)
+        result = capi.c_call_r(cppmethod, cppthis, num_args, args)
+        return self._wrap_reference(space, rffi.cast(self.c_ptrtype, result))
 
     def execute_libffi(self, space, libffifunc, argchain):
         result = libffifunc.call(argchain, self.c_ptrtype)
-        return self._wrap_result(space, result)
-
-
-class BoolExecutor(FunctionExecutor):
-    _immutable_ = True
-    libffitype  = libffi.types.schar
-
-    def execute(self, space, cppmethod, cppthis, num_args, args):
-        result = capi.c_call_b(cppmethod, cppthis, num_args, args)
-        return space.wrap(result)
-
-    def execute_libffi(self, space, libffifunc, argchain):
-        result = libffifunc.call(argchain, rffi.CHAR)
-        return space.wrap(bool(ord(result)))
-
-class ConstIntRefExecutor(FunctionExecutor):
-    _immutable_ = True
-    libffitype = libffi.types.pointer
-
-    def _wrap_result(self, space, result):
-        intptr = rffi.cast(rffi.INTP, result)
-        return space.wrap(intptr[0])
-
-    def execute(self, space, cppmethod, cppthis, num_args, args):
-        result = capi.c_call_r(cppmethod, cppthis, num_args, args)
-        return self._wrap_result(space, result)
-
-    def execute_libffi(self, space, libffifunc, argchain):
-        result = libffifunc.call(argchain, rffi.INTP)
-        return space.wrap(result[0])
-
-class ConstLongRefExecutor(ConstIntRefExecutor):
-    _immutable_ = True
-    libffitype = libffi.types.pointer
-
-    def _wrap_result(self, space, result):
-        longptr = rffi.cast(rffi.LONGP, result)
-        return space.wrap(longptr[0])
-
-    def execute_libffi(self, space, libffifunc, argchain):
-        result = libffifunc.call(argchain, rffi.LONGP)
-        return space.wrap(result[0])
-
-class FloatExecutor(FunctionExecutor):
-    _immutable_ = True
-    libffitype = libffi.types.float
-
-    def execute(self, space, cppmethod, cppthis, num_args, args):
-        result = capi.c_call_f(cppmethod, cppthis, num_args, args)
-        return space.wrap(float(result))
-
-    def execute_libffi(self, space, libffifunc, argchain):
-        result = libffifunc.call(argchain, rffi.FLOAT)
-        return space.wrap(float(result))
+        return self._wrap_reference(space, result)
 
 
 class CStringExecutor(FunctionExecutor):
 
 _executors["void"]                = VoidExecutor
 _executors["void*"]               = PtrTypeExecutor
-_executors["bool"]                = BoolExecutor
 _executors["const char*"]         = CStringExecutor
-_executors["const int&"]          = ConstIntRefExecutor
-_executors["float"]               = FloatExecutor
 
+# special cases
 _executors["constructor"]         = ConstructorExecutor
 
-# special cases
 _executors["std::basic_string<char>"]         = StdStringExecutor
 _executors["const std::basic_string<char>&"]  = StdStringExecutor
 _executors["std::basic_string<char>&"]        = StdStringExecutor    # TODO: shouldn't copy
 def _build_basic_executors():
     "NOT_RPYTHON"
     type_info = (
+        (bool,            capi.c_call_b,   ("bool",)),
         (rffi.CHAR,       capi.c_call_c,   ("char", "unsigned char")),
         (rffi.SHORT,      capi.c_call_h,   ("short", "short int", "unsigned short", "unsigned short int")),
         (rffi.INT,        capi.c_call_i,   ("int",)),
         (rffi.ULONG,      capi.c_call_l,   ("unsigned long", "unsigned long int")),
         (rffi.LONGLONG,   capi.c_call_ll,  ("long long", "long long int")),
         (rffi.ULONGLONG,  capi.c_call_ll,  ("unsigned long long", "unsigned long long int")),
-        (rffi.DOUBLE,     capi.c_call_d,   ("double",))
+        (rffi.FLOAT,      capi.c_call_f,   ("float",)),
+        (rffi.DOUBLE,     capi.c_call_d,   ("double",)),
     )
 
     for c_type, stub, names in type_info:
             _immutable_ = True
             libffitype = libffi.types.pointer
         for name in names:
-            _executors[name]     = BasicExecutor
-            _executors[name+'&'] = BasicRefExecutor
+            _executors[name]              = BasicExecutor
+            _executors[name+'&']          = BasicRefExecutor
+            _executors['const '+name+'&'] = BasicRefExecutor     # no copy needed for builtins
 _build_basic_executors()
 
 # create the pointer executors; all real work is in the PtrTypeExecutor, since

File pypy/module/cppyy/ffitypes.py

 # mixin, a non-RPython function typeid() is used.
 
 
+class BoolTypeMixin(object):
+    _mixin_     = True
+    _immutable_ = True
+    libffitype  = libffi.types.uchar
+    c_type      = rffi.UCHAR
+    c_ptrtype   = rffi.UCHARP
+
+    def _unwrap_object(self, space, w_obj):
+        arg = space.c_int_w(w_obj)
+        if arg != False and arg != True:
+            raise OperationError(space.w_ValueError,
+                                 space.wrap("boolean value should be bool, or integer 1 or 0"))
+        return arg
+
+    def _wrap_object(self, space, obj):
+        return space.wrap(bool(ord(rffi.cast(rffi.CHAR, obj))))
+
 class CharTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
     def _unwrap_object(self, space, w_obj):
         return r_singlefloat(space.float_w(w_obj))
 
+    def _wrap_object(self, space, obj):
+        return space.wrap(float(obj))
+
 class DoubleTypeMixin(object):
     _mixin_     = True
     _immutable_ = True
 
 def typeid(c_type):
     "NOT_RPYTHON"
+    if c_type == bool:            return BoolTypeMixin
     if c_type == rffi.CHAR:       return CharTypeMixin
     if c_type == rffi.SHORT:      return ShortTypeMixin
     if c_type == rffi.USHORT:     return UShortTypeMixin

File pypy/module/cppyy/include/capi.h

 
     /* method/function dispatching -------------------------------------------- */
     void   cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
-    int    cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
     char   cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
     short  cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
     int    cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
     long   cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
     long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
-    double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+    float  cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
     double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
 
     void*  cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);

File pypy/module/cppyy/src/cintcwrapper.cxx

     cppyy_call_T(method, self, nargs, args);
 }
 
-int cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
     G__value result = cppyy_call_T(method, self, nargs, args);
-    return (bool)G__int(result);
+    return (unsigned char)(bool)G__int(result);
 }
 
 char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
     return G__Longlong(result);
 }
 
-double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
     G__value result = cppyy_call_T(method, self, nargs, args);
-    return G__double(result);
+    return (float)G__double(result);
 }
 
 double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {

File pypy/module/cppyy/src/reflexcwrapper.cxx

     return result;
 }
 
-int cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
-    return (int)cppyy_call_T<bool>(method, self, nargs, args);
+unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    return (unsigned char)cppyy_call_T<bool>(method, self, nargs, args);
 }
 
 char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
     return cppyy_call_T<long long>(method, self, nargs, args);
 }
 
-double cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
     return cppyy_call_T<float>(method, self, nargs, args);
 }
 

File pypy/module/cppyy/test/stltypes.cxx

 
 //- explicit instantiations of used types
 STLTYPES_EXPLICIT_INSTANTIATION(vector, int)
+STLTYPES_EXPLICIT_INSTANTIATION(vector, float)
 STLTYPES_EXPLICIT_INSTANTIATION(vector, double)
 STLTYPES_EXPLICIT_INSTANTIATION(vector, just_a_class)
 

File pypy/module/cppyy/test/stltypes.h

 #ifndef __CINT__
 //- explicit instantiations of used types
 STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, int)
+STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, float)
 STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, double)
 STLTYPES_EXPLICIT_INSTANTIATION_DECL(vector, just_a_class)
 #endif

File pypy/module/cppyy/test/test_cint.py

         c.set_data(13)
         assert c.m_data == 13
         assert c.get_data() == 13
+
+
+class AppTestCINTPythonizations:
+    def setup_class(cls):
+        cls.space = space
+
+    def test03_TVector(self):
+        """Test TVector2/3/T behavior"""
+
+        import cppyy, math
+
+        N = 51
+
+        # TVectorF is a typedef of floats
+        v = cppyy.gbl.TVectorF(N)
+        for i in range(N):
+            v[i] = i*i
+
+        #for j in v:       # TODO: raise exception on out-of-bounds
+        #   assert round(v[int(math.sqrt(j)+0.5)]-j, 5) == 0.
+        for i in range(N):
+            j = v[i]
+            assert round(v[int(math.sqrt(j)+0.5)]-j, 5) == 0.

File pypy/module/cppyy/test/test_stltypes.py

 
         assert callable(cppyy.gbl.std.vector)
 
-        tv1i = getattr(cppyy.gbl.std, 'vector<int>')
-        tv2i = cppyy.gbl.std.vector(int)
-        assert tv1i is tv2i
-        assert cppyy.gbl.std.vector(int).iterator is cppyy.gbl.std.vector('int').iterator
+        type_info = (
+            ("int",     int),
+            ("float",   "float"),
+            ("double",  "double"),
+        )
 
-        tv1d = getattr(cppyy.gbl.std, 'vector<double>')
-        tv2d = cppyy.gbl.std.vector('double')
-        assert tv1d is tv2d
-        assert tv1d.iterator is cppyy.gbl.std.vector('double').iterator
+        for c_type, p_type in type_info:
+            tv1 = getattr(cppyy.gbl.std, 'vector<%s>' % c_type)
+            tv2 = cppyy.gbl.std.vector(p_type)
+            assert tv1 is tv2
+            assert tv1.iterator is cppyy.gbl.std.vector(p_type).iterator
 
-        #-----
-        vi = tv1i(self.N)
-        vd = tv1d(); vd += range(self.N)     # default args from Reflex are useless :/
-        def test_v(v):
+            #-----
+            v = tv1(); v += range(self.N)    # default args from Reflex are useless :/
             assert v.begin().__eq__(v.begin())
             assert v.begin() == v.begin()
             assert v.end() == v.end()
             assert v.begin() != v.end()
             assert v.end() != v.begin()
-        test_v(vi)
-        test_v(vd)
 
-        #-----
-        def test_v(v):
+            #-----
             for i in range(self.N):
                 v[i] = i
                 assert v[i] == i
 
             assert v.size() == self.N
             assert len(v) == self.N
-        test_v(vi)
-        test_v(vd)
 
-        #-----
-        vi = tv1i()
-        vd = tv1d()
-        def test_v(v):
+            #-----
+            v = tv1()
             for i in range(self.N):
                 v.push_back(i)
                 assert v.size() == i+1
 
             assert v.size() == self.N
             assert len(v) == self.N
-        test_v(vi)
-        test_v(vd)
 
     def test02_user_type_vector_type(self):
         """Test access to an std::vector<just_a_class>"""