[pypy-commit] pypy cppyy-packaging: (limited, through narrowing to double) support for long double
wlav
pypy.commits at gmail.com
Sun Jul 29 04:06:46 EDT 2018
Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: cppyy-packaging
Changeset: r94924:94c32f0372c1
Date: 2018-07-29 00:46 -0700
http://bitbucket.org/pypy/pypy/changeset/94c32f0372c1/
Log: (limited, through narrowing to double) support for long double
diff --git a/pypy/module/_cppyy/capi/loadable_capi.py b/pypy/module/_cppyy/capi/loadable_capi.py
--- a/pypy/module/_cppyy/capi/loadable_capi.py
+++ b/pypy/module/_cppyy/capi/loadable_capi.py
@@ -28,10 +28,11 @@
class _Arg: # poor man's union
_immutable_ = True
- def __init__(self, tc, h = 0, l = -1, s = '', p = rffi.cast(rffi.VOIDP, 0)):
+ def __init__(self, tc, h = 0, l = -1, d = -1., s = '', p = rffi.cast(rffi.VOIDP, 0)):
self.tc = tc
self._handle = h
self._long = l
+ self._double = d
self._string = s
self._voidp = p
@@ -45,6 +46,11 @@
def __init__(self, val):
_Arg.__init__(self, 'l', l = val)
+class _ArgD(_Arg):
+ _immutable_ = True
+ def __init__(self, val):
+ _Arg.__init__(self, 'd', d = val)
+
class _ArgS(_Arg):
_immutable_ = True
def __init__(self, val):
@@ -94,6 +100,9 @@
assert obj._voidp != rffi.cast(rffi.VOIDP, 0)
data = rffi.cast(rffi.VOIDPP, data)
data[0] = obj._voidp
+ elif obj.tc == 'd':
+ assert isinstance(argtype, ctypeprim.W_CTypePrimitiveFloat)
+ misc.write_raw_float_data(data, rffi.cast(rffi.DOUBLE, obj._double), argtype.size)
else: # only other use is string
assert obj.tc == 's'
n = len(obj._string)
@@ -187,6 +196,7 @@
'call_f' : ([c_method, c_object, c_int, c_voidp], c_float),
'call_d' : ([c_method, c_object, c_int, c_voidp], c_double),
'call_ld' : ([c_method, c_object, c_int, c_voidp], c_ldouble),
+ 'call_nld' : ([c_method, c_object, c_int, c_voidp], c_double),
'call_r' : ([c_method, c_object, c_int, c_voidp], c_voidp),
# call_s actually takes an size_t* as last parameter, but this will do
@@ -410,7 +420,9 @@
return rffi.cast(rffi.DOUBLE, space.float_w(call_capi(space, 'call_d', args)))
def c_call_ld(space, cppmethod, cppobject, nargs, cargs):
args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
- return rffi.cast(rffi.LONGDOUBLE, space.float_w(call_capi(space, 'call_ld', args)))
+ #return rffi.cast(rffi.LONGDOUBLE, space.float_w(call_capi(space, 'call_ld', args)))
+ # call_nld narrows long double to double
+ return rffi.cast(rffi.DOUBLE, space.float_w(call_capi(space, 'call_nld', args)))
def c_call_r(space, cppmethod, cppobject, nargs, cargs):
args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)]
@@ -664,6 +676,11 @@
def c_stdstring2stdstring(space, cppobject):
return _cdata_to_cobject(space, call_capi(space, 'stdstring2stdstring', [_ArgH(cppobject)]))
+def c_longdouble2double(space, addr):
+ return space.float_w(call_capi(space, 'longdouble2double', [_ArgP(addr)]))
+def c_double2longdouble(space, dval, addr):
+ call_capi(space, 'double2longdouble', [_ArgD(dval), _ArgP(addr)])
+
def c_vectorbool_getitem(space, vbool, idx):
return call_capi(space, 'vectorbool_getitem', [_ArgH(vbool), _ArgL(idx)])
def c_vectorbool_setitem(space, vbool, idx, value):
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
@@ -211,6 +211,9 @@
x[0] = self._unwrap_object(space, w_obj)
def default_argument_libffi(self, space, address):
+ if not self.valid_default:
+ from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
x = rffi.cast(self.c_ptrtype, address)
x[0] = self.default
@@ -224,7 +227,7 @@
rffiptr = rffi.cast(self.c_ptrtype, address)
rffiptr[0] = self._unwrap_object(space, w_value)
-class ConstRefNumericTypeConverterMixin(NumericTypeConverterMixin):
+class ConstRefNumericTypeConverterMixin(object):
_mixin_ = True
def cffi_type(self, space):
@@ -321,59 +324,92 @@
pass
class FloatConverter(ffitypes.typeid(rffi.FLOAT), FloatTypeConverterMixin, TypeConverter):
- _immutable_fields_ = ['default']
+ _immutable_fields_ = ['default', 'valid_default']
def __init__(self, space, default):
- if default:
+ self.valid_default = False
+ try:
fval = float(rfloat.rstring_to_float(default))
- else:
+ self.valid_default = True
+ except Exception:
fval = float(0.)
- self.default = r_singlefloat(fval)
+ self.default = rffi.cast(rffi.FLOAT, r_singlefloat(fval))
def from_memory(self, space, w_obj, offset):
address = self._get_raw_address(space, w_obj, offset)
rffiptr = rffi.cast(self.c_ptrtype, address)
return self._wrap_object(space, rffiptr[0])
-class ConstFloatRefConverter(FloatConverter):
+class ConstFloatRefConverter(ConstRefNumericTypeConverterMixin, FloatConverter):
_immutable_fields_ = ['typecode']
typecode = 'f'
- def cffi_type(self, space):
- state = space.fromcache(ffitypes.State)
- return state.c_voidp
-
- def convert_argument_libffi(self, space, w_obj, address, scratch):
- from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
- raise FastCallNotPossible
-
class DoubleConverter(ffitypes.typeid(rffi.DOUBLE), FloatTypeConverterMixin, TypeConverter):
- _immutable_fields_ = ['default']
+ _immutable_fields_ = ['default', 'valid_default']
def __init__(self, space, default):
- if default:
+ self.valid_default = False
+ try:
self.default = rffi.cast(self.c_type, rfloat.rstring_to_float(default))
- else:
+ self.valid_default = True
+ except Exception:
self.default = rffi.cast(self.c_type, 0.)
class ConstDoubleRefConverter(ConstRefNumericTypeConverterMixin, DoubleConverter):
_immutable_fields_ = ['typecode']
typecode = 'd'
-class LongDoubleConverter(ffitypes.typeid(rffi.LONGDOUBLE), FloatTypeConverterMixin, TypeConverter):
- _immutable_fields_ = ['default']
+class LongDoubleConverter(TypeConverter):
+ _immutable_fields_ = ['default', 'valid_default']
+ typecode = 'g'
def __init__(self, space, default):
- if default:
- fval = float(rfloat.rstring_to_float(default))
- else:
- fval = float(0.)
- self.default = r_longfloat(fval)
+ self.valid_default = False
+ try:
+ # use float() instead of cast with r_longfloat
+ fval = rffi.cast(rffi.DOUBLE, rfloat.rstring_to_float(default))
+ self.valid_default = True
+ except Exception:
+ fval = rffi.cast(rffi.DOUBLE, 0.)
+ #self.default = r_longfloat(fval)
+ self.default = fval
+
+ def convert_argument(self, space, w_obj, address):
+ x = rffi.cast(rffi.VOIDP, address)
+ capi.c_double2longdouble(space, space.float_w(w_obj), x)
+ ba = rffi.cast(rffi.CCHARP, address)
+ ba[capi.c_function_arg_typeoffset(space)] = self.typecode
+
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
+ x = rffi.cast(rffi.VOIDP, address)
+ capi.c_double2longdouble(space, space.float_w(w_obj), x)
+
+ def default_argument_libffi(self, space, address):
+ if not self.valid_default:
+ from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+ x = rffi.cast(rffi.VOIDP, address)
+ capi.c_double2longdouble(space, self.default, x)
+
+ def from_memory(self, space, w_obj, offset):
+ address = self._get_raw_address(space, w_obj, offset)
+ rffiptr = rffi.cast(rffi.VOIDP, address)
+ return space.newfloat(capi.c_longdouble2double(space, rffiptr))
+
+ def to_memory(self, space, w_obj, w_value, offset):
+ address = self._get_raw_address(space, w_obj, offset)
+ rffiptr = rffi.cast(rffi.VOIDP, address)
+ capi.c_double2longdouble(space, space.float_w(w_value), rffiptr)
class ConstLongDoubleRefConverter(ConstRefNumericTypeConverterMixin, LongDoubleConverter):
_immutable_fields_ = ['typecode']
typecode = 'g'
+ def convert_argument_libffi(self, space, w_obj, address, scratch):
+ capi.c_double2longdouble(space, space.float_w(w_obj), rffi.cast(rffi.VOIDP, scratch))
+ x = rffi.cast(rffi.VOIDPP, address)
+ x[0] = scratch
+
class CStringConverter(TypeConverter):
def convert_argument(self, space, w_obj, address):
@@ -949,8 +985,8 @@
_converters["const float&"] = ConstFloatRefConverter
_converters["double"] = DoubleConverter
_converters["const double&"] = ConstDoubleRefConverter
-#_converters["long double"] = LongDoubleConverter
-#_converters["const long double&"] = ConstLongDoubleRefConverter
+_converters["long double"] = LongDoubleConverter
+_converters["const long double&"] = ConstLongDoubleRefConverter
_converters["const char*"] = CStringConverter
_converters["void*"] = VoidPtrConverter
_converters["void**"] = VoidPtrPtrConverter
@@ -984,7 +1020,12 @@
_immutable_ = True
typecode = c_tc
def __init__(self, space, default):
- self.default = rffi.cast(self.c_type, capi.c_strtoll(space, default))
+ self.valid_default = False
+ try:
+ self.default = rffi.cast(self.c_type, capi.c_strtoll(space, default))
+ self.valid_default = True
+ except Exception:
+ self.default = rffi.cast(self.c_type, 0)
class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
_immutable_ = True
for name in names:
@@ -1001,7 +1042,12 @@
_immutable_ = True
typecode = c_tc
def __init__(self, space, default):
- self.default = rffi.cast(self.c_type, capi.c_strtoll(space, default))
+ self.valid_default = False
+ try:
+ self.default = rffi.cast(self.c_type, capi.c_strtoll(space, default))
+ self.valid_default = True
+ except Exception:
+ self.default = rffi.cast(self.c_type, 0)
class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
_immutable_ = True
for name in names:
@@ -1021,7 +1067,12 @@
_immutable_ = True
typecode = c_tc
def __init__(self, space, default):
- self.default = rffi.cast(self.c_type, capi.c_strtoull(space, default))
+ self.valid_default = False
+ try:
+ self.default = rffi.cast(self.c_type, capi.c_strtoull(space, default))
+ self.valid_default = True
+ except Exception:
+ self.default = rffi.cast(self.c_type, 0)
class ConstRefConverter(ConstRefNumericTypeConverterMixin, BasicConverter):
_immutable_ = True
for name in names:
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
@@ -76,9 +76,6 @@
class NumericExecutorMixin(object):
_mixin_ = True
- #def _wrap_object(self, space, obj):
- # return getattr(space, self.wrapper)(obj)
-
def execute(self, space, cppmethod, cppthis, num_args, args):
result = self.c_stubcall(space, cppmethod, cppthis, num_args, args)
return self._wrap_object(space, rffi.cast(self.c_type, result))
@@ -100,13 +97,10 @@
self.w_item = w_item
self.do_assign = True
- #def _wrap_object(self, space, obj):
- # return getattr(space, self.wrapper)(rffi.cast(self.c_type, obj))
-
def _wrap_reference(self, space, rffiptr):
if self.do_assign:
rffiptr[0] = rffi.cast(self.c_type, self._unwrap_object(space, self.w_item))
- self.do_assign = False
+ self.do_assign = False
return self._wrap_object(space, rffiptr[0]) # all paths, for rtyper
def execute(self, space, cppmethod, cppthis, num_args, args):
@@ -119,6 +113,48 @@
return self._wrap_reference(space,
rffi.cast(self.c_ptrtype, rffi.cast(rffi.VOIDPP, result)[0]))
+class LongDoubleExecutorMixin(object):
+ # Note: not really supported, but returns normal double
+ _mixin_ = True
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = self.c_stubcall(space, cppmethod, cppthis, num_args, args)
+ return space.newfloat(result)
+
+ def execute_libffi(self, space, cif_descr, funcaddr, buffer):
+ from pypy.module._cppyy.interp_cppyy import FastCallNotPossible
+ raise FastCallNotPossible
+
+class LongDoubleExecutor(ffitypes.typeid(rffi.LONGDOUBLE), LongDoubleExecutorMixin, Executor):
+ _immutable_ = True
+ c_stubcall = staticmethod(capi.c_call_ld)
+
+class LongDoubleRefExecutorMixin(NumericRefExecutorMixin):
+ # Note: not really supported, but returns normal double
+ _mixin_ = True
+
+ def _wrap_reference(self, space, rffiptr):
+ if self.do_assign:
+ capi.c_double2longdouble(space, space.float_w(self.w_item), rffiptr)
+ self.do_assign = False
+ return self.w_item
+ return space.newfloat(capi.c_longdouble2double(space, rffiptr))
+
+ def execute(self, space, cppmethod, cppthis, num_args, args):
+ result = capi.c_call_r(space, cppmethod, cppthis, num_args, args)
+ return self._wrap_reference(space, rffi.cast(self.c_ptrtype, result))
+
+ def execute_libffi(self, space, cif_descr, funcaddr, buffer):
+ jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer)
+ result = rffi.ptradd(buffer, cif_descr.exchange_result)
+ return self._wrap_reference(space,
+ rffi.cast(self.c_ptrtype, rffi.cast(rffi.VOIDPP, result)[0]))
+
+class LongDoubleRefExecutor(ffitypes.typeid(rffi.LONGDOUBLE), LongDoubleRefExecutorMixin, Executor):
+ def cffi_type(self, space):
+ state = space.fromcache(ffitypes.State)
+ return state.c_voidp
+
class CStringExecutor(Executor):
def execute(self, space, cppmethod, cppthis, num_args, args):
@@ -341,6 +377,10 @@
_executors["void*"] = PtrTypeExecutor
_executors["const char*"] = CStringExecutor
+# long double not really supported: narrows to double
+_executors["long double"] = LongDoubleExecutor
+_executors["long double&"] = LongDoubleRefExecutor
+
# special cases (note: 'string' aliases added below)
_executors["constructor"] = ConstructorExecutor
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
@@ -296,7 +296,8 @@
_immutable_fields_ = ['c_type', 'c_ptrtype', 'typecode']
c_type = rffi.LONGDOUBLE
- c_ptrtype = rffi.LONGDOUBLEP
+ # c_ptrtype = rffi.LONGDOUBLEP # useless type at this point
+ c_ptrtype = rffi.VOIDP
typecode = 'g'
# long double is not really supported ...
@@ -304,7 +305,7 @@
return r_longfloat(space.float_w(w_obj))
def _wrap_object(self, space, obj):
- return space.wrap(obj)
+ return space.newfloat(obj)
def cffi_type(self, space):
state = space.fromcache(State)
diff --git a/pypy/module/_cppyy/include/capi.h b/pypy/module/_cppyy/include/capi.h
--- a/pypy/module/_cppyy/include/capi.h
+++ b/pypy/module/_cppyy/include/capi.h
@@ -63,6 +63,8 @@
double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
long double cppyy_call_ld(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
+ RPY_EXTERN
+ double cppyy_call_nld(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
RPY_EXTERN
void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args);
@@ -220,6 +222,11 @@
cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr);
RPY_EXTERN
+ double cppyy_longdouble2double(void*);
+ RPY_EXTERN
+ void cppyy_double2longdouble(double, void*);
+
+ RPY_EXTERN
int cppyy_vectorbool_getitem(cppyy_object_t ptr, int idx);
RPY_EXTERN
void cppyy_vectorbool_setitem(cppyy_object_t ptr, int idx, int value);
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
@@ -230,8 +230,10 @@
if self.converters is None:
try:
self._setup(cppthis)
- except Exception:
- pass
+ except Exception as e:
+ if self.converters is None:
+ raise oefmt(self.space.w_SystemError,
+ "unable to initialize converters (%s)", str(e))
# attempt to call directly through ffi chain
if useffi and self._funcaddr:
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
@@ -113,6 +113,7 @@
float CppyyTestData::get_float() { return m_float; }
double CppyyTestData::get_double() { return m_double; }
long double CppyyTestData::get_ldouble() { return m_ldouble; }
+long double CppyyTestData::get_ldouble_def(long double ld) { return ld; }
CppyyTestData::EWhat CppyyTestData::get_enum() { return m_enum; }
void* CppyyTestData::get_voidp() { return m_voidp; }
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
@@ -96,6 +96,8 @@
float get_float();
double get_double();
long double get_ldouble();
+ typedef long double aap_t;
+ long double get_ldouble_def(long double ld = aap_t(1));
EWhat get_enum();
void* get_voidp();
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
@@ -56,10 +56,11 @@
assert round(c.m_double + 77., 11) == 0
assert round(c.get_double_cr() + 77., 11) == 0
assert round(c.get_double_r() + 77., 11) == 0
- #assert round(c.m_ldouble + 88., 24) == 0
- #assert round(c.get_ldouble_cr() + 88., 24) == 0
- #assert round(c.get_ldouble_r() + 88., 24) == 0
- assert round(c.m_double + 77., 8) == 0
+ assert round(c.m_ldouble + 88., 24) == 0
+ assert round(c.get_ldouble_cr() + 88., 24) == 0
+ assert round(c.get_ldouble_r() + 88., 24) == 0
+ assert round(c.get_ldouble_def() -1., 24) == 0
+ assert round(c.get_ldouble_def(2) -2., 24) == 0
"""# complex<double> type
assert type(c.get_complex()) == complex
@@ -187,16 +188,20 @@
assert eval('c.m_%s' % names[i]) == 3*i
# float types through functions
- c.set_float( 0.123 ); assert round(c.get_float() - 0.123, 5) == 0
- c.set_double( 0.456 ); assert round(c.get_double() - 0.456, 8) == 0
+ c.set_float(0.123); assert round(c.get_float() - 0.123, 5) == 0
+ c.set_double(0.456); assert round(c.get_double() - 0.456, 8) == 0
+ c.set_ldouble(0.789); assert round(c.get_ldouble() - 0.789, 8) == 0
# float types through data members
- c.m_float = 0.123; assert round(c.get_float() - 0.123, 5) == 0
- c.set_float(0.234); assert round(c.m_float - 0.234, 5) == 0
- c.set_float_cr(0.456); assert round(c.m_float - 0.456, 5) == 0
- c.m_double = 0.678; assert round(c.get_double() - 0.678, 8) == 0
- c.set_double(0.890); assert round(c.m_double - 0.890, 8) == 0
- c.set_double_cr(0.012); assert round(c.m_double - 0.012, 8) == 0
+ c.m_float = 0.123; assert round(c.get_float() - 0.123, 5) == 0
+ c.set_float(0.234); assert round(c.m_float - 0.234, 5) == 0
+ c.set_float_cr(0.456); assert round(c.m_float - 0.456, 5) == 0
+ c.m_double = 0.678; assert round(c.get_double() - 0.678, 8) == 0
+ c.set_double(0.890); assert round(c.m_double - 0.890, 8) == 0
+ c.set_double_cr(0.012); assert round(c.m_double - 0.012, 8) == 0
+ c.m_ldouble = 0.876; assert round(c.get_ldouble() - 0.876, 8) == 0
+ c.set_ldouble(0.098); assert round(c.m_ldouble - 0.098, 8) == 0
+ c.set_ldouble_cr(0.210); assert round(c.m_ldouble - 0.210, 8) == 0
# arrays; there will be pointer copies, so destroy the current ones
c.destroy_arrays()
@@ -295,10 +300,12 @@
assert CppyyTestData.s_ullong == 404
# floating point types
- assert round(CppyyTestData.s_float + 606., 5) == 0
- assert round(c.s_float + 606., 5) == 0
- assert round(CppyyTestData.s_double + 707., 8) == 0
- assert round(c.s_double + 707., 8) == 0
+ assert round(CppyyTestData.s_float + 606., 5) == 0
+ assert round(c.s_float + 606., 5) == 0
+ assert round(CppyyTestData.s_double + 707., 8) == 0
+ assert round(c.s_double + 707., 8) == 0
+ assert round(CppyyTestData.s_ldouble + 808., 8) == 0
+ assert round(c.s_ldouble + 808., 8) == 0
c.__destruct__()
@@ -363,6 +370,10 @@
assert CppyyTestData.s_double == -math.pi
CppyyTestData.s_double = math.pi
assert c.s_double == math.pi
+ c.s_ldouble = -math.pi
+ assert CppyyTestData.s_ldouble == -math.pi
+ CppyyTestData.s_ldouble = math.pi
+ assert c.s_ldouble == math.pi
c.__destruct__()
More information about the pypy-commit
mailing list