Commits

wlav committed c1bf38d

o) mixin for floats
o) combine common mixing parts for floats and integers
o) support for float default arguments on ffi path

Comments (0)

Files changed (5)

pypy/module/cppyy/converter.py

 from pypy.interpreter.error import OperationError
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rlib.rarithmetic import r_singlefloat
-from pypy.rlib import jit, libffi, clibffi
+from pypy.rlib import jit, libffi, clibffi, rfloat
 
 from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
 from pypy.module._rawffi.array import W_Array
                                  space.wrap("raw buffer interface not supported"))
 
 
-class IntTypeConverterMixin(object):
+class NumericTypeConverterMixin(object):
     _mixin_ = True
     _immutable_ = True
 
-    def convert_argument(self, space, w_obj, address):
-        x = rffi.cast(self.rffiptype, address)
-        x[0] = self._unwrap_object(space, w_obj)
-
     def convert_argument_libffi(self, space, w_obj, argchain):
         argchain.arg(self._unwrap_object(space, w_obj))
 
         rffiptr = rffi.cast(self.rffiptype, address)
         rffiptr[0] = self._unwrap_object(space, w_value)
 
+class IntTypeConverterMixin(NumericTypeConverterMixin):
+    _mixin_ = True
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address):
+        x = rffi.cast(self.rffiptype, address)
+        x[0] = self._unwrap_object(space, w_obj)
+
+class FloatTypeConverterMixin(NumericTypeConverterMixin):
+    _mixin_ = True
+    _immutable_ = True
+
+    def convert_argument(self, space, w_obj, address):
+        x = rffi.cast(self.rffiptype, address)
+        x[0] = self._unwrap_object(space, w_obj)
+        typecode = rffi.cast(rffi.CCHARP,
+            _direct_ptradd(address, capi.c_function_arg_typeoffset()))
+        typecode[0] = self.typecode
+
 
 class VoidConverter(TypeConverter):
     _immutable_ = True
     def _unwrap_object(self, space, w_obj):
         return space.uint_w(w_obj)
 
-class FloatConverter(TypeConverter):
+
+class FloatConverter(FloatTypeConverterMixin, TypeConverter):
     _immutable_ = True
     libffitype = libffi.types.float
+    rffiptype = rffi.FLOATP
+    typecode = 'f'
+
+    def __init__(self, space, default):
+        if default:
+            fval = float(rfloat.rstring_to_float(default))
+        else:
+            fval = float(0.)
+        self.default = r_singlefloat(fval)
 
     def _unwrap_object(self, space, w_obj):
         return r_singlefloat(space.float_w(w_obj))
 
-    def convert_argument(self, space, w_obj, address):
-        x = rffi.cast(rffi.FLOATP, address)
-        x[0] = self._unwrap_object(space, w_obj)
-        typecode = rffi.cast(rffi.CCHARP,
-            _direct_ptradd(address, capi.c_function_arg_typeoffset()))
-        typecode[0] = 'f'
-
-    def convert_argument_libffi(self, space, w_obj, argchain):
-        from pypy.rlib.rarithmetic import r_singlefloat
-        fval = space.float_w(w_obj)
-        sfval = r_singlefloat(fval)
-        argchain.arg(sfval)
-
     def from_memory(self, space, w_obj, w_type, offset):
         address = self._get_raw_address(space, w_obj, offset)
-        floatptr = rffi.cast(rffi.FLOATP, address)
-        return space.wrap(float(floatptr[0]))
+        rffiptr = rffi.cast(self.rffiptype, address)
+        return space.wrap(float(rffiptr[0]))
 
-    def to_memory(self, space, w_obj, w_value, offset):
-        address = self._get_raw_address(space, w_obj, offset)
-        floatptr = rffi.cast(rffi.FLOATP, address)
-        floatptr[0] = self._unwrap_object(space, w_value)
-
-class DoubleConverter(TypeConverter):
+class DoubleConverter(FloatTypeConverterMixin, TypeConverter):
     _immutable_ = True
     libffitype = libffi.types.double
+    rffiptype = rffi.DOUBLEP
+    typecode = 'd'
+
+    def __init__(self, space, default):
+        if default:
+            self.default = rffi.cast(rffi.DOUBLE, rfloat.rstring_to_float(default))
+        else:
+            self.default = rffi.cast(rffi.DOUBLE, 0.)
 
     def _unwrap_object(self, space, w_obj):
         return space.float_w(w_obj)
 
-    def convert_argument(self, space, w_obj, address):
-        x = rffi.cast(rffi.DOUBLEP, address)
-        x[0] = self._unwrap_object(space, w_obj)
-        typecode = rffi.cast(rffi.CCHARP,
-            _direct_ptradd(address, capi.c_function_arg_typeoffset()))
-        typecode[0] = 'd'
-
-    def convert_argument_libffi(self, space, w_obj, argchain):
-        argchain.arg(self._unwrap_object(space, w_obj))
-
-    def from_memory(self, space, w_obj, w_type, offset):
-        address = self._get_raw_address(space, w_obj, offset)
-        doubleptr = rffi.cast(rffi.DOUBLEP, address)
-        return space.wrap(doubleptr[0])
-
-    def to_memory(self, space, w_obj, w_value, offset):
-        address = self._get_raw_address(space, w_obj, offset)
-        doubleptr = rffi.cast(rffi.DOUBLEP, address)
-        doubleptr[0] = self._unwrap_object(space, w_value)
-
 
 class CStringConverter(TypeConverter):
     _immutable_ = True

pypy/module/cppyy/interp_cppyy.py

+import pypy.module.cppyy.capi as capi
+
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.typedef import TypeDef, interp_attrproperty
 from pypy.rlib import libffi, rdynload, rweakref
 from pypy.rlib import jit, debug
 
-from pypy.module.cppyy import converter, executor, helper, capi
+from pypy.module.cppyy import converter, executor, helper
 
 
 class FastCallNotPossible(Exception):
     pass
 
 def _direct_ptradd(ptr, offset):        # TODO: factor out with convert.py
+    assert lltype.typeOf(ptr) == capi.C_OBJECT
     address = rffi.cast(rffi.CCHARP, ptr)
     return rffi.cast(capi.C_OBJECT, lltype.direct_ptradd(address, offset))
 

pypy/module/cppyy/test/example01.cxx

 typeValueImp(long, long)
 typeValueImp(unsigned long, ulong)
 
+typeValueImp(float, float)
+typeValueImp(double, double)
+
 std::string ArgPasser::stringValue(std::string arg0, int argn, std::string arg1)
 {
    switch (argn) {

pypy/module/cppyy/test/example01.h

     int globalAddOneToInt(int a);
 }
 
-#define typeValue(itype, tname) \
+#define itypeValue(itype, tname) \
    itype tname##Value(itype arg0, int argn=0, itype arg1=1, itype arg2=2)
 
+#define ftypeValue(ftype) \
+   ftype ftype##Value(ftype arg0, int argn=0, ftype arg1=1., ftype arg2=2.)
+
 // argument passing
 class ArgPasser {        // use a class for now as methptrgetter not
 public:                  // implemented for global functions
-   typeValue(short, short);
-   typeValue(unsigned short, ushort);
-   typeValue(int, int);
-   typeValue(unsigned int, uint);
-   typeValue(long, long);
-   typeValue(unsigned long, ulong);
+   itypeValue(short, short);
+   itypeValue(unsigned short, ushort);
+   itypeValue(int, int);
+   itypeValue(unsigned int, uint);
+   itypeValue(long, long);
+   itypeValue(unsigned long, ulong);
+
+   ftypeValue(float);
+   ftypeValue(double);
 
    std::string stringValue(
       std::string arg0, int argn=0, std::string arg1 = "default");

pypy/module/cppyy/test/test_pythonify.py

             assert g(11, 2)         ==  2
             assert g(11)            == 11
 
-    def test12_underscore_in_class_name(self):
+        for ftype in ['float', 'double']:
+            g = getattr(a, '%sValue' % ftype)
+            raises(TypeError, 'g(1., 2, 3., 4., 6.)')
+            assert g(11., 0, 12., 13.) == 11.
+            assert g(11., 1, 12., 13.) == 12.
+            assert g(11., 1, 12.)      == 12.
+            assert g(11., 2, 12.)      ==  2.
+            assert g(11., 1)           ==  1.
+            assert g(11., 2)           ==  2.
+            assert g(11.)              == 11.
+
+    def test11_underscore_in_class_name(self):
         """Test recognition of '_' as part of a valid class name"""
 
         import cppyy