diff options
34 files changed, 3583 insertions, 1107 deletions
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst index 3e2410d9b7..7a4e4c67bb 100644 --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -74,3 +74,9 @@ Update the version of Tk/Tcl on windows to 8.6 .. branch: big-sur-dyld-cache Backport changes to ``_ctypes`` needed for maxos BigSur from py3.7 + +.. branch: cppyy-packaging + +Updated the API to the latest cppyy_backend (1.14.2), made all types used +consistent to avoid void*/long casting problems on Win64, and added several +new "builtin" types (wide chars, complex, etc.). diff --git a/pypy/module/_cppyy/capi/capi_types.py b/pypy/module/_cppyy/capi/capi_types.py index 0d0f6fb8e8..4b744111b9 100644 --- a/pypy/module/_cppyy/capi/capi_types.py +++ b/pypy/module/_cppyy/capi/capi_types.py @@ -1,21 +1,18 @@ from rpython.rtyper.lltypesystem import rffi, lltype # shared ll definitions -_C_OPAQUE_PTR = rffi.ULONG -_C_OPAQUE_NULL = lltype.nullptr(rffi.ULONGP.TO)# ALT: _C_OPAQUE_PTR.TO +C_SCOPE = rffi.SIZE_T +C_NULL_SCOPE = rffi.cast(C_SCOPE, 0) +C_TYPE = C_SCOPE +C_NULL_TYPE = rffi.cast(C_TYPE, 0) +C_ENUM = rffi.VOIDP +C_NULL_ENUM = rffi.cast(C_ENUM, 0) +C_OBJECT = rffi.VOIDP +C_NULL_OBJECT = rffi.cast(C_OBJECT, 0) +C_METHOD = rffi.INTPTR_T -C_SCOPE = _C_OPAQUE_PTR -C_NULL_SCOPE = rffi.cast(C_SCOPE, _C_OPAQUE_NULL) +C_INDEX = rffi.SIZE_T +C_INDEX_ARRAY = rffi.CArrayPtr(rffi.SIZE_T) +C_FUNC_PTR = rffi.VOIDP -C_TYPE = C_SCOPE -C_NULL_TYPE = C_NULL_SCOPE - -C_OBJECT = _C_OPAQUE_PTR -C_NULL_OBJECT = rffi.cast(C_OBJECT, _C_OPAQUE_NULL) - -C_METHOD = _C_OPAQUE_PTR -C_INDEX = rffi.LONG -C_INDEX_ARRAY = rffi.LONGP -WLAVC_INDEX = rffi.LONG - -C_FUNC_PTR = rffi.VOIDP +C_EXCTYPE = rffi.ULONG diff --git a/pypy/module/_cppyy/capi/loadable_capi.py b/pypy/module/_cppyy/capi/loadable_capi.py index f358ac4693..b371c8ce47 100644 --- a/pypy/module/_cppyy/capi/loadable_capi.py +++ b/pypy/module/_cppyy/capi/loadable_capi.py @@ -13,12 +13,13 @@ from pypy.interpreter.typedef import TypeDef from pypy.objspace.std.iterobject import W_AbstractSeqIterObject from pypy.module._rawffi.interp_array import W_ArrayInstance -from pypy.module._cffi_backend import ctypefunc, ctypeprim, cdataobj, misc +from pypy.module._cffi_backend import ctypefunc, cdataobj, misc from pypy.module._cffi_backend import newtype from pypy.module._cppyy import ffitypes +from pypy.module.sys.version import PYPY_VERSION from pypy.module._cppyy.capi.capi_types import C_SCOPE, C_TYPE, C_OBJECT,\ - C_METHOD, C_INDEX, C_INDEX_ARRAY, WLAVC_INDEX, C_FUNC_PTR + C_METHOD, C_INDEX, C_INDEX_ARRAY, C_FUNC_PTR backend_ext = '.so' if sys.platform == 'win32': @@ -34,29 +35,52 @@ std_string_name = 'std::string' class _Arg: # poor man's union _immutable_ = True - def __init__(self, tc, h = 0, u = 0, l = -1, d = -1., s = '', p = rffi.cast(rffi.VOIDP, 0)): + def __init__(self, tc, h = rffi.cast(C_SCOPE, 0), + m = rffi.cast(C_METHOD, 0), + o = rffi.cast(C_OBJECT, 0), + u = rffi.cast(C_INDEX, -1), + i = rffi.cast(rffi.INT, -1), + d = rffi.cast(rffi.DOUBLE, -1.), + s = '', + p = rffi.cast(rffi.VOIDP, 0)): self.tc = tc - self._handle = h + self._scope = h + self._method = m + self._object = o self._index = u - self._long = l + self._int = i self._double = d self._string = s self._voidp = p +# use separate classes for the benefit of the rtyper class _ArgH(_Arg): _immutable_ = True def __init__(self, val): _Arg.__init__(self, 'h', h = val) -class _ArgU(_Arg): # separate class for rtyper +def _ArgC(val): + return _ArgH(val.handle) + +class _ArgM(_Arg): + _immutable_ = True + def __init__(self, val): + _Arg.__init__(self, 'm', m = val) + +class _ArgO(_Arg): + _immutable_ = True + def __init__(self, val): + _Arg.__init__(self, 'o', o = val) + +class _ArgU(_Arg): _immutable_ = True def __init__(self, val): _Arg.__init__(self, 'u', u = val) -class _ArgL(_Arg): +class _ArgI(_Arg): _immutable_ = True def __init__(self, val): - _Arg.__init__(self, 'l', l = val) + _Arg.__init__(self, 'i', i = val) class _ArgD(_Arg): _immutable_ = True @@ -102,24 +126,23 @@ class W_RCTypeFunc(ctypefunc.W_CTypeFunc): argtype = self.fargs[i] # the following is clumsy, but the data types used as arguments are # very limited, so it'll do for now - if obj.tc == 'l': - assert isinstance(argtype, ctypeprim.W_CTypePrimitiveSigned) - misc.write_raw_signed_data(data, rffi.cast(rffi.LONG, obj._long), argtype.size) - elif obj.tc == 'h': - assert isinstance(argtype, ctypeprim.W_CTypePrimitiveUnsigned) - misc.write_raw_unsigned_data(data, rffi.cast(rffi.UINTPTR_T, obj._handle), argtype.size) + if obj.tc == 'h': + misc.write_raw_unsigned_data(data, rffi.cast(rffi.SIZE_T, obj._scope), argtype.size) + elif obj.tc == 'm': + misc.write_raw_signed_data(data, rffi.cast(rffi.INTPTR_T, obj._method), argtype.size) + elif obj.tc == 'o': + misc.write_raw_signed_data(data, rffi.cast(rffi.VOIDP, obj._object), argtype.size) elif obj.tc == 'u': - assert isinstance(argtype, ctypeprim.W_CTypePrimitiveUnsigned) misc.write_raw_unsigned_data(data, rffi.cast(rffi.SIZE_T, obj._index), argtype.size) + elif obj.tc == 'i': + misc.write_raw_signed_data(data, rffi.cast(rffi.INT, obj._int), argtype.size) + elif obj.tc == 'd': + misc.write_raw_float_data(data, rffi.cast(rffi.DOUBLE, obj._double), argtype.size) elif obj.tc == 'p': 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' + elif obj.tc == 's': n = len(obj._string) data = rffi.cast(rffi.CCHARPP, data) if raw_string1 == rffi.cast(rffi.CCHARP, 0): @@ -130,6 +153,11 @@ class W_RCTypeFunc(ctypefunc.W_CTypeFunc): assert raw_string2 == rffi.cast(rffi.CCHARP, 0) raw_string2 = rffi.str2charp(obj._string) data[0] = raw_string2 + else: # only other use is voidp + assert obj.tc == 'p' + assert obj._voidp != rffi.cast(rffi.VOIDP, 0) + data = rffi.cast(rffi.VOIDPP, data) + data[0] = obj._voidp jit_libffi.jit_ffi_call(cif_descr, rffi.cast(rffi.VOIDP, funcaddr), @@ -157,18 +185,18 @@ class State(object): # TODO: the following need to match up with the globally defined C_XYZ low-level # types (see capi/__init__.py), but by using strings here, that isn't guaranteed - c_opaque_ptr = state.c_uintptr_t # not size_t (which is signed) + c_voidp = state.c_voidp c_size_t = state.c_size_t c_ptrdiff_t = state.c_ptrdiff_t c_intptr_t = state.c_intptr_t - c_uintptr_t = state.c_uintptr_t - c_scope = c_opaque_ptr + c_scope = c_size_t c_type = c_scope - c_object = c_opaque_ptr # not voidp (to stick with one handle type) - c_method = c_uintptr_t # not intptr_t (which is signed) + c_enum = c_voidp + c_object = c_voidp + c_method = c_intptr_t c_index = c_size_t - c_index_array = state.c_voidp + c_index_array = c_voidp c_void = state.c_void c_char = state.c_char @@ -182,12 +210,12 @@ class State(object): c_double = state.c_double c_ldouble = state.c_ldouble - c_ccharp = state.c_ccharp - c_voidp = state.c_voidp + c_ccharp = state.c_ccharp self.capi_call_ifaces = { # direct interpreter access 'compile' : ([c_ccharp], c_int), + 'cppyy_to_string' : ([c_type, c_object], c_ccharp), # name to opaque C++ scope representation 'resolve_name' : ([c_ccharp], c_ccharp), @@ -197,6 +225,9 @@ class State(object): 'size_of_klass' : ([c_type], c_size_t), 'size_of_type' : ([c_ccharp], c_size_t), + 'is_builtin' : ([c_ccharp], c_int), + 'is_complete' : ([c_ccharp], c_int), + # memory management 'allocate' : ([c_type], c_object), 'deallocate' : ([c_type, c_object], c_void), @@ -220,8 +251,8 @@ class State(object): '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 'call_s' : ([c_method, c_object, c_int, c_voidp, c_voidp], c_ccharp), - 'constructor' : ([c_method, c_object, c_int, c_voidp], c_object), + 'destructor' : ([c_type, c_object], c_void), 'call_o' : ([c_method, c_object, c_int, c_voidp, c_type], c_object), 'function_address' : ([c_method], c_voidp), # TODO: verify @@ -237,6 +268,8 @@ class State(object): 'is_template' : ([c_ccharp], c_int), 'is_abstract' : ([c_type], c_int), 'is_enum' : ([c_ccharp], c_int), + 'is_aggregate' : ([c_ccharp], c_int), + 'is_default_constructable' : ([c_ccharp], c_int), 'get_all_cpp_names' : ([c_scope, c_voidp], c_voidp), # const char** @@ -250,11 +283,13 @@ class State(object): 'has_complex_hierarchy' : ([c_type], c_int), 'num_bases' : ([c_type], c_int), 'base_name' : ([c_type, c_int], c_ccharp), - 'is_smartptr' : ([c_type], c_int), 'is_subtype' : ([c_type, c_type], c_int), + 'is_smartptr' : ([c_type], c_int), 'smartptr_info' : ([c_ccharp, c_voidp, c_voidp], c_int), 'add_smartptr_type' : ([c_ccharp], c_void), + 'add_type_reducer' : ([c_ccharp, c_ccharp], c_void), + 'base_offset' : ([c_type, c_type, c_object, c_int], c_ptrdiff_t), # method/function reflection information @@ -279,14 +314,16 @@ class State(object): 'get_num_templated_methods': ([c_scope], c_int), 'get_templated_method_name': ([c_scope, c_index], c_ccharp), + 'is_templated_constructor' : ([c_scope, c_index], c_int), 'exists_method_template' : ([c_scope, c_ccharp], c_int), 'method_is_template' : ([c_scope, c_index], c_int), - 'get_method_template' : ([c_scope, c_ccharp, c_ccharp], c_method), + 'get_method_template' : ([c_scope, c_ccharp, c_ccharp], c_method), 'get_global_operator' : ([c_scope, c_scope, c_scope, c_ccharp], c_index), # method properties 'is_public_method' : ([c_method], c_int), + 'is_protected_method' : ([c_method], c_int), 'is_constructor' : ([c_method], c_int), 'is_destructor' : ([c_method], c_int), 'is_staticmethod' : ([c_method], c_int), @@ -300,11 +337,18 @@ class State(object): # data member properties 'is_publicdata' : ([c_scope, c_int], c_int), + 'is_protecteddata' : ([c_scope, c_int], c_int), 'is_staticdata' : ([c_scope, c_int], c_int), 'is_const_data' : ([c_scope, c_int], c_int), 'is_enum_data' : ([c_scope, c_int], c_int), 'get_dimension_size' : ([c_scope, c_int, c_int], c_int), + # enum properties + 'get_enum' : ([c_scope, c_ccharp], c_enum), + 'get_num_enum_data' : ([c_enum], c_index), + 'get_enum_data_name' : ([c_enum, c_index], c_ccharp), + 'get_enum_data_value' : ([c_enum, c_index], c_llong), + # misc helpers 'strtoll' : ([c_ccharp], c_llong), 'strtoull' : ([c_ccharp], c_ullong), @@ -343,8 +387,10 @@ def load_backend(space): fullname = backend_library+backend_ext state.backend = W_Library(space, space.newtext(fullname), dldflags) except Exception as e: - # TODO: where to find the value '.pypy-41'? Note that this only matters for testing. - state.backend = W_Library(space, space.newtext(backend_library+'.pypy-41'+backend_ext), dldflags) + soabi = space.config.objspace.soabi + if soabi is None: + soabi = '.pypy-%d%d' % PYPY_VERSION[:2] + state.backend = W_Library(space, space.newtext(backend_library+soabi+backend_ext), dldflags) if state.backend: # fix constants @@ -359,7 +405,7 @@ def verify_backend(space): except Exception: if objectmodel.we_are_translated(): raise oefmt(space.w_ImportError, - "missing reflection library %s", backend_library) + "missing backend library %s", backend_library) return False return True @@ -380,8 +426,17 @@ def call_capi(space, name, args): with c_call as ptr: return c_call.ctype.rcall(ptr, args) +def _cdata_to_ptr(space, w_cdata): + w_cdata = space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False) + with w_cdata as ptr: + return rffi.cast(rffi.VOIDP, ptr) # escapes (is okay) + return rffi.cast(rffi.VOIDP, 0) + def _cdata_to_cobject(space, w_cdata): - return rffi.cast(C_OBJECT, space.uint_w(w_cdata)) + ptr = _cdata_to_ptr(space, w_cdata) + return rffi.cast(C_OBJECT, ptr) + +_cdata_to_cenum = _cdata_to_cobject def _cdata_to_size_t(space, w_cdata): return rffi.cast(rffi.SIZE_T, space.uint_w(w_cdata)) @@ -392,18 +447,16 @@ def _cdata_to_ptrdiff_t(space, w_cdata): def _cdata_to_intptr_t(space, w_cdata): return rffi.cast(rffi.INTPTR_T, space.int_w(w_cdata)) -def _cdata_to_ptr(space, w_cdata): # TODO: this is both a hack and dreadfully slow - w_cdata = space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False) - ptr = w_cdata.unsafe_escaping_ptr() - return rffi.cast(rffi.VOIDP, ptr) - def _cdata_to_ccharp(space, w_cdata): - ptr = _cdata_to_ptr(space, w_cdata) # see above ... something better? + ptr = _cdata_to_ptr(space, w_cdata) return rffi.cast(rffi.CCHARP, ptr) # direct interpreter access def c_compile(space, code): return space.int_w(call_capi(space, 'compile', [_ArgS(code)])) +def c_cppyy_to_string(space, cppclass, cppobj): + args = [_ArgC(cppclass), _ArgO(cppobj)] + return charp2str_free(space, call_capi(space, 'cppyy_to_string', args)) # name to opaque C++ scope representation ------------------------------------ def c_resolve_name(space, name): @@ -413,85 +466,91 @@ def c_resolve_enum(space, name): def c_get_scope_opaque(space, name): return rffi.cast(C_SCOPE, space.uint_w(call_capi(space, 'get_scope', [_ArgS(name)]))) def c_actual_class(space, cppclass, cppobj): - args = [_ArgH(cppclass.handle), _ArgH(cppobj)] + args = [_ArgC(cppclass), _ArgO(cppobj)] return rffi.cast(C_TYPE, space.uint_w(call_capi(space, 'actual_class', args))) def c_size_of_klass(space, cppclass): - return _cdata_to_size_t(space, call_capi(space, 'size_of_klass', [_ArgH(cppclass.handle)])) + return _cdata_to_size_t(space, call_capi(space, 'size_of_klass', [_ArgC(cppclass)])) def c_size_of_type(space, name): return _cdata_to_size_t(space, call_capi(space, 'size_of_type', [_ArgS(name)])) +def c_is_builtin(space, name): + return space.bool_w(call_capi(space, 'is_builtin', [_ArgS(name)])) +def c_is_complete(space, name): + return space.bool_w(call_capi(space, 'is_complete', [_ArgS(name)])) + # memory management ---------------------------------------------------------- def c_allocate(space, cppclass): - return _cdata_to_cobject(space, call_capi(space, 'allocate', [_ArgH(cppclass.handle)])) -def c_deallocate(space, cppclass, cppobject): - call_capi(space, 'deallocate', [_ArgH(cppclass.handle), _ArgH(cppobject)]) + return _cdata_to_cobject(space, call_capi(space, 'allocate', [_ArgC(cppclass)])) +def c_deallocate(space, cppclass, cppobj): + call_capi(space, 'deallocate', [_ArgC(cppclass), _ArgO(cppobj)]) def c_construct(space, cppclass): - return _cdata_to_cobject(space, call_capi(space, 'construct', [_ArgH(cppclass.handle)])) -def c_destruct(space, cppclass, cppobject): - call_capi(space, 'destruct', [_ArgH(cppclass.handle), _ArgH(cppobject)]) + return _cdata_to_cobject(space, call_capi(space, 'construct', [_ArgC(cppclass)])) +def c_destruct(space, cppclass, cppobj): + call_capi(space, 'destruct', [_ArgC(cppclass), _ArgO(cppobj)]) # method/function dispatching ------------------------------------------------ -def c_call_v(space, cppmethod, cppobject, nargs, cargs): - args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)] +def c_call_v(space, cppmeth, cppobj, nargs, cargs): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs)] call_capi(space, 'call_v', args) -def c_call_b(space, cppmethod, cppobject, nargs, cargs): - args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)] +def c_call_b(space, cppmeth, cppobj, nargs, cargs): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs)] return rffi.cast(rffi.UCHAR, space.c_uint_w(call_capi(space, 'call_b', args))) -def c_call_c(space, cppmethod, cppobject, nargs, cargs): - args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)] +def c_call_c(space, cppmeth, cppobj, nargs, cargs): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs)] return rffi.cast(rffi.CHAR, space.text_w(call_capi(space, 'call_c', args))[0]) -def c_call_h(space, cppmethod, cppobject, nargs, cargs): - args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)] +def c_call_h(space, cppmeth, cppobj, nargs, cargs): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs)] return rffi.cast(rffi.SHORT, space.int_w(call_capi(space, 'call_h', args))) -def c_call_i(space, cppmethod, cppobject, nargs, cargs): - args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)] +def c_call_i(space, cppmeth, cppobj, nargs, cargs): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs)] return rffi.cast(rffi.INT, space.c_int_w(call_capi(space, 'call_i', args))) -def c_call_l(space, cppmethod, cppobject, nargs, cargs): - args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)] +def c_call_l(space, cppmeth, cppobj, nargs, cargs): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs)] return rffi.cast(rffi.LONG, space.int_w(call_capi(space, 'call_l', args))) -def c_call_ll(space, cppmethod, cppobject, nargs, cargs): - args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)] +def c_call_ll(space, cppmeth, cppobj, nargs, cargs): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs)] return rffi.cast(rffi.LONGLONG, space.r_longlong_w(call_capi(space, 'call_ll', args))) -def c_call_f(space, cppmethod, cppobject, nargs, cargs): - args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)] +def c_call_f(space, cppmeth, cppobj, nargs, cargs): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs)] return rffi.cast(rffi.FLOAT, r_singlefloat(space.float_w(call_capi(space, 'call_f', args)))) -def c_call_d(space, cppmethod, cppobject, nargs, cargs): - args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)] +def c_call_d(space, cppmeth, cppobj, nargs, cargs): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs)] 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)] +def c_call_ld(space, cppmeth, cppobj, nargs, cargs): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs)] #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)] +def c_call_r(space, cppmeth, cppobj, nargs, cargs): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs)] return _cdata_to_ptr(space, call_capi(space, 'call_r', args)) -def c_call_s(space, cppmethod, cppobject, nargs, cargs): +def c_call_s(space, cppmeth, cppobj, nargs, cargs): length = lltype.malloc(rffi.SIZE_TP.TO, 1, flavor='raw') try: w_cstr = call_capi(space, 'call_s', - [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs), + [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs), _ArgP(rffi.cast(rffi.VOIDP, length))]) cstr_len = int(intmask(length[0])) finally: lltype.free(length, flavor='raw') return _cdata_to_ccharp(space, w_cstr), cstr_len - -def c_constructor(space, cppmethod, cppobject, nargs, cargs): - args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs)] +def c_constructor(space, cppmeth, cppobj, nargs, cargs): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs)] return _cdata_to_cobject(space, call_capi(space, 'constructor', args)) -def c_call_o(space, cppmethod, cppobject, nargs, cargs, cppclass): - args = [_ArgH(cppmethod), _ArgH(cppobject), _ArgL(nargs), _ArgP(cargs), _ArgH(cppclass.handle)] +def c_destructor(space, cppclass, cppobj): + call_capi(space, 'constructor', [_ArgC(cppclass), _ArgO(cppobj)]) +def c_call_o(space, cppmeth, cppobj, nargs, cargs, cppclass): + args = [_ArgM(cppmeth), _ArgO(cppobj), _ArgI(nargs), _ArgP(cargs), _ArgC(cppclass)] return _cdata_to_cobject(space, call_capi(space, 'call_o', args)) -def c_function_address(space, cppmethod): +def c_function_address(space, cppmeth): return rffi.cast(C_FUNC_PTR, - _cdata_to_ptr(space, call_capi(space, 'function_address', [_ArgH(cppmethod)]))) + _cdata_to_ptr(space, call_capi(space, 'function_address', [_ArgM(cppmeth)]))) # handling of function argument buffer --------------------------------------- def c_allocate_function_args(space, size): - return _cdata_to_ptr(space, call_capi(space, 'allocate_function_args', [_ArgL(size)])) + return _cdata_to_ptr(space, call_capi(space, 'allocate_function_args', [_ArgI(size)])) def c_deallocate_function_args(space, cargs): call_capi(space, 'deallocate_function_args', [_ArgP(cargs)]) def c_function_arg_sizeof(space): @@ -507,14 +566,18 @@ def c_is_namespace(space, scope): def c_is_template(space, name): return space.bool_w(call_capi(space, 'is_template', [_ArgS(name)])) def c_is_abstract(space, cpptype): - return space.bool_w(call_capi(space, 'is_abstract', [_ArgH(cpptype)])) + return space.bool_w(call_capi(space, 'is_abstract', [_ArgC(cpptype)])) def c_is_enum(space, name): return space.bool_w(call_capi(space, 'is_enum', [_ArgS(name)])) +def c_is_aggregate(space, name): + return space.bool_w(call_capi(space, 'is_aggregate', [_ArgS(name)])) +def c_is_default_constructable(space, name): + return space.bool_w(call_capi(space, 'is_default_constructable', [_ArgS(name)])) -def c_get_all_cpp_names(space, scope): +def c_get_all_cpp_names(space, cppscope): sz = lltype.malloc(rffi.SIZE_TP.TO, 1, flavor='raw', zero=True) try: - args = [_ArgH(scope.handle), _ArgP(rffi.cast(rffi.VOIDP, sz))] + args = [_ArgC(cppscope), _ArgP(rffi.cast(rffi.VOIDP, sz))] rawnames = rffi.cast(rffi.CCHARPP, _cdata_to_ptr(space, call_capi(space, 'get_all_cpp_names', args))) count = int(intmask(sz[0])) @@ -530,29 +593,29 @@ def c_get_all_cpp_names(space, scope): # namespace reflection information def c_get_using_namespaces(space, cppscope): - return space.uint_w(call_capi(space, 'get_using_namespaces', [_ArgH(cppscope)])) + return space.uint_w(call_capi(space, 'get_using_namespaces', [_ArgC(cppscope)])) # type/class reflection information ------------------------------------------ -def c_final_name(space, cpptype): - return charp2str_free(space, call_capi(space, 'final_name', [_ArgH(cpptype)])) -def c_scoped_final_name(space, cpptype): - return charp2str_free(space, call_capi(space, 'scoped_final_name', [_ArgH(cpptype)])) +def c_final_name(space, handle): + return charp2str_free(space, call_capi(space, 'final_name', [_ArgH(handle)])) +def c_scoped_final_name(space, handle): + return charp2str_free(space, call_capi(space, 'scoped_final_name', [_ArgH(handle)])) def c_has_virtual_destructor(space, handle): return space.bool_w(call_capi(space, 'has_virtual_destructor', [_ArgH(handle)])) def c_has_complex_hierarchy(space, handle): return space.bool_w(call_capi(space, 'has_complex_hierarchy', [_ArgH(handle)])) def c_num_bases(space, cppclass): - return space.int_w(call_capi(space, 'num_bases', [_ArgH(cppclass.handle)])) + return space.int_w(call_capi(space, 'num_bases', [_ArgC(cppclass)])) def c_base_name(space, cppclass, base_index): - args = [_ArgH(cppclass.handle), _ArgL(base_index)] + args = [_ArgC(cppclass), _ArgI(base_index)] return charp2str_free(space, call_capi(space, 'base_name', args)) -def c_is_smartptr(space, handle): - return space.bool_w(call_capi(space, 'is_smartptr', [_ArgH(handle)])) def c_is_subtype(space, derived, base): jit.promote(base) if derived == base: return bool(1) - return space.bool_w(call_capi(space, 'is_subtype', [_ArgH(derived.handle), _ArgH(base.handle)])) + return space.bool_w(call_capi(space, 'is_subtype', [_ArgC(derived), _ArgC(base)])) +def c_is_smartptr(space, handle): + return space.bool_w(call_capi(space, 'is_smartptr', [_ArgH(handle)])) def c_smartptr_info(space, name): out_raw = lltype.malloc(rffi.ULONGP.TO, 1, flavor='raw', zero=True) out_deref = lltype.malloc(rffi.ULONGP.TO, 1, flavor='raw', zero=True) @@ -569,8 +632,11 @@ def c_smartptr_info(space, name): def c_add_smartptr_type(space, name): return space.bool_w(call_capi(space, 'add_smartptr_type', [_ArgS(name)])) +def c_add_type_reducer(space, reducable, reduced): + return space.bool_w(call_capi(space, 'add_type_reducer', [_ArgS(reducable), _ArgS(reduced)])) + def _c_base_offset(space, derived_h, base_h, address, direction): - args = [_ArgH(derived_h), _ArgH(base_h), _ArgH(address), _ArgL(direction)] + args = [_ArgH(derived_h), _ArgH(base_h), _ArgO(address), _ArgI(direction)] return _cdata_to_ptrdiff_t(space, call_capi(space, 'base_offset', args)) def c_base_offset(space, derived, base, address, direction): if derived == base: @@ -581,10 +647,9 @@ def c_base_offset1(space, derived_h, base, address, direction): # method/function reflection information ------------------------------------- def c_num_methods(space, cppscope): - args = [_ArgH(cppscope.handle)] - return space.int_w(call_capi(space, 'num_methods', args)) + return space.int_w(call_capi(space, 'num_methods', [_ArgC(cppscope)])) def c_method_indices_from_name(space, cppscope, name): - args = [_ArgH(cppscope.handle), _ArgS(name)] + args = [_ArgC(cppscope), _ArgS(name)] indices = rffi.cast(C_INDEX_ARRAY, _cdata_to_ptr(space, call_capi(space, 'method_indices_from_name', args))) if not indices: @@ -592,7 +657,7 @@ def c_method_indices_from_name(space, cppscope, name): py_indices = [] i = 0 index = indices[i] - while index != -1: + while index != rffi.cast(C_INDEX, -1): i += 1 py_indices.append(index) index = indices[i] @@ -600,107 +665,128 @@ def c_method_indices_from_name(space, cppscope, name): return py_indices def c_get_method(space, cppscope, index): - args = [_ArgH(cppscope.handle), _ArgU(index)] - return rffi.cast(C_METHOD, space.uint_w(call_capi(space, 'get_method', args))) + args = [_ArgC(cppscope), _ArgU(index)] + return _cdata_to_intptr_t(space, call_capi(space, 'get_method', args)) def c_method_name(space, cppmeth): - return charp2str_free(space, call_capi(space, 'method_name', [_ArgH(cppmeth)])) + return charp2str_free(space, call_capi(space, 'method_name', [_ArgM(cppmeth)])) def c_method_full_name(space, cppmeth): - return charp2str_free(space, call_capi(space, 'method_full_name', [_ArgH(cppmeth)])) + return charp2str_free(space, call_capi(space, 'method_full_name', [_ArgM(cppmeth)])) def c_method_mangled_name(space, cppmeth): - return charp2str_free(space, call_capi(space, 'method_mangled_name', [_ArgH(cppmeth)])) + return charp2str_free(space, call_capi(space, 'method_mangled_name', [_ArgM(cppmeth)])) def c_method_result_type(space, cppmeth): - return charp2str_free(space, call_capi(space, 'method_result_type', [_ArgH(cppmeth)])) + return charp2str_free(space, call_capi(space, 'method_result_type', [_ArgM(cppmeth)])) def c_method_num_args(space, cppmeth): - return space.int_w(call_capi(space, 'method_num_args', [_ArgH(cppmeth)])) + return space.int_w(call_capi(space, 'method_num_args', [_ArgM(cppmeth)])) def c_method_req_args(space, cppmeth): - return space.int_w(call_capi(space, 'method_req_args', [_ArgH(cppmeth)])) + return space.int_w(call_capi(space, 'method_req_args', [_ArgM(cppmeth)])) def c_method_arg_name(space, cppmeth, arg_index): - args = [_ArgH(cppmeth), _ArgL(arg_index)] + args = [_ArgM(cppmeth), _ArgI(arg_index)] return charp2str_free(space, call_capi(space, 'method_arg_name', args)) def c_method_arg_type(space, cppmeth, arg_index): - args = [_ArgH(cppmeth), _ArgL(arg_index)] + args = [_ArgM(cppmeth), _ArgI(arg_index)] return charp2str_free(space, call_capi(space, 'method_arg_type', args)) def c_method_arg_default(space, cppmeth, arg_index): - args = [_ArgH(cppmeth), _ArgL(arg_index)] + args = [_ArgM(cppmeth), _ArgI(arg_index)] return charp2str_free(space, call_capi(space, 'method_arg_default', args)) def c_method_signature(space, cppmeth, show_formalargs=True): - args = [_ArgH(cppmeth), _ArgL(show_formalargs)] + args = [_ArgM(cppmeth), _ArgI(show_formalargs)] return charp2str_free(space, call_capi(space, 'method_signature', args)) def c_method_signature_max(space, cppmeth, show_formalargs, maxargs): - args = [_ArgH(cppmeth), _ArgL(show_formalargs), _ArgL(maxargs)] + args = [_ArgM(cppmeth), _ArgI(show_formalargs), _ArgI(maxargs)] return charp2str_free(space, call_capi(space, 'method_signature_max', args)) def c_method_prototype(space, cppscope, cppmeth, show_formalargs=True): - args = [_ArgH(cppscope.handle), _ArgH(cppmeth), _ArgL(show_formalargs)] + args = [_ArgC(cppscope), _ArgM(cppmeth), _ArgI(show_formalargs)] return charp2str_free(space, call_capi(space, 'method_prototype', args)) def c_is_const_method(space, cppmeth): - return space.bool_w(call_capi(space, 'is_const_method', [_ArgH(cppmeth)])) + return space.bool_w(call_capi(space, 'is_const_method', [_ArgM(cppmeth)])) def c_get_num_templated_methods(space, cppscope): - return space.int_w(call_capi(space, 'get_num_templated_methods', [_ArgH(cppscope.handle)])) + return space.int_w(call_capi(space, 'get_num_templated_methods', [_ArgC(cppscope)])) def c_get_templated_method_name(space, cppscope, index): - args = [_ArgH(cppscope.handle), _ArgU(index)] + args = [_ArgC(cppscope), _ArgU(index)] return charp2str_free(space, call_capi(space, 'get_templated_method_name', args)) +def c_is_templated_constructor(space, cppscope, index): + args = [_ArgC(cppscope), _ArgU(index)] + return space.bool_w(space, call_capi(space, 'is_templated_constructor', args)) def c_exists_method_template(space, cppscope, name): - args = [_ArgH(cppscope.handle), _ArgS(name)] + args = [_ArgC(cppscope), _ArgS(name)] return space.bool_w(call_capi(space, 'exists_method_template', args)) def c_method_is_template(space, cppscope, index): - args = [_ArgH(cppscope.handle), _ArgU(index)] + args = [_ArgC(cppscope), _ArgU(index)] return space.bool_w(call_capi(space, 'method_is_template', args)) def c_get_method_template(space, cppscope, name, proto): - args = [_ArgH(cppscope.handle), _ArgS(name), _ArgS(proto)] + args = [_ArgC(cppscope), _ArgS(name), _ArgS(proto)] return rffi.cast(C_METHOD, space.int_w(call_capi(space, 'get_method_template', args))) def c_get_global_operator(space, nss, lc, rc, op): if nss is not None: - args = [_ArgH(nss.handle), _ArgH(lc.handle), _ArgH(rc.handle), _ArgS(op)] - return rffi.cast(WLAVC_INDEX, space.uint_w(call_capi(space, 'get_global_operator', args))) - return rffi.cast(WLAVC_INDEX, -1) + args = [_ArgC(nss), _ArgC(lc), _ArgC(rc), _ArgS(op)] + return rffi.cast(C_INDEX, space.uint_w(call_capi(space, 'get_global_operator', args))) + return rffi.cast(C_INDEX, -1) # method properties ---------------------------------------------------------- def c_is_public_method(space, cppmeth): - return space.bool_w(call_capi(space, 'is_public_method', [_ArgH(cppmeth)])) + return space.bool_w(call_capi(space, 'is_public_method', [_ArgM(cppmeth)])) +def c_is_protected_method(space, cppmeth): + return space.bool_w(call_capi(space, 'is_protected_method', [_ArgM(cppmeth)])) def c_is_constructor(space, cppmeth): - return space.bool_w(call_capi(space, 'is_constructor', [_ArgH(cppmeth)])) + return space.bool_w(call_capi(space, 'is_constructor', [_ArgM(cppmeth)])) def c_is_destructor(space, cppmeth): - return space.bool_w(call_capi(space, 'is_destructor', [_ArgH(cppmeth)])) + return space.bool_w(call_capi(space, 'is_destructor', [_ArgM(cppmeth)])) def c_is_staticmethod(space, cppmeth): - return space.bool_w(call_capi(space, 'is_staticmethod', [_ArgH(cppmeth)])) + return space.bool_w(call_capi(space, 'is_staticmethod', [_ArgM(cppmeth)])) # data member reflection information ----------------------------------------- def c_num_datamembers(space, cppscope): - return space.int_w(call_capi(space, 'num_datamembers', [_ArgH(cppscope.handle)])) + return space.int_w(call_capi(space, 'num_datamembers', [_ArgC(cppscope)])) def c_datamember_name(space, cppscope, datamember_index): - args = [_ArgH(cppscope.handle), _ArgL(datamember_index)] + args = [_ArgC(cppscope), _ArgI(datamember_index)] return charp2str_free(space, call_capi(space, 'datamember_name', args)) def c_datamember_type(space, cppscope, datamember_index): - args = [_ArgH(cppscope.handle), _ArgL(datamember_index)] - return charp2str_free(space, call_capi(space, 'datamember_type', args)) + args = [_ArgC(cppscope), _ArgI(datamember_index)] + return charp2str_free(space, call_capi(space, 'datamember_type', args)) def c_datamember_offset(space, cppscope, datamember_index): - args = [_ArgH(cppscope.handle), _ArgL(datamember_index)] + args = [_ArgC(cppscope), _ArgI(datamember_index)] return _cdata_to_intptr_t(space, call_capi(space, 'datamember_offset', args)) def c_datamember_index(space, cppscope, name): - args = [_ArgH(cppscope.handle), _ArgS(name)] + args = [_ArgC(cppscope), _ArgS(name)] return space.int_w(call_capi(space, 'datamember_index', args)) # data member properties ----------------------------------------------------- def c_is_publicdata(space, cppscope, datamember_index): - args = [_ArgH(cppscope.handle), _ArgL(datamember_index)] + args = [_ArgC(cppscope), _ArgU(datamember_index)] return space.bool_w(call_capi(space, 'is_publicdata', args)) +def c_is_protecteddata(space, cppscope, datamember_index): + args = [_ArgC(cppscope), _ArgU(datamember_index)] + return space.bool_w(call_capi(space, 'is_protecteddata', args)) def c_is_staticdata(space, cppscope, datamember_index): - args = [_ArgH(cppscope.handle), _ArgL(datamember_index)] + args = [_ArgC(cppscope), _ArgU(datamember_index)] return space.bool_w(call_capi(space, 'is_staticdata', args)) def c_is_const_data(space, cppscope, datamember_index): - args = [_ArgH(cppscope.handle), _ArgL(datamember_index)] + args = [_ArgC(cppscope), _ArgU(datamember_index)] return space.bool_w(call_capi(space, 'is_const_data', args)) def c_is_enum_data(space, cppscope, datamember_index): - args = [_ArgH(cppscope.handle), _ArgL(datamember_index)] + args = [_ArgC(cppscope), _ArgU(datamember_index)] return space.bool_w(call_capi(space, 'is_enum_data', args)) def c_get_dimension_size(space, cppscope, datamember_index, dim_idx): - args = [_ArgH(cppscope.handle), _ArgL(datamember_index), _ArgL(dim_idx)] + args = [_ArgC(cppscope), _ArgU(datamember_index), _ArgI(dim_idx)] return space.int_w(call_capi(space, 'get_dimension_size', args)) +# enum properties ------------------------------------------------------------ +def c_get_enum(space, cppscope, name): + args = [_ArgC(cppscope), _ArgS(name)] + return _cdata_to_cenum(call_capi(space, 'get_enum', args)) +def c_num_enum_data(space, cppenum): + return space.int_w(call_capi(space, 'num_enum_data', [_ArgE(cppenum)])) +def c_get_enum_data_name(space, cppenum, idata): + args = [_ArgE(cppenum), _ArgU(idata)] + return charp2str_free(space, call_capi(space, 'get_enum_data_name', args)) +def c_get_enum_data_value(space, cppenum, idata): + args = [_ArgE(cppenum), _ArgU(idata)] + return rffi.cast(C_ENUM, call_capi(space, 'get_enum_data_value', args)) + # misc helpers --------------------------------------------------------------- def c_strtoll(space, svalue): return space.r_longlong_w(call_capi(space, 'strtoll', [_ArgS(svalue)])) @@ -717,18 +803,18 @@ def charp2str_free(space, cdata): def c_charp2stdstring(space, svalue, sz): return _cdata_to_cobject(space, call_capi(space, 'charp2stdstring', - [_ArgS(svalue), _ArgH(rffi.cast(rffi.ULONG, sz))])) + [_ArgS(svalue), _ArgU(rffi.cast(C_INDEX, sz))])) def c_stdstring2charp(space, cppstr): - sz = lltype.malloc(rffi.SIZE_TP.TO, 1, flavor='raw') + szp = lltype.malloc(rffi.SIZE_TP.TO, 1, flavor='raw') try: w_cstr = call_capi(space, 'stdstring2charp', - [_ArgH(cppstr), _ArgP(rffi.cast(rffi.VOIDP, sz))]) - cstr_len = int(intmask(sz[0])) + [_ArgO(cppstr), _ArgP(rffi.cast(rffi.VOIDP, szp))]) + cstr_len = int(intmask(szp[0])) finally: - lltype.free(sz, flavor='raw') + lltype.free(szp, flavor='raw') return rffi.charpsize2str(_cdata_to_ccharp(space, w_cstr), cstr_len) -def c_stdstring2stdstring(space, cppobject): - return _cdata_to_cobject(space, call_capi(space, 'stdstring2stdstring', [_ArgH(cppobject)])) +def c_stdstring2stdstring(space, cppobj): + return _cdata_to_cobject(space, call_capi(space, 'stdstring2stdstring', [_ArgO(cppobj)])) def c_longdouble2double(space, addr): return space.float_w(call_capi(space, 'longdouble2double', [_ArgP(addr)])) @@ -736,9 +822,9 @@ 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)]) + return call_capi(space, 'vectorbool_getitem', [_ArgO(vbool), _ArgI(idx)]) def c_vectorbool_setitem(space, vbool, idx, value): - call_capi(space, 'vectorbool_setitem', [_ArgH(vbool), _ArgL(idx), _ArgL(value)]) + call_capi(space, 'vectorbool_setitem', [_ArgO(vbool), _ArgI(idx), _ArgI(value)]) # TODO: factor these out ... diff --git a/pypy/module/_cppyy/converter.py b/pypy/module/_cppyy/converter.py index 4a9b6ffd57..897715288a 100644 --- a/pypy/module/_cppyy/converter.py +++ b/pypy/module/_cppyy/converter.py @@ -144,10 +144,10 @@ class ArrayTypeConverterMixin(object): def from_memory(self, space, w_obj, offset): # read access, so no copy needed - address_value = self._get_raw_address(space, w_obj, offset) - address = rffi.cast(rffi.ULONG, address_value) + address = self._get_raw_address(space, w_obj, offset) + ipv = rffi.cast(rffi.UINTPTR_T, address) return lowlevelviews.W_LowLevelView( - space, letter2tp(space, self.typecode), self.size, address) + space, letter2tp(space, self.typecode), self.size, ipv) def to_memory(self, space, w_obj, w_value, offset): # copy the full array (uses byte copy for now) @@ -157,7 +157,6 @@ class ArrayTypeConverterMixin(object): for i in range(min(self.size*self.typesize, buf.getlength())): address[i] = buf.getitem(i) - class PtrTypeConverterMixin(object): _mixin_ = True _immutable_fields_ = ['size'] @@ -186,10 +185,10 @@ class PtrTypeConverterMixin(object): def from_memory(self, space, w_obj, offset): # read access, so no copy needed - address_value = self._get_raw_address(space, w_obj, offset) - address = rffi.cast(rffi.ULONGP, address_value) + address = self._get_raw_address(space, w_obj, offset) + ipv = rffi.cast(rffi.UINTPTR_T, rffi.cast(rffi.VOIDPP, address)[0]) return lowlevelviews.W_LowLevelView( - space, letter2tp(space, self.typecode), self.size, address[0]) + space, letter2tp(space, self.typecode), self.size, ipv) def to_memory(self, space, w_obj, w_value, offset): # copy only the pointer value @@ -202,6 +201,13 @@ class PtrTypeConverterMixin(object): raise oefmt(space.w_TypeError, "raw buffer interface not supported") +class ArrayPtrTypeConverterMixin(PtrTypeConverterMixin): + _mixin_ = True + + def cffi_type(self, space): + state = space.fromcache(ffitypes.State) + return state.c_voidpp + class NumericTypeConverterMixin(object): _mixin_ = True @@ -300,9 +306,12 @@ class BoolConverter(ffitypes.typeid(bool), TypeConverter): else: address[0] = '\x00' -class CharConverter(ffitypes.typeid(rffi.CHAR), TypeConverter): + +class CharTypeConverterMixin(object): + _mixin_ = True + def convert_argument(self, space, w_obj, address): - x = rffi.cast(rffi.CCHARP, address) + x = rffi.cast(self.c_ptrtype, address) x[0] = self._unwrap_object(space, w_obj) ba = rffi.cast(rffi.CCHARP, address) ba[capi.c_function_arg_typeoffset(space)] = 'b' @@ -312,17 +321,14 @@ class CharConverter(ffitypes.typeid(rffi.CHAR), TypeConverter): x[0] = self._unwrap_object(space, w_obj) def from_memory(self, space, w_obj, offset): - address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset)) - return space.newbytes(address[0]) + address = rffi.cast(self.c_ptrtype, self._get_raw_address(space, w_obj, offset)) + return self._wrap_object(space, address[0]) def to_memory(self, space, w_obj, w_value, offset): - address = rffi.cast(rffi.CCHARP, self._get_raw_address(space, w_obj, offset)) + address = rffi.cast(self.c_ptrtype, 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', 'valid_default'] @@ -413,9 +419,9 @@ class ConstLongDoubleRefConverter(ConstRefNumericTypeConverterMixin, LongDoubleC class CStringConverter(TypeConverter): def convert_argument(self, space, w_obj, address): - x = rffi.cast(rffi.LONGP, address) + x = rffi.cast(rffi.VOIDPP, address) arg = space.text_w(w_obj) - x[0] = rffi.cast(rffi.LONG, rffi.str2charp(arg)) + x[0] = rffi.cast(rffi.VOIDP, rffi.str2charp(arg)) ba = rffi.cast(rffi.CCHARP, address) ba[capi.c_function_arg_typeoffset(space)] = 'p' @@ -470,12 +476,12 @@ class VoidPtrConverter(TypeConverter): # 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.ULONGP, address)[0] - if ptrval == rffi.cast(rffi.ULONG, 0): + ipv = rffi.cast(rffi.UINTPTR_T, rffi.cast(rffi.VOIDPP, address)[0]) + if ipv == rffi.cast(rffi.UINTPTR_T, 0): from pypy.module._cppyy import interp_cppyy return interp_cppyy.get_nullptr(space) shape = letter2tp(space, 'P') - return lowlevelviews.W_LowLevelView(space, shape, sys.maxint/shape.size, ptrval) + return lowlevelviews.W_LowLevelView(space, shape, sys.maxint/shape.size, ipv) def to_memory(self, space, w_obj, w_value, offset): address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset)) @@ -584,7 +590,10 @@ class InstanceConverter(InstanceRefConverter): return interp_cppyy.wrap_cppinstance(space, address, self.clsdecl, do_cast=False) def to_memory(self, space, w_obj, w_value, offset): - self._is_abstract(space) + address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset)) + assign = self.clsdecl.get_overload("__assign__") + from pypy.module._cppyy import interp_cppyy + assign.call_impl(address, [w_value]) class InstancePtrConverter(InstanceRefConverter): typecode = 'o' @@ -601,7 +610,28 @@ class InstancePtrConverter(InstanceRefConverter): def from_memory(self, space, w_obj, offset): address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset)) from pypy.module._cppyy import interp_cppyy - return interp_cppyy.wrap_cppinstance(space, address, self.clsdecl, do_cast=False) + return interp_cppyy.wrap_cppinstance( + space, address, self.clsdecl, do_cast=False, is_ref=True) + + def to_memory(self, space, w_obj, w_value, offset): + from pypy.module._cppyy.interp_cppyy import W_CPPInstance + cppinstance = space.interp_w(W_CPPInstance, w_value, can_be_None=True) + if cppinstance: + # get the object address from value, correct for hierarchy offset + rawobject = cppinstance.get_rawobject() + base_offset = capi.c_base_offset(space, cppinstance.clsdecl, self.clsdecl, rawobject, 1) + rawptr = capi.direct_ptradd(rawobject, base_offset) + + # get the data member address and write the pointer in + address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset)) + address[0] = rffi.cast(rffi.VOIDP, rawptr) + + # register the value object for potential recycling + from pypy.module._cppyy.interp_cppyy import memory_regulator + memory_regulator.register(cppinstance) + else: + raise oefmt(space.w_TypeError, + "cannot pass %T instance as %s", w_value, self.clsdecl.name) class InstancePtrPtrConverter(InstancePtrConverter): typecode = 'o' @@ -625,29 +655,10 @@ class InstancePtrPtrConverter(InstancePtrConverter): raise FastCallNotPossible def from_memory(self, space, w_obj, offset): - address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset)) - from pypy.module._cppyy import interp_cppyy - return interp_cppyy.wrap_cppinstance( - space, address, self.clsdecl, do_cast=False, is_ref=True) + self._is_abstract(space) def to_memory(self, space, w_obj, w_value, offset): - # the actual data member is of object* type, but we receive a pointer to that - # data member in order to modify its value, so by convention, the internal type - # used is object** - address = rffi.cast(rffi.VOIDPP, self._get_raw_address(space, w_obj, offset)) - from pypy.module._cppyy.interp_cppyy import W_CPPInstance - cppinstance = space.interp_w(W_CPPInstance, w_value, can_be_None=True) - if cppinstance: - rawobject = cppinstance.get_rawobject() - offset = capi.c_base_offset(space, cppinstance.clsdecl, self.clsdecl, rawobject, 1) - obj_address = capi.direct_ptradd(rawobject, offset) - address[0] = rffi.cast(rffi.VOIDP, obj_address); - # register the value for potential recycling - from pypy.module._cppyy.interp_cppyy import memory_regulator - memory_regulator.register(cppinstance) - else: - raise oefmt(space.w_TypeError, - "cannot pass %T instance as %s", w_value, self.clsdecl.name) + self._is_abstract(space) def finalize_call(self, space, w_obj): if self.ref_buffer: @@ -678,7 +689,7 @@ class InstanceArrayConverter(InstancePtrConverter): self._is_abstract(space) -class StdStringConverter(InstanceConverter): +class STLStringConverter(InstanceConverter): def __init__(self, space, extra): from pypy.module._cppyy import interp_cppyy cppclass = interp_cppyy.scope_byname(space, capi.std_string_name) @@ -689,22 +700,12 @@ class StdStringConverter(InstanceConverter): if isinstance(w_obj, W_CPPInstance): arg = InstanceConverter._unwrap_object(self, space, w_obj) return capi.c_stdstring2stdstring(space, arg) - else: - return capi.c_charp2stdstring(space, space.text_w(w_obj), space.len_w(w_obj)) - - def to_memory(self, space, w_obj, w_value, offset): - try: - address = rffi.cast(capi.C_OBJECT, self._get_raw_address(space, w_obj, offset)) - assign = self.clsdecl.get_overload("__assign__") - from pypy.module._cppyy import interp_cppyy - assign.call_impl(address, [w_value]) - except Exception: - InstanceConverter.to_memory(self, space, w_obj, w_value, offset) + return capi.c_charp2stdstring(space, space.text_w(w_obj), space.len_w(w_obj)) def free_argument(self, space, arg): capi.c_destruct(space, self.clsdecl, rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, arg)[0])) -class StdStringMoveConverter(StdStringConverter): +class STLStringMoveConverter(STLStringConverter): def _unwrap_object(self, space, w_obj): # moving is same as by-ref, but have to check that move is allowed moveit_reason = 3 @@ -721,7 +722,7 @@ class StdStringMoveConverter(StdStringConverter): if moveit_reason: try: - return StdStringConverter._unwrap_object(self, space, w_obj) + return STLStringConverter._unwrap_object(self, space, w_obj) except Exception: if moveit_reason == 1: # TODO: if the method fails on some other converter, then the next @@ -732,7 +733,7 @@ class StdStringMoveConverter(StdStringConverter): raise oefmt(space.w_ValueError, "object is not an rvalue") -class StdStringRefConverter(InstancePtrConverter): +class STLStringRefConverter(InstancePtrConverter): _immutable_fields_ = ['cppclass', 'typecode'] typecode = 'V' @@ -887,9 +888,14 @@ def get_converter(space, _name, default): # 3a) smart pointers # 4) void* or void converter (which fails on use) - name = capi.c_resolve_name(space, _name) + # original, exact match + try: + return _converters[_name](space, default) + except KeyError: + pass - # full, exact match + # resolved, exact match + name = capi.c_resolve_name(space, _name) try: return _converters[name](space, default) except KeyError: @@ -960,16 +966,17 @@ def get_converter(space, _name, default): return InstanceArrayConverter(space, clsdecl, array_size, dims) elif cpd == "": return InstanceConverter(space, clsdecl) - elif "(anonymous)" in name: + + if "(anonymous)" in name: # special case: enum w/o a type name - return _converters["internal_enum_type_t"](space, default) + return _converters["internal_enum_type_t"+cpd](space, default) elif "(*)" in name or "::*)" in name: # function pointer pos = name.find("*)") if pos > 0: return FunctionPointerConverter(space, name[pos+2:]) - # void* or void converter (which fails on use) + # void*|**|*& or void converter (which fails on use) if 0 <= cpd.find('*'): return VoidPtrConverter(space, default) # "user knows best" @@ -979,8 +986,6 @@ def get_converter(space, _name, default): _converters["bool"] = BoolConverter -_converters["char"] = CharConverter -_converters["unsigned char"] = UCharConverter _converters["float"] = FloatConverter _converters["const float&"] = ConstFloatRefConverter _converters["double"] = DoubleConverter @@ -992,11 +997,11 @@ _converters["void*"] = VoidPtrConverter _converters["void**"] = VoidPtrPtrConverter _converters["void*&"] = VoidPtrRefConverter -# special cases (note: 'string' aliases added below) -_converters["std::string"] = StdStringConverter -_converters["const std::basic_string<char>&"] = StdStringConverter # TODO: shouldn't copy -_converters["std::basic_string<char>&"] = StdStringRefConverter -_converters["std::basic_string<char>&&"] = StdStringMoveConverter +# special cases (note: 'std::string' aliases added below) +_converters["std::basic_string<char>"] = STLStringConverter +_converters["const std::basic_string<char>&"] = STLStringConverter # TODO: shouldn't copy +_converters["std::basic_string<char>&"] = STLStringRefConverter +_converters["std::basic_string<char>&&"] = STLStringMoveConverter _converters["PyObject*"] = PyObjectConverter @@ -1005,71 +1010,57 @@ _converters["#define"] = MacroConverter # add basic (builtin) converters def _build_basic_converters(): "NOT_RPYTHON" - # signed types (use strtoll in setting of default in __init__) - type_info = ( - (rffi.SHORT, ("short", "short int"), 'h'), - (rffi.INT, ("int", "internal_enum_type_t"), 'i'), - ) - - # constref converters exist only b/c the stubs take constref by value, whereas - # libffi takes them by pointer (hence it needs the fast-path in testing); note - # that this is list is not complete, as some classes are specialized - - for c_type, names, c_tc in type_info: - class BasicConverter(ffitypes.typeid(c_type), IntTypeConverterMixin, TypeConverter): + # basic char types + type_info = { + (rffi.CHAR, "char"), + (rffi.SIGNEDCHAR, "signed char"), + (rffi.UCHAR, "unsigned char"), + (lltype.UniChar, "wchar_t"), + (ffitypes.CHAR16_T, "char16_t"), + (ffitypes.CHAR32_T, "char32_t"), + } + + for c_type, name in type_info: + class BasicConverter(ffitypes.typeid(c_type), CharTypeConverterMixin, TypeConverter): _immutable_ = True - typecode = c_tc def __init__(self, space, default): self.valid_default = False try: - self.default = rffi.cast(self.c_type, capi.c_strtoll(space, default)) + 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: - _converters[name] = BasicConverter - _converters["const "+name+"&"] = ConstRefConverter + _converters[name] = BasicConverter + _converters["const "+name+"&"] = ConstRefConverter + # signed types use strtoll in setting of default in __init__, unsigned uses strtoull type_info = ( - (rffi.LONG, ("long", "long int"), 'l'), - (rffi.LONGLONG, ("long long", "long long int", "Long64_t"), 'q'), + (ffitypes.INT8_T, ("int8_t",), 'b', capi.c_strtoll), + (ffitypes.UINT8_T, ("uint8_t", "std::byte", "byte"), 'B', capi.c_strtoull), + (rffi.SHORT, ("short", "short int"), 'h', capi.c_strtoll), + (rffi.USHORT, ("unsigned short", "unsigned short int"), 'H', capi.c_strtoull), + (rffi.INT, ("int", "internal_enum_type_t"), 'i', capi.c_strtoll), + (rffi.UINT, ("unsigned", "unsigned int"), 'I', capi.c_strtoull), + (rffi.LONG, ("long", "long int"), 'l', capi.c_strtoll), + (rffi.ULONG, ("unsigned long", "unsigned long int"), 'L', capi.c_strtoull), + (rffi.LONGLONG, ("long long", "long long int", "Long64_t"), 'q', capi.c_strtoll), + (rffi.ULONGLONG, ("unsigned long long", "unsigned long long int", "ULong64_t"), 'Q', capi.c_strtoull), ) - for c_type, names, c_tc in type_info: - class BasicConverter(ffitypes.typeid(c_type), IntTypeConverterMixin, TypeConverter): - _immutable_ = True - typecode = c_tc - def __init__(self, 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: - _converters[name] = BasicConverter - _converters["const "+name+"&"] = ConstRefConverter - - # unsigned integer types (use strtoull in setting of default in __init__) - type_info = ( - (rffi.USHORT, ("unsigned short", "unsigned short int"), 'H'), - (rffi.UINT, ("unsigned", "unsigned int"), 'I'), - (rffi.ULONG, ("unsigned long", "unsigned long int"), 'L'), - (rffi.ULONGLONG, ("unsigned long long", "unsigned long long int", "ULong64_t"), 'Q'), - ) + # constref converters exist only b/c the stubs take constref by value, whereas + # libffi takes them by pointer (hence it needs the fast-path in testing); note + # that this is list is not complete, as some classes are specialized - for c_type, names, c_tc in type_info: + for c_type, names, c_tc, dfc in type_info: class BasicConverter(ffitypes.typeid(c_type), IntTypeConverterMixin, TypeConverter): _immutable_ = True typecode = c_tc def __init__(self, space, default): self.valid_default = False try: - self.default = rffi.cast(self.c_type, capi.c_strtoull(space, default)) + self.default = rffi.cast(self.c_type, dfc(space, default)) self.valid_default = True except Exception: self.default = rffi.cast(self.c_type, 0) @@ -1085,8 +1076,9 @@ _build_basic_converters() def _build_array_converters(): "NOT_RPYTHON" array_info = ( - ('b', rffi.sizeof(rffi.UCHAR), ("bool",)), # is debatable, but works ... - ('B', rffi.sizeof(rffi.UCHAR), ("unsigned char",)), + ('b', rffi.sizeof(rffi.SIGNEDCHAR), ("bool",)), # is debatable, but works ... + ('b', rffi.sizeof(rffi.SIGNEDCHAR), ("signed char",)), + ('B', rffi.sizeof(rffi.UCHAR), ("unsigned char", "std::byte", "byte")), ('h', rffi.sizeof(rffi.SHORT), ("short int", "short")), ('H', rffi.sizeof(rffi.USHORT), ("unsigned short int", "unsigned short")), ('i', rffi.sizeof(rffi.INT), ("int",)), @@ -1109,9 +1101,14 @@ def _build_array_converters(): _immutable_fields_ = ['typecode', 'typesize'] typecode = tcode typesize = tsize + class ArrayPtrConverter(ArrayPtrTypeConverterMixin, TypeConverter): + _immutable_fields_ = ['typecode', 'typesize'] + typecode = tcode + typesize = tsize for name in names: _a_converters[name+'[]'] = ArrayConverter _a_converters[name+'*'] = PtrConverter + _a_converters[name+'**'] = ArrayPtrConverter # special case, const char* w/ size and w/o '\0' _a_converters["const char[]"] = CStringConverterWithSize @@ -1123,14 +1120,14 @@ _build_array_converters() def _add_aliased_converters(): "NOT_RPYTHON" aliases = ( - ("char", "signed char"), # TODO: check ("const char*", "char*"), - ("std::string", "string"), - ("std::string", "std::basic_string<char>"), - ("const std::basic_string<char>&", "const string&"), - ("std::basic_string<char>&", "string&"), - ("std::basic_string<char>&&", "string&&"), + ("std::basic_string<char>", "std::string"), + ("const std::basic_string<char>&", "const std::string&"), + ("std::basic_string<char>&", "std::string&"), + ("std::basic_string<char>&&", "std::string&&"), + + ("const internal_enum_type_t&", "internal_enum_type_t&"), ("PyObject*", "_object*"), ) diff --git a/pypy/module/_cppyy/executor.py b/pypy/module/_cppyy/executor.py index 73de224170..2f9b21dfb3 100644 --- a/pypy/module/_cppyy/executor.py +++ b/pypy/module/_cppyy/executor.py @@ -1,8 +1,12 @@ import sys from pypy.interpreter.error import oefmt +from pypy.interpreter.argument import Arguments +from pypy.objspace.std.unicodeobject import W_UnicodeObject + from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib import jit_libffi + from pypy.module._rawffi.interp_rawffi import letter2tp from pypy.module._cppyy import helper, capi, ffitypes, lowlevelviews @@ -34,7 +38,7 @@ class Executor(object): raise oefmt(space.w_TypeError, "return type not available or supported") - def execute_libffi(self, space, cif_descr, funcaddr, buffer): + def execute_libffi(self, space, cif_descr, funcaddr, buf): from pypy.module._cppyy.interp_cppyy import FastCallNotPossible raise FastCallNotPossible @@ -50,13 +54,13 @@ class PtrTypeExecutor(Executor): def execute(self, space, cppmethod, cppthis, num_args, args): if hasattr(space, "fake"): raise NotImplementedError - lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args) - ptrval = rffi.cast(rffi.ULONG, lresult) - if ptrval == rffi.cast(rffi.ULONG, 0): + address = capi.c_call_r(space, cppmethod, cppthis, num_args, args) + ipv = rffi.cast(rffi.UINTPTR_T, address) + if ipv == rffi.cast(rffi.UINTPTR_T, 0): from pypy.module._cppyy import interp_cppyy return interp_cppyy.get_nullptr(space) shape = letter2tp(space, self.typecode) - return lowlevelviews.W_LowLevelView(space, shape, sys.maxint/shape.size, ptrval) + return lowlevelviews.W_LowLevelView(space, shape, sys.maxint/shape.size, ipv) class VoidExecutor(Executor): @@ -68,8 +72,8 @@ class VoidExecutor(Executor): capi.c_call_v(space, cppmethod, cppthis, num_args, args) return space.w_None - def execute_libffi(self, space, cif_descr, funcaddr, buffer): - jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer) + def execute_libffi(self, space, cif_descr, funcaddr, buf): + jit_libffi.jit_ffi_call(cif_descr, funcaddr, buf) return space.w_None @@ -80,9 +84,9 @@ class NumericExecutorMixin(object): result = self.c_stubcall(space, cppmethod, cppthis, num_args, args) return self._wrap_object(space, rffi.cast(self.c_type, 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) + def execute_libffi(self, space, cif_descr, funcaddr, buf): + jit_libffi.jit_ffi_call(cif_descr, funcaddr, buf) + result = rffi.ptradd(buf, cif_descr.exchange_result) return self._wrap_object(space, rffi.cast(self.c_ptrtype, result)[0]) class NumericRefExecutorMixin(object): @@ -107,9 +111,9 @@ class NumericRefExecutorMixin(object): 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) + def execute_libffi(self, space, cif_descr, funcaddr, buf): + jit_libffi.jit_ffi_call(cif_descr, funcaddr, buf) + result = rffi.ptradd(buf, cif_descr.exchange_result) return self._wrap_reference(space, rffi.cast(self.c_ptrtype, rffi.cast(rffi.VOIDPP, result)[0])) @@ -121,7 +125,7 @@ class LongDoubleExecutorMixin(object): result = self.c_stubcall(space, cppmethod, cppthis, num_args, args) return space.newfloat(result) - def execute_libffi(self, space, cif_descr, funcaddr, buffer): + def execute_libffi(self, space, cif_descr, funcaddr, buf): from pypy.module._cppyy.interp_cppyy import FastCallNotPossible raise FastCallNotPossible @@ -144,9 +148,9 @@ class LongDoubleRefExecutorMixin(NumericRefExecutorMixin): 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) + def execute_libffi(self, space, cif_descr, funcaddr, buf): + jit_libffi.jit_ffi_call(cif_descr, funcaddr, buf) + result = rffi.ptradd(buf, cif_descr.exchange_result) return self._wrap_reference(space, rffi.cast(self.c_ptrtype, rffi.cast(rffi.VOIDPP, result)[0])) @@ -158,12 +162,34 @@ class LongDoubleRefExecutor(ffitypes.typeid(rffi.LONGDOUBLE), LongDoubleRefExecu class CStringExecutor(Executor): def execute(self, space, cppmethod, cppthis, num_args, args): - lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args) - ccpresult = rffi.cast(rffi.CCHARP, lresult) - if ccpresult == rffi.cast(rffi.CCHARP, 0): + vptr = capi.c_call_r(space, cppmethod, cppthis, num_args, args) + ccp = rffi.cast(rffi.CCHARP, vptr) + if ccp == rffi.cast(rffi.CCHARP, 0): return space.newbytes("") - result = rffi.charp2str(ccpresult) # TODO: make it a choice to free - return space.newbytes(result) + result = rffi.charp2str(ccp) # TODO: make it a choice to free + return space.newtext(result) + + +class CharNExecutor(object): + _mixin_ = True + def execute(self, space, cppmethod, cppthis, num_args, args): + lres = capi.c_call_l(space, cppmethod, cppthis, num_args, args) + return self._wrap_object(space, lres) + + def execute_libffi(self, space, cif_descr, funcaddr, buf): + jit_libffi.jit_ffi_call(cif_descr, funcaddr, buf) + vptr = rffi.ptradd(buf, cif_descr.exchange_result) + lres = rffi.cast(rffi.LONG, rffi.cast(rffi.LONGP, vptr)[0]) + return self._wrap_object(space, lres) + +class WCharExecutor(ffitypes.typeid(lltype.UniChar), CharNExecutor, Executor): + pass + +class Char16Executor(ffitypes.typeid(ffitypes.CHAR16_T), CharNExecutor, Executor): + pass + +class Char32Executor(ffitypes.typeid(ffitypes.CHAR32_T), CharNExecutor, Executor): + pass class ConstructorExecutor(Executor): @@ -175,7 +201,7 @@ class ConstructorExecutor(Executor): class InstanceExecutor(Executor): - # For return of a C++ instance by pointer: MyClass* func() + # For return of a C++ instance by value: MyClass func() _immutable_fields_ = ['clsdecl'] def __init__(self, space, clsdecl): @@ -204,12 +230,12 @@ class InstancePtrExecutor(InstanceExecutor): return interp_cppyy.wrap_cppinstance(space, obj, self.clsdecl) def execute(self, space, cppmethod, cppthis, num_args, args): - lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args) - return self._wrap_result(space, rffi.cast(capi.C_OBJECT, lresult)) + vptr = capi.c_call_r(space, cppmethod, cppthis, num_args, args) + return self._wrap_result(space, rffi.cast(capi.C_OBJECT, vptr)) - def execute_libffi(self, space, cif_descr, funcaddr, buffer): - jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer) - presult = rffi.ptradd(buffer, cif_descr.exchange_result) + def execute_libffi(self, space, cif_descr, funcaddr, buf): + jit_libffi.jit_ffi_call(cif_descr, funcaddr, buf) + presult = rffi.ptradd(buf, cif_descr.exchange_result) obj = rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, presult)[0]) return self._wrap_result(space, obj) @@ -218,14 +244,46 @@ class InstancePtrPtrExecutor(InstancePtrExecutor): def execute(self, space, cppmethod, cppthis, num_args, args): presult = capi.c_call_r(space, cppmethod, cppthis, num_args, args) - ref = rffi.cast(rffi.VOIDPP, presult) - return self._wrap_result(space, rffi.cast(capi.C_OBJECT, ref[0])) + vref = rffi.cast(rffi.VOIDPP, presult) + return self._wrap_result(space, rffi.cast(capi.C_OBJECT, vref[0])) - def execute_libffi(self, space, cif_descr, funcaddr, buffer): + def execute_libffi(self, space, cif_descr, funcaddr, buf): from pypy.module._cppyy.interp_cppyy import FastCallNotPossible raise FastCallNotPossible +class ComplexExecutor(Executor): + _immutable_fields_ = ['clsdecl', 'realf', 'imagf'] + + def __init__(self, space, clsdecl): + Executor.__init__(self, space, clsdecl) + self.clsdecl = clsdecl + self.realf = self.clsdecl.scope__dispatch__('real', '') + self.imagf = self.clsdecl.scope__dispatch__('imag', '') + + def _convert2complex(self, space, cmplx): + w_real = self.realf.call_impl(cmplx, []) + w_imag = self.imagf.call_impl(cmplx, []) + return space.newcomplex(space.float_w(w_real), space.float_w(w_imag)) + + def execute(self, space, cppmethod, cppthis, num_args, args): + cmplx = capi.c_call_o(space, cppmethod, cppthis, num_args, args, self.clsdecl) + pycmplx = self._convert2complex(space, rffi.cast(capi.C_OBJECT, cmplx)) + capi.c_destruct(space, self.clsdecl, cmplx) + return pycmplx + +class ComplexRefExecutor(ComplexExecutor): + def execute(self, space, cppmethod, cppthis, num_args, args): + cmplx = capi.c_call_r(space, cppmethod, cppthis, num_args, args) + return self._convert2complex(space, rffi.cast(capi.C_OBJECT, cmplx)) + + def execute_libffi(self, space, cif_descr, funcaddr, buf): + jit_libffi.jit_ffi_call(cif_descr, funcaddr, buf) + result = rffi.ptradd(buf, cif_descr.exchange_result) + return self._convert2complex(space, + rffi.cast(capi.C_OBJECT, rffi.cast(rffi.VOIDPP, result)[0])) + + class StdStringExecutor(InstancePtrExecutor): def execute(self, space, cppmethod, cppthis, num_args, args): cstr, cstr_len = capi.c_call_s(space, cppmethod, cppthis, num_args, args) @@ -233,7 +291,7 @@ class StdStringExecutor(InstancePtrExecutor): capi.c_free(space, rffi.cast(rffi.VOIDP, cstr)) return space.newbytes(pystr) - def execute_libffi(self, space, cif_descr, funcaddr, buffer): + def execute_libffi(self, space, cif_descr, funcaddr, buf): from pypy.module._cppyy.interp_cppyy import FastCallNotPossible raise FastCallNotPossible @@ -257,15 +315,15 @@ class PyObjectExecutor(PtrTypeExecutor): def execute(self, space, cppmethod, cppthis, num_args, args): if hasattr(space, "fake"): raise NotImplementedError - lresult = capi.c_call_l(space, cppmethod, cppthis, num_args, args) - return self.wrap_result(space, lresult) + vptr = capi.c_call_r(space, cppmethod, cppthis, num_args, args) + return self.wrap_result(space, vptr) - def execute_libffi(self, space, cif_descr, funcaddr, buffer): + def execute_libffi(self, space, cif_descr, funcaddr, buf): if hasattr(space, "fake"): raise NotImplementedError - jit_libffi.jit_ffi_call(cif_descr, funcaddr, buffer) - result = rffi.ptradd(buffer, cif_descr.exchange_result) - return self.wrap_result(space, rffi.cast(rffi.LONGP, result)[0]) + jit_libffi.jit_ffi_call(cif_descr, funcaddr, buf) + result = rffi.ptradd(buf, cif_descr.exchange_result) + return self.wrap_result(space, rffi.cast(rffi.VOIDPP, result)[0]) class SmartPointerExecutor(InstanceExecutor): @@ -313,9 +371,14 @@ def get_executor(space, name): # # If all fails, a default is used, which can be ignored at least until use. - name = capi.c_resolve_name(space, name) + # original, exact match + try: + return _executors[name](space, None) + except KeyError: + pass - # full, qualified match + # resolved, exact match + name = capi.c_resolve_name(space, name) try: return _executors[name](space, None) except KeyError: @@ -355,6 +418,13 @@ def get_executor(space, name): return SmartPointerPtrExecutor(space, clsdecl, check_smart[1], check_smart[2]) # fall through: can still return smart pointer in non-smart way + if clean_name.find('std::complex', 0, 12) == 0 and\ + (0 < clean_name.find('double') or 0 < clean_name.find('float')): + if compound == '': + return ComplexExecutor(space, clsdecl) + elif compound == '&': + return ComplexRefExecutor(space, clsdecl) + if compound == '': return InstanceExecutor(space, clsdecl) elif compound == '*' or compound == '&': @@ -376,6 +446,9 @@ def get_executor(space, name): _executors["void"] = VoidExecutor _executors["void*"] = PtrTypeExecutor _executors["const char*"] = CStringExecutor +_executors["wchar_t"] = WCharExecutor +_executors["char16_t"] = Char16Executor +_executors["char32_t"] = Char32Executor # long double not really supported: narrows to double _executors["long double"] = LongDoubleExecutor @@ -384,7 +457,7 @@ _executors["long double&"] = LongDoubleRefExecutor # special cases (note: 'string' aliases added below) _executors["constructor"] = ConstructorExecutor -_executors["std::string"] = StdStringExecutor +_executors["std::basic_string<char>"] = StdStringExecutor _executors["const std::basic_string<char>&"] = StdStringRefExecutor _executors["std::basic_string<char>&"] = StdStringRefExecutor @@ -394,18 +467,20 @@ _executors["PyObject*"] = PyObjectExecutor def _build_basic_executors(): "NOT_RPYTHON" type_info = ( - (bool, capi.c_call_b, ("bool",)), + (bool, capi.c_call_b, ("bool",)), # TODO: either signed or unsigned is correct for a given platform ... - (rffi.CHAR, capi.c_call_c, ("char", "unsigned char", "signed char")), - (rffi.SHORT, capi.c_call_h, ("short", "short int", "unsigned short", "unsigned short int")), - (rffi.INT, capi.c_call_i, ("int", "internal_enum_type_t")), - (rffi.UINT, capi.c_call_l, ("unsigned", "unsigned int")), - (rffi.LONG, capi.c_call_l, ("long", "long int")), - (rffi.ULONG, capi.c_call_l, ("unsigned long", "unsigned long int")), - (rffi.LONGLONG, capi.c_call_ll, ("long long", "long long int", "Long64_t")), - (rffi.ULONGLONG, capi.c_call_ll, ("unsigned long long", "unsigned long long int", "ULong64_t")), - (rffi.FLOAT, capi.c_call_f, ("float",)), - (rffi.DOUBLE, capi.c_call_d, ("double",)), + (rffi.CHAR, capi.c_call_c, ("char", "unsigned char", "signed char")), + (ffitypes.INT8_T, capi.c_call_c, ("int8_t",)), + (ffitypes.UINT8_T, capi.c_call_c, ("uint8_t", "std::byte", "byte",)), + (rffi.SHORT, capi.c_call_h, ("short", "short int", "unsigned short", "unsigned short int")), + (rffi.INT, capi.c_call_i, ("int", "internal_enum_type_t")), + (rffi.UINT, capi.c_call_l, ("unsigned", "unsigned int")), + (rffi.LONG, capi.c_call_l, ("long", "long int")), + (rffi.ULONG, capi.c_call_l, ("unsigned long", "unsigned long int")), + (rffi.LONGLONG, capi.c_call_ll, ("long long", "long long int", "Long64_t")), + (rffi.ULONGLONG, capi.c_call_ll, ("unsigned long long", "unsigned long long int", "ULong64_t")), + (rffi.FLOAT, capi.c_call_f, ("float",)), + (rffi.DOUBLE, capi.c_call_d, ("double",)), # (rffi.LONGDOUBLE, capi.c_call_ld, ("long double",)), ) @@ -453,10 +528,9 @@ def _add_aliased_executors(): aliases = ( ("const char*", "char*"), - ("std::string", "string"), - ("std::string", "std::basic_string<char>"), - ("const std::basic_string<char>&", "const string&"), - ("std::basic_string<char>&", "string&"), + ("std::basic_string<char>", "std::string"), + ("const std::basic_string<char>&", "const std::string&"), + ("std::basic_string<char>&", "std::string&"), ("PyObject*", "_object*"), ) diff --git a/pypy/module/_cppyy/ffitypes.py b/pypy/module/_cppyy/ffitypes.py index af2c879bd5..205f99d4cc 100644 --- a/pypy/module/_cppyy/ffitypes.py +++ b/pypy/module/_cppyy/ffitypes.py @@ -1,6 +1,8 @@ from pypy.interpreter.error import oefmt +from pypy.interpreter.unicodehelper import utf8_encode_utf_16, utf8_encode_utf_32 +from pypy.objspace.std.unicodeobject import W_UnicodeObject -from rpython.rtyper.lltypesystem import rffi +from rpython.rtyper.lltypesystem import rffi, lltype from rpython.rlib.rarithmetic import r_singlefloat, r_longfloat from rpython.rlib.rbigint import rbigint @@ -14,6 +16,9 @@ class State(object): def __init__(self, space): nt = newtype # module from _cffi_backend + # the below are (expected to be) lookups, not actual new types, hence + # the underlying wrapped primitive class need not be specified + # builtin types self.c_void = nt.new_void_type(space) self.c_bool = nt.new_primitive_type(space, '_Bool') @@ -34,12 +39,19 @@ class State(object): # pointer types self.c_ccharp = nt.new_pointer_type(space, self.c_char) self.c_voidp = nt.new_pointer_type(space, self.c_void) + self.c_voidpp = nt.new_pointer_type(space, self.c_voidp) # special types + self.c_int8_t = nt.new_primitive_type(space, 'int8_t') + self.c_uint8_t = nt.new_primitive_type(space, 'uint8_t') self.c_size_t = nt.new_primitive_type(space, 'size_t') self.c_ptrdiff_t = nt.new_primitive_type(space, 'ptrdiff_t') self.c_intptr_t = nt.new_primitive_type(space, 'intptr_t') self.c_uintptr_t = nt.new_primitive_type(space, 'uintptr_t') + self.c_wchar_t = nt.new_primitive_type(space, 'wchar_t') + self.c_char16_t = nt.new_primitive_type(space, 'char16_t') + self.c_char32_t = nt.new_primitive_type(space, 'char32_t') + class BoolTypeMixin(object): _mixin_ = True @@ -70,7 +82,7 @@ class CharTypeMixin(object): c_ptrtype = rffi.CCHARP # there's no such thing as rffi.CHARP def _wrap_object(self, space, obj): - return space.newbytes(obj) + return space.newbytes(rffi.cast(self.c_type, obj)) def _unwrap_object(self, space, w_value): # allow int to pass to char and make sure that str is of length 1 @@ -89,19 +101,29 @@ class CharTypeMixin(object): 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 + value = rffi.cast(rffi.CHAR, value[0]) + return value def cffi_type(self, space): state = space.fromcache(State) return state.c_char +class SCharTypeMixin(CharTypeMixin): + _mixin_ = True + _immutable_fields_ = ['c_type', 'c_ptrtype'] + + c_type = rffi.SIGNEDCHAR + c_ptrtype = rffi.CCHARP # SIGNEDCHARP is not recognized as a char type for str + + def _wrap_object(self, space, obj): + return space.newbytes(rffi.cast(rffi.CHAR, rffi.cast(self.c_type, obj))) + 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 + c_ptrtype = rffi.CCHARP # UCHARP is not recognized as a char type for str def _wrap_object(self, space, obj): return space.newbytes(obj) @@ -123,22 +145,136 @@ class UCharTypeMixin(object): raise oefmt(space.w_ValueError, "unsigned char expected, got string of size %d", len(value)) - value = rffi.cast(rffi.CHAR, value[0]) + 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 WCharTypeMixin(object): + _mixin_ = True + _immutable_fields_ = ['c_type', 'c_ptrtype'] + + c_type = lltype.UniChar + c_ptrtype = rffi.CWCHARP + + def _wrap_object(self, space, obj): + result = rffi.cast(self.c_type, obj) + u = rffi.cast(lltype.UniChar, result) + return W_UnicodeObject(u.encode('utf8'), 1) + + def _unwrap_object(self, space, w_value): + utf8, length = space.utf8_len_w(space.unicode_from_object(w_value)) + if length != 1: + raise oefmt(space.w_ValueError, + "wchar_t expected, got string of size %d", length) + + with rffi.scoped_utf82wcharp(utf8, length) as u: + value = rffi.cast(self.c_type, u[0]) + return value + + def cffi_type(self, space): + state = space.fromcache(State) + return state.c_wchar_t + + +def select_sized_int(size): + for t, p in [(rffi.SHORT, rffi.SHORTP), (rffi.INT, rffi.INTP), (rffi.LONG, rffi.LONGP)]: + if rffi.sizeof(t) == size: + return t, p + raise NotImplementedError("no integer type of size %d available" % size) + +CHAR16_T = 'char16_t' +class Char16TypeMixin(object): + _mixin_ = True + _immutable_fields_ = ['c_type', 'c_ptrtype'] + + c_type, c_ptrtype = select_sized_int(2) + + def _wrap_object(self, space, obj): + result = rffi.cast(self.c_type, obj) + u = rffi.cast(lltype.UniChar, result) + return W_UnicodeObject(u.encode('utf8'), 1) + + def _unwrap_object(self, space, w_value): + utf8, length = space.utf8_len_w(space.unicode_from_object(w_value)) + if length != 1: + raise oefmt(space.w_ValueError, + "char16_t expected, got string of size %d", length) + + utf16 = utf8_encode_utf_16(utf8, 'strict') + rawstr = rffi.str2charp(utf16) + value = rffi.cast(self.c_ptrtype, lltype.direct_ptradd(rawstr, 2))[0] # adjust BOM + lltype.free(rawstr, flavor='raw') + return value + + def cffi_type(self, space): + state = space.fromcache(State) + return state.c_char16_t + +CHAR32_T = 'char32_t' +class Char32TypeMixin(object): + _mixin_ = True + _immutable_fields_ = ['c_type', 'c_ptrtype'] + + c_type, c_ptrtype = select_sized_int(4) + + def _wrap_object(self, space, obj): + result = rffi.cast(self.c_type, obj) + u = rffi.cast(lltype.UniChar, result) + return W_UnicodeObject(u.encode('utf8'), 1) + + def _unwrap_object(self, space, w_value): + utf8, length = space.utf8_len_w(space.unicode_from_object(w_value)) + if length != 1: + raise oefmt(space.w_ValueError, + "char32_t expected, got string of size %d", length) + + utf32 = utf8_encode_utf_32(utf8, 'strict') + rawstr = rffi.str2charp(utf32) + value = rffi.cast(self.c_ptrtype, lltype.direct_ptradd(rawstr, 4))[0] # adjust BOM + lltype.free(rawstr, flavor='raw') + return value + + def cffi_type(self, space): + state = space.fromcache(State) + return state.c_char32_t + + class BaseIntTypeMixin(object): _mixin_ = True def _wrap_object(self, space, obj): - return space.newint(rffi.cast(rffi.INT, obj)) + return space.newint(rffi.cast(rffi.INT, rffi.cast(self.c_type, obj))) def _unwrap_object(self, space, w_obj): return rffi.cast(self.c_type, space.c_int_w(w_obj)) +INT8_T = 'int8_t' +class Int8TypeMixin(BaseIntTypeMixin): + _mixin_ = True + _immutable_fields_ = ['c_type', 'c_ptrtype'] + + c_type = rffi.SIGNEDCHAR + c_ptrtype = rffi.SIGNEDCHARP + + def cffi_type(self, space): + state = space.fromcache(State) + return state.c_int8_t + +UINT8_T = 'uint8_t' +class UInt8TypeMixin(BaseIntTypeMixin): + _mixin_ = True + _immutable_fields_ = ['c_type', 'c_ptrtype'] + + c_type = rffi.UCHAR + c_ptrtype = rffi.UCHARP + + def cffi_type(self, space): + state = space.fromcache(State) + return state.c_uint8_t + class ShortTypeMixin(BaseIntTypeMixin): _mixin_ = True _immutable_fields_ = ['c_type', 'c_ptrtype'] @@ -146,22 +282,22 @@ class ShortTypeMixin(BaseIntTypeMixin): c_type = rffi.SHORT c_ptrtype = rffi.SHORTP -class UShortTypeMixin(BaseIntTypeMixin): def cffi_type(self, space): state = space.fromcache(State) return state.c_short +class UShortTypeMixin(BaseIntTypeMixin): _mixin_ = True _immutable_fields_ = ['c_type', 'c_ptrtype'] c_type = rffi.USHORT c_ptrtype = rffi.USHORTP -class IntTypeMixin(BaseIntTypeMixin): def cffi_type(self, space): state = space.fromcache(State) return state.c_ushort +class IntTypeMixin(BaseIntTypeMixin): _mixin_ = True _immutable_fields_ = ['c_type', 'c_ptrtype'] @@ -317,7 +453,13 @@ def typeid(c_type): "NOT_RPYTHON" if c_type == bool: return BoolTypeMixin if c_type == rffi.CHAR: return CharTypeMixin + if c_type == rffi.SIGNEDCHAR: return SCharTypeMixin if c_type == rffi.UCHAR: return UCharTypeMixin + if c_type == lltype.UniChar: return WCharTypeMixin # rffi.W_CHAR_T is rffi.INT + if c_type == CHAR16_T: return Char16TypeMixin # no type in rffi + if c_type == CHAR32_T: return Char32TypeMixin # id. + if c_type == INT8_T: return Int8TypeMixin # id. + if c_type == UINT8_T: return UInt8TypeMixin # id. 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/helper.py b/pypy/module/_cppyy/helper.py index c5a8d5f5a3..826ae66922 100644 --- a/pypy/module/_cppyy/helper.py +++ b/pypy/module/_cppyy/helper.py @@ -36,7 +36,7 @@ def _find_qualifier_index(name): # search from the back; note len(name) > 0 (so rtyper can use uint) for i in range(len(name) - 1, 0, -1): c = name[i] - if c.isalnum() or c == ">" or c == "]": + if c.isalnum() or c in ['_', '>', ']', ')']: break return i + 1 diff --git a/pypy/module/_cppyy/include/capi.h b/pypy/module/_cppyy/include/capi.h index a032a064d9..04044dd353 100644 --- a/pypy/module/_cppyy/include/capi.h +++ b/pypy/module/_cppyy/include/capi.h @@ -11,6 +11,7 @@ extern "C" { typedef size_t cppyy_scope_t; typedef cppyy_scope_t cppyy_type_t; + typedef void* cppyy_enum_t; typedef void* cppyy_object_t; typedef intptr_t cppyy_method_t; @@ -20,7 +21,10 @@ extern "C" { typedef unsigned long cppyy_exctype_t; /* direct interpreter access ---------------------------------------------- */ + RPY_EXTERN int cppyy_compile(const char* code); + RPY_EXTERN + char* cppyy_to_string(cppyy_type_t klass, cppyy_object_t obj); /* name to opaque C++ scope representation -------------------------------- */ RPY_EXTERN @@ -36,6 +40,11 @@ extern "C" { RPY_EXTERN size_t cppyy_size_of_type(const char* type_name); + RPY_EXTERN + int cppyy_is_builtin(const char* type_name); + RPY_EXTERN + int cppyy_is_complete(const char* type_name); + /* memory management ------------------------------------------------------ */ RPY_EXTERN cppyy_object_t cppyy_allocate(cppyy_type_t type); @@ -103,11 +112,16 @@ extern "C" { int cppyy_is_abstract(cppyy_type_t type); RPY_EXTERN int cppyy_is_enum(const char* type_name); + RPY_EXTERN + int cppyy_is_aggregate(cppyy_type_t type); + RPY_EXTERN + int cppyy_is_default_constructable(cppyy_type_t type); RPY_EXTERN const char** cppyy_get_all_cpp_names(cppyy_scope_t scope, size_t* count); /* namespace reflection information --------------------------------------- */ + RPY_EXTERN cppyy_index_t* cppyy_get_using_namespaces(cppyy_scope_t scope); /* class reflection information ------------------------------------------- */ @@ -132,6 +146,9 @@ extern "C" { RPY_EXTERN void cppyy_add_smartptr_type(const char* type_name); + RPY_EXTERN + void cppyy_add_type_reducer(const char* reducable, const char* reduced); + /* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */ RPY_EXTERN ptrdiff_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction); @@ -140,6 +157,8 @@ extern "C" { RPY_EXTERN int cppyy_num_methods(cppyy_scope_t scope); RPY_EXTERN + int cppyy_num_methods_ns(cppyy_scope_t scope); + RPY_EXTERN cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const char* name); RPY_EXTERN @@ -158,7 +177,7 @@ extern "C" { RPY_EXTERN int cppyy_method_req_args(cppyy_method_t); RPY_EXTERN - char* cppyy_method_arg_name(cppyy_method_t,int arg_index); + char* cppyy_method_arg_name(cppyy_method_t, int arg_index); RPY_EXTERN char* cppyy_method_arg_type(cppyy_method_t, int arg_index); RPY_EXTERN @@ -174,9 +193,13 @@ extern "C" { RPY_EXTERN int cppyy_get_num_templated_methods(cppyy_scope_t scope); + RPY_EXPORTED + int cppyy_get_num_templated_methods_ns(cppyy_scope_t scope); RPY_EXTERN char* cppyy_get_templated_method_name(cppyy_scope_t scope, cppyy_index_t imeth); RPY_EXTERN + int cppyy_is_templated_constructor(cppyy_scope_t scope, cppyy_index_t imeth); + RPY_EXTERN int cppyy_exists_method_template(cppyy_scope_t scope, const char* name); RPY_EXTERN int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx); @@ -191,6 +214,8 @@ extern "C" { RPY_EXTERN int cppyy_is_publicmethod(cppyy_method_t); RPY_EXTERN + int cppyy_is_protectedmethod(cppyy_method_t); + RPY_EXTERN int cppyy_is_constructor(cppyy_method_t); RPY_EXTERN int cppyy_is_destructor(cppyy_method_t); @@ -200,6 +225,8 @@ extern "C" { /* data member reflection information ------------------------------------- */ RPY_EXTERN int cppyy_num_datamembers(cppyy_scope_t scope); + RPY_EXPORTED + int cppyy_num_datamembers_ns(cppyy_scope_t scope); RPY_EXTERN char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index); RPY_EXTERN @@ -213,6 +240,8 @@ extern "C" { RPY_EXTERN int cppyy_is_publicdata(cppyy_type_t type, cppyy_index_t datamember_index); RPY_EXTERN + int cppyy_is_protecteddata(cppyy_type_t type, cppyy_index_t datamember_index); + RPY_EXTERN int cppyy_is_staticdata(cppyy_type_t type, cppyy_index_t datamember_index); RPY_EXTERN int cppyy_is_const_data(cppyy_scope_t scope, cppyy_index_t idata); @@ -221,6 +250,16 @@ extern "C" { RPY_EXTERN int cppyy_get_dimension_size(cppyy_scope_t scope, cppyy_index_t idata, int dimension); + /* enum properties -------------------------------------------------------- */ + RPY_EXTERN + cppyy_enum_t cppyy_get_enum(cppyy_scope_t scope, const char* enum_name); + RPY_EXTERN + cppyy_index_t cppyy_get_num_enum_data(cppyy_enum_t); + RPY_EXTERN + const char* cppyy_get_enum_data_name(cppyy_enum_t, cppyy_index_t idata); + RPY_EXTERN + long long cppyy_get_enum_data_value(cppyy_enum_t, cppyy_index_t idata); + /* misc helpers ----------------------------------------------------------- */ RPY_EXTERN long long cppyy_strtoll(const char* str); diff --git a/pypy/module/_cppyy/interp_cppyy.py b/pypy/module/_cppyy/interp_cppyy.py index b114ee17c0..c0ebaf104c 100644 --- a/pypy/module/_cppyy/interp_cppyy.py +++ b/pypy/module/_cppyy/interp_cppyy.py @@ -146,7 +146,7 @@ def register_class(space, w_pycppclass): # class allows simple aliasing of methods) capi.pythonize(space, w_pycppclass, cppclass.name) state = space.fromcache(State) - state.cppclass_registry[rffi.cast(rffi.LONG, cppclass.handle)] = w_pycppclass + state.cppclass_registry[cppclass.handle] = w_pycppclass class W_CPPLibrary(W_Root): @@ -169,7 +169,7 @@ W_CPPLibrary.typedef.acceptable_as_base_class = True # # W_CPPOverload: instance methods (base class) # W_CPPConstructorOverload: constructors -# W_CPPAbstractCtorOverload: to provent instantiation of abstract classes +# W_CPPAbstractCtorOverload: to prevent instantiation of abstract classes # W_CPPStaticOverload: free and static functions # W_CPPTemplateOverload: templated methods # W_CPPTemplateStaticOverload: templated free and static functions @@ -270,8 +270,8 @@ class CPPMethod(object): if cppthis: # this pointer 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) + x = rffi.cast(rffi.VOIDPP, data) + x[0] = rffi.cast(rffi.VOIDP, cppthis) thisoff = 1 # actual provided arguments @@ -803,7 +803,7 @@ class TemplateOverloadMixin(object): elif space.isinstance_w(w_tp, space.w_type): try: # cppyy bound types - s = space.text_w(space.getattr(w_tp, space.newtext('__cppname__'))) + s = space.text_w(space.getattr(w_tp, space.newtext('__cpp_name__'))) if args_w: # try to specialize the type match for the given object cppinstance = self.space.interp_w(W_CPPInstance, args_w[i]) @@ -826,13 +826,14 @@ class TemplateOverloadMixin(object): tmpl_args += s return tmpl_args - def find_method_template(self, name, proto = ''): - # find/instantiate new callable function + def instantiate_method_template(self, name, proto = ''): + # instantiate/find new callable function space = self.space cppmeth = capi.c_get_method_template(space, self.scope, name, proto) if not cppmeth: raise oefmt(self.space.w_AttributeError, - "scope '%s' has no function %s", self.scope.name, name) + "failed to instantiate %s::%s for arguments '%s'", + self.scope.name, name, proto) funcs = [] ftype = self.scope._make_cppfunction(name, cppmeth, funcs) @@ -842,53 +843,46 @@ class TemplateOverloadMixin(object): cppol = W_CPPOverload(space, self.scope, funcs[:], self.flags) return cppol - def instantiate_and_call(self, name, args_w): + def _call_method(self, method, args_w): + if not self.space.is_w(self.w_this, self.space.w_None): + return self.space.call_obj_args(method, self.w_this, Arguments(self.space, args_w)) + return self.space.call_args(method, Arguments(self.space, args_w)) + + def template_call(self, name, tmpl_args, args_w): method = None + + fullname = name + if tmpl_args is not None: + fullname = fullname+'<'+tmpl_args+'>' + try: # existing cached instantiations - if name[-1] == '>': # only accept full templated name, to ensure explicit - method = self.master.overloads[name] - else: - # try to match with run-time instantiations - # TODO: logically, this could be used, but in practice, it's proving too - # greedy ... maybe as a last resort? - #for cppol in self.master.overloads.values(): - # try: - # if not self.space.is_w(self.w_this, self.space.w_None): - # return self.space.call_obj_args(cppol, self.w_this, Arguments(self.space, args_w)) - # return self.space.call_args(cppol, Arguments(self.space, args_w)) - # except Exception: - # pass # completely ignore for now; have to see whether errors become confusing - raise TypeError("pre-existing overloads failed") - except (KeyError, TypeError): - # if not known, try to deduce from argument types - w_types = self.space.newtuple([self.space.type(obj_w) for obj_w in args_w]) - proto = self.construct_template_args(w_types, args_w) - method = self.find_method_template(name, proto) - - # only cache result if the name retains the full template - # TODO: the problem is in part that c_method_full_name returns incorrect names, - # e.g. when default template arguments are involved, so for now use 'name' if it - # has the full templated name - if name[-1] == '>': - fullname = name + method = self.master.overloads[fullname] + return self._call_method(method, args_w) + except Exception: + pass + + # if not known, or failed, try instantiation + w_types = self.space.newtuple([self.space.type(obj_w) for obj_w in args_w]) + proto = self.construct_template_args(w_types, args_w) + method = self.instantiate_method_template(fullname, proto) # may raise + + # cache result as the full templated name only + if fullname[-1] != '>': + fullname = capi.c_method_full_name(self.space, method.functions[0].cppmethod) + try: + existing = self.master.overloads[fullname] + allf = existing.functions + method.functions + if isinstance(existing, W_CPPStaticOverload): + cppol = W_CPPStaticOverload(self.space, self.scope, allf, self.flags) else: - fullname = capi.c_method_full_name(self.space, method.functions[0].cppmethod) - try: - existing = self.master.overloads[fullname] - allf = existing.functions + method.functions - if isinstance(existing, W_CPPStaticOverload): - cppol = W_CPPStaticOverload(self.space, self.scope, allf, self.flags) - else: - cppol = W_CPPOverload(self.space, self.scope, allf, self.flags) - self.master.overloads[fullname] = cppol - except KeyError: - self.master.overloads[fullname] = method + cppol = W_CPPOverload(self.space, self.scope, allf, self.flags) + self.master.overloads[fullname] = cppol + except KeyError: + self.master.overloads[fullname] = method - if method is not None: - if not self.space.is_w(self.w_this, self.space.w_None): - return self.space.call_obj_args(method, self.w_this, Arguments(self.space, args_w)) - return self.space.call_args(method, Arguments(self.space, args_w)) + # perform actual call (which may still fail) + return self._call_method(method, args_w) def getitem_impl(self, name, args_w): space = self.space @@ -899,14 +893,7 @@ class TemplateOverloadMixin(object): w_args = space.newtuple(args_w) tmpl_args = self.construct_template_args(w_args) - fullname = name+'<'+tmpl_args+'>' - try: - method = self.master.overloads[fullname] - except KeyError as e: - # defer instantiation until arguments are known - return self.clone(tmpl_args) - - return method.descr_get(self.w_this, None) + return self.clone(tmpl_args) # defer instantiation until arguments are known class W_CPPTemplateOverload(W_CPPOverload, TemplateOverloadMixin): @@ -944,19 +931,11 @@ class W_CPPTemplateOverload(W_CPPOverload, TemplateOverloadMixin): def call_args(self, args_w): # direct call: either pick non-templated overload or attempt to deduce # the template instantiation from the argument types - - # do explicit lookup with tmpl_args if given try: - fullname = self.name - if self.tmpl_args is not None: - fullname = fullname+'<'+self.tmpl_args+'>' - return self.instantiate_and_call(fullname, args_w) + return W_CPPOverload.call_args(self, [self.w_this]+args_w) except Exception: pass - - # otherwise, try existing overloads or compile-time instantiations - # TODO: consolidate errors - return W_CPPOverload.call_args(self, [self.w_this]+args_w) + return self.template_call(self.name, self.tmpl_args, args_w) @unwrap_spec(args_w='args_w') def getitem(self, args_w): @@ -1019,20 +998,11 @@ class W_CPPTemplateStaticOverload(W_CPPStaticOverload, TemplateOverloadMixin): def call_args(self, args_w): # direct call: either pick non-templated overload or attempt to deduce # the template instantiation from the argument types - # TODO: refactor with W_CPPTemplateOverload - - # do explicit lookup with tmpl_args if given try: - fullname = self.name - if self.tmpl_args is not None: - fullname = fullname+'<'+self.tmpl_args+'>' - return self.instantiate_and_call(fullname, args_w) + return W_CPPStaticOverload.call_args(self, [self.w_this]+args_w) except Exception: pass - - # otherwise, try existing overloads or compile-time instantiations - # TODO: consolidate errors - return W_CPPStaticOverload.call_args(self, args_w) + return self.template_call(self.name, self.tmpl_args, args_w) @unwrap_spec(args_w='args_w') def getitem(self, args_w): @@ -1081,7 +1051,7 @@ class W_CPPDataMember(W_Root): self.space = space self.scope = decl_scope self.converter = converter.get_converter(self.space, type_name, dimensions) - self.offset = rffi.cast(rffi.LONG, offset) + self.offset = rffi.cast(rffi.INTPTR_T, offset) def _get_offset(self, cppinstance): if cppinstance: @@ -1282,7 +1252,7 @@ class W_CPPNamespaceDecl(W_CPPScopeDecl): if capi.c_is_enum_data(self.space, self, dm_idx): type_name = capi.c_resolve_enum(self.space, type_name) offset = capi.c_datamember_offset(self.space, self, dm_idx) - if offset == -1: + if offset == rffi.cast(rffi.INTPTR_T, -1): raise self.missing_attribute_error(dm_name) dims = self._encode_dm_dimensions(dm_idx) if capi.c_is_const_data(self.space, self, dm_idx): @@ -1339,7 +1309,7 @@ W_CPPNamespaceDecl.typedef = TypeDef( get_datamember = interp2app(W_CPPNamespaceDecl.get_datamember), is_namespace = interp2app(W_CPPNamespaceDecl.is_namespace), has_enum = interp2app(W_CPPNamespaceDecl.has_enum), - __cppname__ = interp_attrproperty('name', W_CPPNamespaceDecl, wrapfn="newtext"), + __cpp_name__ = interp_attrproperty('name', W_CPPNamespaceDecl, wrapfn="newtext"), __dispatch__ = interp2app(W_CPPNamespaceDecl.scope__dispatch__), __dir__ = interp2app(W_CPPNamespaceDecl.ns__dir__), ) @@ -1395,7 +1365,7 @@ class W_CPPClassDecl(W_CPPScopeDecl): ftype = ftype_tmp[pyname] CPPMethodSort(methods).sort() if ftype & FUNCTION_IS_CONSTRUCTOR: - if capi.c_is_abstract(self.space, self.handle): + if capi.c_is_abstract(self.space, self): overload = W_CPPAbstractCtorOverload(self.space, self, methods[:]) else: overload = W_CPPConstructorOverload(self.space, self, methods[:]) @@ -1448,7 +1418,7 @@ class W_CPPClassDecl(W_CPPScopeDecl): datamember_name = capi.c_datamember_name(self.space, self, i) type_name = capi.c_datamember_type(self.space, self, i) offset = capi.c_datamember_offset(self.space, self, i) - if offset == -1: + if offset == rffi.cast(rffi.INTPTR_T, -1): continue # dictionary problem; raises AttributeError on use is_static = bool(capi.c_is_staticdata(self.space, self, i)) is_const = bool(capi.c_is_const_data(self.space, self, i)) @@ -1504,7 +1474,7 @@ W_CPPClassDecl.typedef = TypeDef( get_datamember = interp2app(W_CPPClassDecl.get_datamember), is_namespace = interp2app(W_CPPClassDecl.is_namespace), has_enum = interp2app(W_CPPClassDecl.has_enum), - __cppname__ = interp_attrproperty('name', W_CPPClassDecl, wrapfn="newtext"), + __cpp_name__ = interp_attrproperty('name', W_CPPClassDecl, wrapfn="newtext"), __dispatch__ = interp2app(W_CPPClassDecl.scope__dispatch__) ) W_CPPClassDecl.typedef.acceptable_as_base_class = False @@ -1532,7 +1502,7 @@ W_CPPComplexClassDecl.typedef = TypeDef( get_datamember_names = interp2app(W_CPPComplexClassDecl.get_datamember_names), get_datamember = interp2app(W_CPPComplexClassDecl.get_datamember), is_namespace = interp2app(W_CPPComplexClassDecl.is_namespace), - __cppname__ = interp_attrproperty('name', W_CPPComplexClassDecl, wrapfn="newtext"), + __cpp_name__ = interp_attrproperty('name', W_CPPComplexClassDecl, wrapfn="newtext"), __dispatch__ = interp2app(W_CPPComplexClassDecl.scope__dispatch__) ) W_CPPComplexClassDecl.typedef.acceptable_as_base_class = False @@ -1597,7 +1567,7 @@ class W_CPPInstance(W_Root): return self._rawobject elif self.smartdecl and self.deref: args = capi.c_allocate_function_args(self.space, 0) - rawptr = capi.c_call_l(self.space, self.deref, self._rawobject, 0, args) + rawptr = capi.c_call_r(self.space, self.deref, self._rawobject, 0, args) capi.c_deallocate_function_args(self.space, args) return rffi.cast(capi.C_OBJECT, rawptr) else: @@ -1635,7 +1605,7 @@ class W_CPPInstance(W_Root): nss = scope_byname(self.space, name) meth_idx = capi.c_get_global_operator( self.space, nss, self.clsdecl, other.clsdecl, "operator==") - if meth_idx != -1: + if meth_idx != rffi.cast(capi.C_INDEX, -1): funcs = [] cppmeth = capi.c_get_method(self.space, nss, meth_idx) nss._make_cppfunction("operator==", cppmeth, funcs) @@ -1688,7 +1658,7 @@ class W_CPPInstance(W_Root): if w_as_builtin is not None: return self.space.repr(w_as_builtin) return self.space.newtext("<%s object at 0x%x>" % - (self.clsdecl.name, rffi.cast(rffi.ULONG, self.get_rawobject()))) + (self.clsdecl.name, rffi.cast(rffi.UINTPTR_T, self.get_rawobject()))) def smartptr(self): if self._rawobject and self.smartdecl: @@ -1736,7 +1706,7 @@ class MemoryRegulator: def register(obj): if not obj._rawobject: return - addr_as_int = int(rffi.cast(rffi.LONG, obj.get_rawobject())) + addr_as_int = int(rffi.cast(rffi.INTPTR_T, obj.get_rawobject())) clsdecl = obj.clsdecl assert isinstance(clsdecl, W_CPPClassDecl) clsdecl.cppobjects.set(addr_as_int, obj) @@ -1745,7 +1715,7 @@ class MemoryRegulator: def unregister(obj): if not obj._rawobject: return - addr_as_int = int(rffi.cast(rffi.LONG, obj.get_rawobject())) + addr_as_int = int(rffi.cast(rffi.INTPTR_T, obj.get_rawobject())) clsdecl = obj.clsdecl assert isinstance(clsdecl, W_CPPClassDecl) clsdecl.cppobjects.set(addr_as_int, None) # actually deletes (pops) @@ -1754,7 +1724,7 @@ class MemoryRegulator: def retrieve(clsdecl, address): if not address: return None - addr_as_int = int(rffi.cast(rffi.LONG, address)) + addr_as_int = int(rffi.cast(rffi.INTPTR_T, address)) assert isinstance(clsdecl, W_CPPClassDecl) return clsdecl.cppobjects.get(addr_as_int) @@ -1764,7 +1734,7 @@ memory_regulator = MemoryRegulator() def get_pythonized_cppclass(space, handle): state = space.fromcache(State) try: - w_pycppclass = state.cppclass_registry[rffi.cast(rffi.LONG, handle)] + w_pycppclass = state.cppclass_registry[handle] except KeyError: final_name = capi.c_scoped_final_name(space, handle) # the callback will cache the class by calling register_class diff --git a/pypy/module/_cppyy/pythonify.py b/pypy/module/_cppyy/pythonify.py index e6210c7e50..47ccd689d9 100644 --- a/pypy/module/_cppyy/pythonify.py +++ b/pypy/module/_cppyy/pythonify.py @@ -83,7 +83,7 @@ def with_metaclass(meta, *bases): # C++ namespace base class (the C++ class base class defined in _post_import_startup) class CPPNamespace(with_metaclass(CPPNamespaceMeta, object)): def __init__(self): - raise TypeError("cannot instantiate namespace '%s'", self.__cppname__) + raise TypeError("cannot instantiate namespace '%s'", self.__cpp_name__) # TODO: this can be moved to the interp level (and share template argument @@ -100,8 +100,8 @@ class CPPTemplate(object): # arguments are strings representing types, types, or builtins if type(arg) == str: return arg # string describing type - elif hasattr(arg, '__cppname__'): - return arg.__cppname__ # C++ bound type + elif hasattr(arg, '__cpp_name__'): + return arg.__cpp_name__ # C++ bound type elif arg == str: import _cppyy return _cppyy._std_string_name() # special case pystr -> C++ string @@ -187,9 +187,9 @@ def make_cppnamespace(scope, name, decl): ns_meta = type(CPPNamespace)(name+'_meta', (CPPNamespaceMeta,), {}) # create the python-side C++ namespace representation, cache in scope if given - d = {"__cppdecl__" : decl, - "__module__" : make_module_name(scope), - "__cppname__" : decl.__cppname__ } + d = {"__cppdecl__" : decl, + "__module__" : make_module_name(scope), + "__cpp_name__" : decl.__cpp_name__ } pyns = ns_meta(name, (CPPNamespace,), d) if scope: setattr(scope, name, pyns) @@ -242,11 +242,10 @@ def make_cppclass(scope, cl_name, decl): cppol = decl.__dispatch__(m_name, signature) return MethodType(cppol, self, type(self)) d_class = {"__cppdecl__" : decl, - "__new__" : make_new(decl), - "__module__" : make_module_name(scope), - "__cppname__" : decl.__cppname__, - "__dispatch__" : dispatch, - } + "__new__" : make_new(decl), + "__module__" : make_module_name(scope), + "__cpp_name__" : decl.__cpp_name__, + "__dispatch__" : dispatch,} # insert (static) methods into the class dictionary for m_name in decl.get_method_names(): @@ -275,7 +274,7 @@ def make_cppclass(scope, cl_name, decl): # needs to run first, so that the generic pythonizations can use them import _cppyy _cppyy._register_class(pycls) - _pythonize(pycls, pycls.__cppname__) + _pythonize(pycls, pycls.__cpp_name__) return pycls def make_cpptemplatetype(scope, template_name): @@ -287,7 +286,7 @@ def get_scoped_pycppitem(scope, name, type_only=False): # resolve typedefs/aliases: these may cross namespaces, in which case # the lookup must trigger the creation of all necessary scopes - scoped_name = (scope == gbl) and name or (scope.__cppname__+'::'+name) + scoped_name = (scope == gbl) and name or (scope.__cpp_name__+'::'+name) final_scoped_name = _cppyy._resolve_name(scoped_name) if final_scoped_name != scoped_name: pycppitem = get_pycppitem(final_scoped_name) @@ -434,11 +433,13 @@ def _pythonize(pyclass, name): return self pyclass.__iadd__ = iadd + is_vector = name.find('std::vector', 0, 11) == 0 + # map begin()/end() protocol to iter protocol on STL(-like) classes, but # not on vector, which is pythonized in the capi (interp-level; there is # also the fallback on the indexed __getitem__, but that is slower) add_checked_item = False - if name.find('std::vector', 0, 11) != 0: + if not is_vector: if 'begin' in pyclass.__dict__ and 'end' in pyclass.__dict__: if _cppyy._scope_byname(name+'::iterator') or \ _cppyy._scope_byname(name+'::const_iterator'): @@ -458,7 +459,7 @@ def _pythonize(pyclass, name): add_checked_item = True # add python collection based initializer - if name.find('std::vector', 0, 11) == 0: + else: pyclass.__real_init__ = pyclass.__init__ def vector_init(self, *args): if len(args) == 1 and isinstance(args[0], (tuple, list)): @@ -482,7 +483,7 @@ def _pythonize(pyclass, name): # TODO: must be a simpler way to check (or at least hook these to a namespace # std specific pythonizor) - if add_checked_item or name.find('std::vector', 0, 11) == 0 or \ + if add_checked_item or is_vector or \ name.find('std::array', 0, 11) == 0 or name.find('std::deque', 0, 10) == 0: # combine __getitem__ and __len__ to make a pythonized __getitem__ if '__getitem__' in pyclass.__dict__ and '__len__' in pyclass.__dict__: @@ -503,7 +504,7 @@ def _pythonize(pyclass, name): pyclass.__str__ = pyclass.c_str # std::pair unpacking through iteration - if 'std::pair' == name[:9]: + elif name.find('std::pair', 0, 9) == 0: def getitem(self, idx): if idx == 0: return self.first if idx == 1: return self.second @@ -513,6 +514,30 @@ def _pythonize(pyclass, name): pyclass.__getitem__ = getitem pyclass.__len__ = return2 + # std::complex integration with Python complex + elif name.find('std::complex', 0, 12) == 0: + def getreal(obj): + return obj.__cpp_real() + def setreal(obj, val): + obj.__cpp_real(val) + pyclass.__cpp_real = pyclass.real + pyclass.real = property(getreal, setreal) + + def getimag(obj): + return obj.__cpp_imag() + def setimag(obj, val): + obj.__cpp_imag(val) + pyclass.__cpp_imag = pyclass.imag + pyclass.imag = property(getimag, setimag) + + def cmplx(self): + return self.real+self.imag*1.j + pyclass.__complex__ = cmplx + + def cmplx_repr(self): + return repr(self.__complex__()) + pyclass.__repr__ = cmplx_repr + # user provided, custom pythonizations try: ns_name, cl_name = extract_namespace(name) diff --git a/pypy/module/_cppyy/src/dummy_backend.cxx b/pypy/module/_cppyy/src/dummy_backend.cxx index 55d49b3af3..a4663cbf8d 100644 --- a/pypy/module/_cppyy/src/dummy_backend.cxx +++ b/pypy/module/_cppyy/src/dummy_backend.cxx @@ -1,15 +1,23 @@ #include "capi.h" +// include all headers from datatype.cxx and example01.cxx here, +// allowing those .cxx files to be placed in the "dummy" namespace +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <cstring> +#include <cwchar> + +#include <complex> +#include <functional> #include <map> +#include <memory> #include <string> #include <sstream> #include <utility> #include <vector> -#include <assert.h> -#include <stddef.h> -#include <stdlib.h> -#include <string.h> +#include <sys/types.h> #pragma GCC diagnostic ignored "-Winvalid-offsetof" @@ -47,6 +55,22 @@ struct CPPYY_G__value { int type; }; + +// gInterpreter +namespace dummy { + class TInterpreter { + public: + int ProcessLine(const char* line) { + if (strcmp(line, "__cplusplus;") == 0) + return 0; + return -1; + } + }; + + TInterpreter gInterpreter; +} // namespace dummy + + // add example01.cxx code int globalAddOneToInt(int a); @@ -172,17 +196,38 @@ int Pseudo_kLots = 42; struct Cppyy_InitPseudoReflectionInfo { Cppyy_InitPseudoReflectionInfo() { - // class example01 -- static cppyy_scope_t s_scope_id = 0; { // namespace '' s_handles[""] = (cppyy_scope_t)++s_scope_id; + + std::vector<Cppyy_PseudoDatambrInfo> data; + data.push_back(Cppyy_PseudoDatambrInfo("N", "int", (ptrdiff_t)&dummy::N, true)); + data.push_back(Cppyy_PseudoDatambrInfo( + "gInterpreter", "TInterpreter", (ptrdiff_t)&dummy::gInterpreter, true)); + + Cppyy_PseudoClassInfo info(std::vector<Cppyy_PseudoMethodInfo*>(), data); + s_scopes[(cppyy_scope_t)s_scope_id] = info; } { // namespace std s_handles["std"] = (cppyy_scope_t)++s_scope_id; } + { // class TInterpreter + s_handles["TInterpreter"] = (cppyy_scope_t)++s_scope_id; + + std::vector<Cppyy_PseudoMethodInfo*> methods; + + std::vector<std::string> argtypes; + argtypes.push_back("const char*"); + methods.push_back(new Cppyy_PseudoMethodInfo("ProcessLine", argtypes, "int")); + s_methods["TInterpreter::ProcessLine_cchar*"] = methods.back(); + + Cppyy_PseudoClassInfo info(methods, std::vector<Cppyy_PseudoDatambrInfo>()); + s_scopes[(cppyy_scope_t)s_scope_id] = info; + } + { // class example01 -- s_handles["example01"] = (cppyy_scope_t)++s_scope_id; @@ -308,6 +353,64 @@ struct Cppyy_InitPseudoReflectionInfo { //==================================================================== + { // class complex<double> -- + s_handles["complex_t"] = (cppyy_scope_t)++s_scope_id; + s_handles["std::complex<double>"] = s_handles["complex_t"]; + + std::vector<Cppyy_PseudoMethodInfo*> methods; + + std::vector<std::string> argtypes; + + // double real() + argtypes.clear(); + methods.push_back(new Cppyy_PseudoMethodInfo("real", argtypes, "double")); + s_methods["std::complex<double>::real"] = methods.back(); + + // double imag() + argtypes.clear(); + methods.push_back(new Cppyy_PseudoMethodInfo("imag", argtypes, "double")); + s_methods["std::complex<double>::imag"] = methods.back(); + + // complex<double>(double r, double i) + argtypes.clear(); + argtypes.push_back("double"); + argtypes.push_back("double"); + methods.push_back(new Cppyy_PseudoMethodInfo("complex<double>", argtypes, "constructor", kConstructor)); + s_methods["std::complex<double>::complex<double>_double_double"] = methods.back(); + + Cppyy_PseudoClassInfo info(methods, std::vector<Cppyy_PseudoDatambrInfo>()); + s_scopes[(cppyy_scope_t)s_scope_id] = info; + } + + { // class complex<int> -- + s_handles["icomplex_t"] = (cppyy_scope_t)++s_scope_id; + s_handles["std::complex<int>"] = s_handles["icomplex_t"]; + + std::vector<Cppyy_PseudoMethodInfo*> methods; + + std::vector<std::string> argtypes; + + // int real() + argtypes.clear(); + methods.push_back(new Cppyy_PseudoMethodInfo("real", argtypes, "int")); + s_methods["std::complex<int>::real"] = methods.back(); + + // int imag() + argtypes.clear(); + methods.push_back(new Cppyy_PseudoMethodInfo("imag", argtypes, "int")); + s_methods["std::complex<int>::imag"] = methods.back(); + + // complex<int>(int r, int i) + argtypes.clear(); + argtypes.push_back("int"); + argtypes.push_back("int"); + methods.push_back(new Cppyy_PseudoMethodInfo("complex<int>", argtypes, "constructor", kConstructor)); + s_methods["std::complex<int>::complex<int>_int_int"] = methods.back(); + + Cppyy_PseudoClassInfo info(methods, std::vector<Cppyy_PseudoDatambrInfo>()); + s_scopes[(cppyy_scope_t)s_scope_id] = info; + } + { // class payload -- s_handles["payload"] = (cppyy_scope_t)++s_scope_id; @@ -350,30 +453,42 @@ struct Cppyy_InitPseudoReflectionInfo { s_methods["CppyyTestData::destroy_arrays"] = methods.back(); std::vector<Cppyy_PseudoDatambrInfo> data; - PUBLIC_CPPYY_DATA2(bool, bool); - PUBLIC_CPPYY_DATA (char, char); - PUBLIC_CPPYY_DATA (schar, signed char); - PUBLIC_CPPYY_DATA2(uchar, unsigned char); - PUBLIC_CPPYY_DATA3(short, short, h); - PUBLIC_CPPYY_DATA3(ushort, unsigned short, H); - PUBLIC_CPPYY_DATA3(int, int, i); - PUBLIC_CPPYY_DATA (const_int, const int); - PUBLIC_CPPYY_DATA3(uint, unsigned int, I); - PUBLIC_CPPYY_DATA3(long, long, l); - PUBLIC_CPPYY_DATA3(ulong, unsigned long, L); - PUBLIC_CPPYY_DATA (llong, long long); - PUBLIC_CPPYY_DATA (ullong, unsigned long long); - PUBLIC_CPPYY_DATA (long64, Long64_t); - PUBLIC_CPPYY_DATA (ulong64, ULong64_t); - PUBLIC_CPPYY_DATA3(float, float, f); - PUBLIC_CPPYY_DATA3(double, double, d); - PUBLIC_CPPYY_DATA (ldouble, long double); - PUBLIC_CPPYY_DATA (enum, CppyyTestData::EWhat); - PUBLIC_CPPYY_DATA (voidp, void*); + PUBLIC_CPPYY_DATA2(bool, bool); + PUBLIC_CPPYY_DATA (char, char); + PUBLIC_CPPYY_DATA2(schar, signed char); + PUBLIC_CPPYY_DATA2(uchar, unsigned char); + PUBLIC_CPPYY_DATA (wchar, wchar_t); + PUBLIC_CPPYY_DATA (char16, char16_t); + PUBLIC_CPPYY_DATA (char32, char32_t); + PUBLIC_CPPYY_DATA (int8, int8_t); + PUBLIC_CPPYY_DATA (uint8, uint8_t); + PUBLIC_CPPYY_DATA3(short, short, h); + PUBLIC_CPPYY_DATA3(ushort, unsigned short, H); + PUBLIC_CPPYY_DATA3(int, int, i); + PUBLIC_CPPYY_DATA (const_int, const int); + PUBLIC_CPPYY_DATA3(uint, unsigned int, I); + PUBLIC_CPPYY_DATA3(long, long, l); + PUBLIC_CPPYY_DATA3(ulong, unsigned long, L); + PUBLIC_CPPYY_DATA (llong, long long); + PUBLIC_CPPYY_DATA (ullong, unsigned long long); + PUBLIC_CPPYY_DATA (long64, Long64_t); + PUBLIC_CPPYY_DATA (ulong64, ULong64_t); + PUBLIC_CPPYY_DATA3(float, float, f); + PUBLIC_CPPYY_DATA3(double, double, d); + PUBLIC_CPPYY_DATA (ldouble, long double); + PUBLIC_CPPYY_DATA (complex, complex_t); + PUBLIC_CPPYY_DATA (icomplex, icomplex_t); + PUBLIC_CPPYY_DATA (enum, CppyyTestData::EWhat); + PUBLIC_CPPYY_DATA (voidp, void*); PUBLIC_CPPYY_STATIC_DATA(char, char); PUBLIC_CPPYY_STATIC_DATA(schar, signed char); PUBLIC_CPPYY_STATIC_DATA(uchar, unsigned char); + PUBLIC_CPPYY_STATIC_DATA(wchar, wchar_t); + PUBLIC_CPPYY_STATIC_DATA(char16, char16_t); + PUBLIC_CPPYY_STATIC_DATA(char32, char32_t); + PUBLIC_CPPYY_STATIC_DATA(int8, int8_t); + PUBLIC_CPPYY_STATIC_DATA(uint8, uint8_t); PUBLIC_CPPYY_STATIC_DATA(short, short); PUBLIC_CPPYY_STATIC_DATA(ushort, unsigned short); PUBLIC_CPPYY_STATIC_DATA(int, int); @@ -435,7 +550,11 @@ static INLINE char* cppstring_to_cstring(const std::string& name) { /* name to opaque C++ scope representation -------------------------------- */ char* cppyy_resolve_name(const char* cppitem_name) { - if (cppyy_is_enum(cppitem_name)) + if (strcmp(cppitem_name, "complex_t") == 0) + return cppstring_to_cstring("std::complex<double>"); + else if (strcmp(cppitem_name, "icomplex_t") == 0) + return cppstring_to_cstring("std::complex<int>"); + else if (cppyy_is_enum(cppitem_name)) return cppstring_to_cstring("internal_enum_type_t"); else if (strcmp(cppitem_name, "aap_t") == 0) return cppstring_to_cstring("long double"); @@ -483,6 +602,27 @@ void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* a } else if (idx == s_methods["CppyyTestData::set_uchar"]) { assert(self && nargs == 1); ((dummy::CppyyTestData*)self)->set_uchar(((CPPYY_G__value*)args)[0].obj.uch); + } else if (idx == s_methods["CppyyTestData::set_wchar"]) { + assert(self && nargs == 1); + ((dummy::CppyyTestData*)self)->set_wchar(((CPPYY_G__value*)args)[0].obj.i); + } else if (idx == s_methods["CppyyTestData::set_char16"]) { + assert(self && nargs == 1); + ((dummy::CppyyTestData*)self)->set_char16(((CPPYY_G__value*)args)[0].obj.i); + } else if (idx == s_methods["CppyyTestData::set_char32"]) { + assert(self && nargs == 1); + ((dummy::CppyyTestData*)self)->set_char32(((CPPYY_G__value*)args)[0].obj.i); + } else if (idx == s_methods["CppyyTestData::set_int8"]) { + assert(self && nargs == 1); + ((dummy::CppyyTestData*)self)->set_int8(((CPPYY_G__value*)args)[0].obj.ch); + } else if (idx == s_methods["CppyyTestData::set_int8_cr"]) { + assert(self && nargs == 1); + ((dummy::CppyyTestData*)self)->set_int8_cr(*(int8_t*)&((CPPYY_G__value*)args)[0]); + } else if (idx == s_methods["CppyyTestData::set_uint8"]) { + assert(self && nargs == 1); + ((dummy::CppyyTestData*)self)->set_uint8(((CPPYY_G__value*)args)[0].obj.ch); + } else if (idx == s_methods["CppyyTestData::set_uint8_cr"]) { + assert(self && nargs == 1); + ((dummy::CppyyTestData*)self)->set_uint8_cr(*(uint8_t*)&((CPPYY_G__value*)args)[0]); } else if (idx == s_methods["CppyyTestData::set_short"]) { assert(self && nargs == 1); ((dummy::CppyyTestData*)self)->set_short(((CPPYY_G__value*)args)[0].obj.sh); @@ -575,6 +715,12 @@ char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* a } else if (idx == s_methods["CppyyTestData::get_uchar"]) { assert(self && nargs == 0); result = (char)((dummy::CppyyTestData*)self)->get_uchar(); + } else if (idx == s_methods["CppyyTestData::get_int8"]) { + assert(self && nargs == 0); + result = (long)((dummy::CppyyTestData*)self)->get_int8(); + } else if (idx == s_methods["CppyyTestData::get_uint8"]) { + assert(self && nargs == 0); + result = (long)((dummy::CppyyTestData*)self)->get_uint8(); } else { assert(!"method unknown in cppyy_call_c"); } @@ -599,7 +745,11 @@ short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { int result = 0; Cppyy_PseudoMethodInfo* idx = (Cppyy_PseudoMethodInfo*)method; - if (idx == s_methods["static_example01::staticAddOneToInt_int"]) { + if (idx == s_methods["TInterpreter::ProcessLine_cchar*"]) { + assert(self && nargs == 1); + result = ((dummy::TInterpreter*)self)->ProcessLine( + (const char*)(*(intptr_t*)&((CPPYY_G__value*)args)[0])); + } else if (idx == s_methods["static_example01::staticAddOneToInt_int"]) { assert(!self && nargs == 1); result = dummy::example01::staticAddOneToInt(((CPPYY_G__value*)args)[0].obj.in); } else if (idx == s_methods["static_example01::staticAddOneToInt_int_int"]) { @@ -622,6 +772,12 @@ int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* ar } else if (idx == s_methods["CppyyTestData::get_int"]) { assert(self && nargs == 0); result = ((dummy::CppyyTestData*)self)->get_int(); + } else if (idx == s_methods["std::complex<int>::real"]) { + assert(self && nargs == 0); + result = ((std::complex<int>*)self)->real(); + } else if (idx == s_methods["std::complex<int>::imag"]) { + assert(self && nargs == 0); + result = ((std::complex<int>*)self)->imag(); } else { assert(!"method unknown in cppyy_call_i"); } @@ -631,23 +787,15 @@ int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* ar long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { long result = 0; Cppyy_PseudoMethodInfo* idx = (Cppyy_PseudoMethodInfo*)method; - if (idx == s_methods["static_example01::staticStrcpy_cchar*"]) { - assert(!self && nargs == 1); - result = (long)dummy::example01::staticStrcpy( - (const char*)(*(intptr_t*)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["static_example01::staticCyclePayload_payload*_double"]) { - assert(!self && nargs == 2); - result = (long)dummy::example01::staticCyclePayload( - (dummy::payload*)(*(intptr_t*)&((CPPYY_G__value*)args)[0]), - ((CPPYY_G__value*)args)[1].obj.d); - } else if (idx == s_methods["example01::addToStringValue_cchar*"]) { - assert(self && nargs == 1); - result = (long)((dummy::example01*)self)->addToStringValue( - (const char*)(*(intptr_t*)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["example01::cyclePayload_payload*"]) { - assert(self && nargs == 1); - result = (long)((dummy::example01*)self)->cyclePayload( - (dummy::payload*)(*(intptr_t*)&((CPPYY_G__value*)args)[0])); + if (idx == s_methods["CppyyTestData::get_wchar"]) { + assert(self && nargs == 0); + result = (long)((dummy::CppyyTestData*)self)->get_wchar(); + } else if (idx == s_methods["CppyyTestData::get_char16"]) { + assert(self && nargs == 0); + result = (long)((dummy::CppyyTestData*)self)->get_char16(); + } else if (idx == s_methods["CppyyTestData::get_char32"]) { + assert(self && nargs == 0); + result = (long)((dummy::CppyyTestData*)self)->get_char32(); } else if (idx == s_methods["CppyyTestData::get_uint"]) { assert(self && nargs == 0); result = (long)((dummy::CppyyTestData*)self)->get_uint(); @@ -657,118 +805,6 @@ long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* a } else if (idx == s_methods["CppyyTestData::get_ulong"]) { assert(self && nargs == 0); result = (long)((dummy::CppyyTestData*)self)->get_ulong(); - } else if (idx == s_methods["CppyyTestData::get_bool_array"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_bool_array(); - } else if (idx == s_methods["CppyyTestData::get_bool_array2"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_bool_array2(); - } else if (idx == s_methods["CppyyTestData::get_uchar_array"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_uchar_array(); - } else if (idx == s_methods["CppyyTestData::get_uchar_array2"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_uchar_array2(); - } else if (idx == s_methods["CppyyTestData::get_short_array"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_short_array(); - } else if (idx == s_methods["CppyyTestData::get_short_array2"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_short_array2(); - } else if (idx == s_methods["CppyyTestData::get_ushort_array"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_ushort_array(); - } else if (idx == s_methods["CppyyTestData::get_ushort_array2"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_ushort_array2(); - } else if (idx == s_methods["CppyyTestData::get_int_array"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_int_array(); - } else if (idx == s_methods["CppyyTestData::get_int_array2"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_int_array2(); - } else if (idx == s_methods["CppyyTestData::get_uint_array"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_uint_array(); - } else if (idx == s_methods["CppyyTestData::get_uint_array2"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_uint_array2(); - } else if (idx == s_methods["CppyyTestData::get_long_array"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_long_array(); - } else if (idx == s_methods["CppyyTestData::get_long_array2"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_long_array2(); - } else if (idx == s_methods["CppyyTestData::get_ulong_array"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_ulong_array(); - } else if (idx == s_methods["CppyyTestData::get_ulong_array2"]) { - assert(self && nargs == 0); - result = (long)((dummy::CppyyTestData*)self)->get_ulong_array2(); - } else if (idx == s_methods["CppyyTestData::pass_array_short"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_array( - (*(short**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_void_array_h"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_void_array_h( - (*(short**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_array_ushort"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_array( - (*(unsigned short**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_void_array_H"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_void_array_H( - (*(unsigned short**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_array_int"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_array( - (*(int**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_void_array_i"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_void_array_i( - (*(int**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_array_uint"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_array( - (*(unsigned int**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_void_array_I"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_void_array_I( - (*(unsigned int**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_array_long"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_array( - (*(long**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_void_array_l"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_void_array_l( - (*(intptr_t**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_array_ulong"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_array( - (*(unsigned long**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_void_array_L"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_void_array_L( - (*(uintptr_t**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_array_float"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_array( - (*(float**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_void_array_f"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_void_array_f( - (*(float**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_array_double"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_array( - (*(double**)&((CPPYY_G__value*)args)[0])); - } else if (idx == s_methods["CppyyTestData::pass_void_array_d"]) { - assert(self && nargs == 1); - result = (long)((dummy::CppyyTestData*)self)->pass_void_array_d( - (*(double**)&((CPPYY_G__value*)args)[0])); } else { assert(!"method unknown in cppyy_call_l"); } @@ -817,6 +853,12 @@ double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* } else if (idx == s_methods["CppyyTestData::get_double"]) { assert(self && nargs == 0); result = ((dummy::CppyyTestData*)self)->get_double(); + } else if (idx == s_methods["std::complex<double>::real"]) { + assert(self && nargs == 0); + result = ((std::complex<double>*)self)->real(); + } else if (idx == s_methods["std::complex<double>::imag"]) { + assert(self && nargs == 0); + result = ((std::complex<double>*)self)->imag(); } else { assert(!"method unknown in cppyy_call_d"); } @@ -844,7 +886,7 @@ double cppyy_call_nld(cppyy_method_t method, cppyy_object_t self, int nargs, voi } #define DISPATCH_CALL_R_GET(tpname) \ - else if (idx == s_methods["CppyyTestData::get_"#tpname"_r"]) { \ + else if (idx == s_methods["CppyyTestData::get_"#tpname"_r"]) { \ assert(self && nargs == 0); \ result = (void*)&((dummy::CppyyTestData*)self)->get_##tpname##_r(); \ } else if (idx == s_methods["CppyyTestData::get_"#tpname"_cr"]) { \ @@ -852,24 +894,68 @@ double cppyy_call_nld(cppyy_method_t method, cppyy_object_t self, int nargs, voi result = (void*)&((dummy::CppyyTestData*)self)->get_##tpname##_cr(); \ } +#define DISPATCH_CALL_R_GET2(tpname) \ + DISPATCH_CALL_R_GET(tpname) \ + else if (idx == s_methods["CppyyTestData::get_"#tpname"_array"]) { \ + assert(self && nargs == 0); \ + result = (void*)((dummy::CppyyTestData*)self)->get_##tpname##_array();\ + } else if (idx == s_methods["CppyyTestData::get_"#tpname"_array2"]) { \ + assert(self && nargs == 0); \ + result = (void*)((dummy::CppyyTestData*)self)->get_##tpname##_array2();\ + } + +#define DISPATCH_CALL_R_GET3(tpname, tpcode, type) \ + DISPATCH_CALL_R_GET2(tpname) \ + else if (idx == s_methods["CppyyTestData::pass_array_"#tpname]) { \ + assert(self && nargs == 1); \ + result = (void*)((dummy::CppyyTestData*)self)->pass_array( \ + (*(type**)&((CPPYY_G__value*)args)[0])); \ + } else if (idx == s_methods["CppyyTestData::pass_void_array_"#tpcode]) { \ + assert(self && nargs == 1); \ + result = (void*)((dummy::CppyyTestData*)self)->pass_void_array_##tpcode (\ + (*(type**)&((CPPYY_G__value*)args)[0])); \ + } + void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { void* result = nullptr; Cppyy_PseudoMethodInfo* idx = (Cppyy_PseudoMethodInfo*)method; - if (0) {} - DISPATCH_CALL_R_GET(bool) - DISPATCH_CALL_R_GET(short) - DISPATCH_CALL_R_GET(ushort) - DISPATCH_CALL_R_GET(int) - DISPATCH_CALL_R_GET(uint) - DISPATCH_CALL_R_GET(long) - DISPATCH_CALL_R_GET(ulong) - DISPATCH_CALL_R_GET(llong) - DISPATCH_CALL_R_GET(ullong) - DISPATCH_CALL_R_GET(long64) - DISPATCH_CALL_R_GET(ulong64) - DISPATCH_CALL_R_GET(float) - DISPATCH_CALL_R_GET(double) - DISPATCH_CALL_R_GET(ldouble) + if (idx == s_methods["static_example01::staticStrcpy_cchar*"]) { + assert(!self && nargs == 1); + result = (void*)dummy::example01::staticStrcpy( + (const char*)(*(intptr_t*)&((CPPYY_G__value*)args)[0])); + } else if (idx == s_methods["static_example01::staticCyclePayload_payload*_double"]) { + assert(!self && nargs == 2); + result = (void*)dummy::example01::staticCyclePayload( + (dummy::payload*)(*(intptr_t*)&((CPPYY_G__value*)args)[0]), + ((CPPYY_G__value*)args)[1].obj.d); + } else if (idx == s_methods["example01::addToStringValue_cchar*"]) { + assert(self && nargs == 1); + result = (void*)((dummy::example01*)self)->addToStringValue( + (const char*)(*(intptr_t*)&((CPPYY_G__value*)args)[0])); + } else if (idx == s_methods["example01::cyclePayload_payload*"]) { + assert(self && nargs == 1); + result = (void*)((dummy::example01*)self)->cyclePayload( + (dummy::payload*)(*(intptr_t*)&((CPPYY_G__value*)args)[0])); + } + DISPATCH_CALL_R_GET2(bool) + DISPATCH_CALL_R_GET (wchar) + DISPATCH_CALL_R_GET (int8) + DISPATCH_CALL_R_GET (uint8) + DISPATCH_CALL_R_GET3(short, h, short) + DISPATCH_CALL_R_GET3(ushort, H, unsigned short) + DISPATCH_CALL_R_GET3(int, i, int) + DISPATCH_CALL_R_GET3(uint, I, unsigned int) + DISPATCH_CALL_R_GET3(long, l, long) + DISPATCH_CALL_R_GET3(ulong, L, unsigned long) + DISPATCH_CALL_R_GET (llong) + DISPATCH_CALL_R_GET (ullong) + DISPATCH_CALL_R_GET (long64) + DISPATCH_CALL_R_GET (ulong64) + DISPATCH_CALL_R_GET3(float, f, float) + DISPATCH_CALL_R_GET3(double, d, double) + DISPATCH_CALL_R_GET (ldouble) + DISPATCH_CALL_R_GET (complex) + DISPATCH_CALL_R_GET (icomplex) else { assert(!"method unknown in cppyy_call_r"); } @@ -904,12 +990,32 @@ cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t handle, int } else if (idx == s_methods["CppyyTestData::CppyyTestData"]) { assert(nargs == 0); result = new dummy::CppyyTestData; + } else if (idx == s_methods["std::complex<double>::complex<double>_double_double"]) { + assert(nargs == 2); + result = new std::complex<double>(((CPPYY_G__value*)args)[0].obj.d, ((CPPYY_G__value*)args)[1].obj.d); + } else if (idx == s_methods["std::complex<int>::complex<int>_int_int"]) { + assert(nargs == 2); + result = new std::complex<int>(((CPPYY_G__value*)args)[0].obj.i, ((CPPYY_G__value*)args)[1].obj.i); } else { assert(!"method unknown in cppyy_constructor"); } return (cppyy_object_t)result; } +cppyy_object_t cppyy_call_o( + cppyy_method_t method, cppyy_object_t self, int nargs, void* args, cppyy_type_t result_type) { + void* result = 0; + Cppyy_PseudoMethodInfo* idx = (Cppyy_PseudoMethodInfo*)method; + if (idx == s_methods["CppyyTestData::get_complex"]) { + assert(self && nargs == 0); + result = new std::complex<double>(((dummy::CppyyTestData*)self)->get_complex()); + } else if (idx == s_methods["CppyyTestData::get_icomplex"]) { + assert(self && nargs == 0); + result = new std::complex<int>(((dummy::CppyyTestData*)self)->get_icomplex()); + } + return (cppyy_object_t)result; +} + cppyy_funcaddr_t cppyy_function_address(cppyy_method_t /* method */) { return (cppyy_funcaddr_t)0; } @@ -940,12 +1046,16 @@ size_t cppyy_function_arg_typeoffset() { /* scope reflection information ------------------------------------------- */ int cppyy_is_namespace(cppyy_scope_t handle) { - if (handle == s_handles["pyzables"]) + if (handle == s_handles[std::string("")] || + handle == s_handles["std"] || + handle == s_handles["pyzables"]) return 1; return 0; } -int cppyy_is_template(const char* /* template_name */) { +int cppyy_is_template(const char* template_name) { + if (strcmp(template_name, "std::complex") == 0) + return 1; return 0; } @@ -970,7 +1080,12 @@ char* cppyy_final_name(cppyy_type_t handle) { } char* cppyy_scoped_final_name(cppyy_type_t handle) { - return cppyy_final_name(handle); + const std::string& rec_name = cppyy_final_name(handle); + if (rec_name == "complex_t") + return cppstring_to_cstring("std::complex<double>"); + else if (rec_name == "icomplex_t") + return cppstring_to_cstring("std::complex<int>"); + return cppstring_to_cstring(rec_name); } int cppyy_has_complex_hierarchy(cppyy_type_t /* handle */) { @@ -1029,7 +1144,16 @@ char* cppyy_method_arg_default(cppyy_method_t method, int idx) { return cppstring_to_cstring(""); } -char* cppyy_method_signature(cppyy_method_t, int /* show_formalargs */) { +char* cppyy_method_signature(cppyy_method_t method, int /* show_formalargs */) { + Cppyy_PseudoMethodInfo* idx = (Cppyy_PseudoMethodInfo*)method; + if (idx == s_methods["std::complex<double>::real"]) + return cppstring_to_cstring("()"); + else if (idx == s_methods["std::complex<double>::imag"]) + return cppstring_to_cstring("()"); + else if (idx == s_methods["std::complex<int>::real"]) + return cppstring_to_cstring("()"); + else if (idx == s_methods["std::complex<int>::imag"]) + return cppstring_to_cstring("()"); return cppstring_to_cstring(""); } @@ -1081,6 +1205,8 @@ int cppyy_is_staticmethod(cppyy_method_t method) { /* data member reflection information ------------------------------------- */ int cppyy_num_datamembers(cppyy_scope_t handle) { + if (cppyy_is_namespace(handle)) + return 0; return s_scopes[handle].m_datambrs.size(); } @@ -1096,6 +1222,15 @@ ptrdiff_t cppyy_datamember_offset(cppyy_scope_t handle, int idatambr) { return s_scopes[handle].m_datambrs[idatambr].m_offset; } +int cppyy_datamember_index(cppyy_scope_t handle, const char* name) { + if (handle == s_handles[std::string("")]) { + if (strcmp(name, "N") == 0) return 0; + if (strcmp(name, "gInterpreter") == 0) return 1; + } + + return (int)-1; +} + /* data member properties ------------------------------------------------ */ int cppyy_is_publicdata(cppyy_scope_t /* handle */, cppyy_index_t /* idatambr */) { diff --git a/pypy/module/_cppyy/test/Makefile b/pypy/module/_cppyy/test/Makefile index cdf513b271..2535696b12 100644 --- a/pypy/module/_cppyy/test/Makefile +++ b/pypy/module/_cppyy/test/Makefile @@ -13,9 +13,14 @@ dicts = advancedcppDict.so \ all : $(dicts) -HASGENREFLEX:=$(shell command -v genreflex 2> /dev/null) +cppflags=-O3 -fPIC -rdynamic + +HASCLINGCONFIG:=$(shell command -v cling-config 2> /dev/null) +ifdef HASCLINGCONFIG + cppflags+=$(shell cling-config --cppflags) +endif -cppflags=$(shell cling-config --cppflags) -O3 -fPIC -rdynamic +HASGENREFLEX:=$(shell command -v genreflex 2> /dev/null) ifdef HASGENREFLEX genreflex_flags:=$(shell genreflex --cppflags) cppflags+=$(genreflex_flags) @@ -25,7 +30,7 @@ endif PLATFORM := $(shell uname -s) ifeq ($(PLATFORM),Darwin) - cppflags+=-dynamiclib -single_module -undefined dynamic_lookup + cppflags+=-dynamiclib -single_module -arch x86_64 -undefined dynamic_lookup -Wno-delete-non-virtual-dtor endif diff --git a/pypy/module/_cppyy/test/datatypes.cxx b/pypy/module/_cppyy/test/datatypes.cxx index 9d6143c7c5..aebfc7c8b6 100644 --- a/pypy/module/_cppyy/test/datatypes.cxx +++ b/pypy/module/_cppyy/test/datatypes.cxx @@ -8,60 +8,80 @@ std::vector<EFruit> vecFruits{kCitrus, kApple}; //=========================================================================== CppyyTestData::CppyyTestData() : m_const_int(17), m_owns_arrays(false) { - m_bool = false; - m_char = 'a'; - m_schar = 'b'; - m_uchar = 'c'; - m_short = -11; - m_ushort = 11u; - m_int = -22; - m_uint = 22u; - m_long = -33l; - m_ulong = 33ul; - m_llong = -44ll; - m_ullong = 44ull; - m_long64 = -55ll; - m_ulong64 = 55ull; - m_float = -66.f; - m_double = -77.; - m_ldouble = -88.l; - m_enum = kNothing; - 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]; - m_uint_array2 = new unsigned int[N]; - m_long_array2 = new long[N]; - m_ulong_array2 = new unsigned long[N]; - - m_float_array2 = new float[N]; - m_double_array2 = new double[N]; + m_bool = false; + m_char = 'a'; + m_schar = 'b'; + m_uchar = 'c'; + m_wchar = L'D'; + m_char16 = u'\u00df'; + m_char32 = U'\u00df'; +#if __cplusplus > 201402L + m_byte = (std::byte)'d'; +#endif + m_int8 = -9; + m_uint8 = 9; + m_short = -11; + m_ushort = 11u; + m_int = -22; + m_uint = 22u; + m_long = -33l; + m_ulong = 33ul; + m_llong = -44ll; + m_ullong = 44ull; + m_long64 = -55ll; + m_ulong64 = 55ull; + m_float = -66.f; + m_double = -77.; + m_ldouble = -88.l; + m_complex = {99., 101.}; + m_icomplex = {121, 141}; + m_enum = kNothing; + m_voidp = (void*)0; + + m_bool_array2 = new bool[N]; + m_schar_array2 = new signed char[N]; + m_uchar_array2 = new unsigned char[N]; +#if __cplusplus > 201402L + m_byte_array2 = new std::byte[N]; +#endif + m_short_array2 = new short[N]; + m_ushort_array2 = new unsigned short[N]; + m_int_array2 = new int[N]; + m_uint_array2 = new unsigned int[N]; + m_long_array2 = new long[N]; + m_ulong_array2 = new unsigned long[N]; + + m_float_array2 = new float[N]; + m_double_array2 = new double[N]; + m_complex_array2 = new complex_t[N]; 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; - m_ushort_array2[i] = 4u*i; - m_int_array[i] = -5*i; - m_int_array2[i] = -6*i; - m_uint_array[i] = 7u*i; - m_uint_array2[i] = 8u*i; - m_long_array[i] = -9l*i; - m_long_array2[i] = -10l*i; - m_ulong_array[i] = 11ul*i; - m_ulong_array2[i] = 12ul*i; - - m_float_array[i] = -13.f*i; - m_float_array2[i] = -14.f*i; - m_double_array[i] = -15.*i; - m_double_array2[i] = -16.*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; +#if __cplusplus > 201402L + m_byte_array[i] = (std::byte)(3u*i); + m_byte_array2[i] = (std::byte)(4u*i); +#endif + m_short_array[i] = -1*i; + m_short_array2[i] = -2*i; + m_ushort_array[i] = 3u*i; + m_ushort_array2[i] = 4u*i; + m_int_array[i] = -5*i; + m_int_array2[i] = -6*i; + m_uint_array[i] = 7u*i; + m_uint_array2[i] = 8u*i; + m_long_array[i] = -9l*i; + m_long_array2[i] = -10l*i; + m_ulong_array[i] = 11ul*i; + m_ulong_array2[i] = 12ul*i; + + m_float_array[i] = -13.f*i; + m_float_array2[i] = -14.f*i; + m_double_array[i] = -15.*i; + m_double_array2[i] = -16.*i; + m_complex_array2[i] = {17.*i, 18.*i}; } m_owns_arrays = true; @@ -81,6 +101,9 @@ void CppyyTestData::destroy_arrays() { if (m_owns_arrays == true) { delete[] m_bool_array2; delete[] m_uchar_array2; +#if __cplusplus > 201402L + delete[] m_byte_array2; +#endif delete[] m_short_array2; delete[] m_ushort_array2; delete[] m_int_array2; @@ -90,37 +113,54 @@ void CppyyTestData::destroy_arrays() { delete[] m_float_array2; delete[] m_double_array2; + delete[] m_complex_array2; m_owns_arrays = false; } } //- getters ----------------------------------------------------------------- -bool CppyyTestData::get_bool() { return m_bool; } -char CppyyTestData::get_char() { return m_char; } -signed char CppyyTestData::get_schar() { return m_schar; } -unsigned char CppyyTestData::get_uchar() { return m_uchar; } -short CppyyTestData::get_short() { return m_short; } -unsigned short CppyyTestData::get_ushort() { return m_ushort; } -int CppyyTestData::get_int() { return m_int; } -unsigned int CppyyTestData::get_uint() { return m_uint; } -long CppyyTestData::get_long() { return m_long; } -unsigned long CppyyTestData::get_ulong() { return m_ulong; } -long long CppyyTestData::get_llong() { return m_llong; } -unsigned long long CppyyTestData::get_ullong() { return m_ullong; } -Long64_t CppyyTestData::get_long64() { return m_long64; } -ULong64_t CppyyTestData::get_ulong64() { return m_ulong64; } -float CppyyTestData::get_float() { return m_float; } -double CppyyTestData::get_double() { return m_double; } -long double CppyyTestData::get_ldouble() { return m_ldouble; } +bool CppyyTestData::get_bool() { return m_bool; } +char CppyyTestData::get_char() { return m_char; } +signed char CppyyTestData::get_schar() { return m_schar; } +unsigned char CppyyTestData::get_uchar() { return m_uchar; } +wchar_t CppyyTestData::get_wchar() { return m_wchar; } +char16_t CppyyTestData::get_char16() { return m_char16; } +char32_t CppyyTestData::get_char32() { return m_char32; } +#if __cplusplus > 201402L +std::byte CppyyTestData::get_byte() { return m_byte; } +#endif +int8_t CppyyTestData::get_int8() { return m_int8; } +uint8_t CppyyTestData::get_uint8() { return m_uint8; } +short CppyyTestData::get_short() { return m_short; } +unsigned short CppyyTestData::get_ushort() { return m_ushort; } +int CppyyTestData::get_int() { return m_int; } +unsigned int CppyyTestData::get_uint() { return m_uint; } +long CppyyTestData::get_long() { return m_long; } +unsigned long CppyyTestData::get_ulong() { return m_ulong; } +long long CppyyTestData::get_llong() { return m_llong; } +unsigned long long CppyyTestData::get_ullong() { return m_ullong; } +Long64_t CppyyTestData::get_long64() { return m_long64; } +ULong64_t CppyyTestData::get_ulong64() { return m_ulong64; } +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; } +complex_t CppyyTestData::get_complex() { return m_complex; } +icomplex_t CppyyTestData::get_icomplex() { return m_icomplex; } +CppyyTestData::EWhat CppyyTestData::get_enum() { return m_enum; } +void* CppyyTestData::get_voidp() { return m_voidp; } bool* CppyyTestData::get_bool_array() { return m_bool_array; } bool* CppyyTestData::get_bool_array2() { return m_bool_array2; } +signed char* CppyyTestData::get_schar_array() { return m_schar_array; } +signed char* CppyyTestData::get_schar_array2() { return m_schar_array2; } unsigned char* CppyyTestData::get_uchar_array() { return m_uchar_array; } unsigned char* CppyyTestData::get_uchar_array2() { return m_uchar_array2; } +#if __cplusplus > 201402L +std::byte* CppyyTestData::get_byte_array() { return m_byte_array; } +std::byte* CppyyTestData::get_byte_array2() { return m_byte_array2; } +#endif 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; } @@ -134,10 +174,12 @@ long* CppyyTestData::get_long_array2() { return m_long_array2; } unsigned long* CppyyTestData::get_ulong_array() { return m_ulong_array; } unsigned long* CppyyTestData::get_ulong_array2() { return m_ulong_array2; } -float* CppyyTestData::get_float_array() { return m_float_array; } -float* CppyyTestData::get_float_array2() { return m_float_array2; } -double* CppyyTestData::get_double_array() { return m_double_array; } -double* CppyyTestData::get_double_array2() { return m_double_array2; } +float* CppyyTestData::get_float_array() { return m_float_array; } +float* CppyyTestData::get_float_array2() { return m_float_array2; } +double* CppyyTestData::get_double_array() { return m_double_array; } +double* CppyyTestData::get_double_array2() { return m_double_array2; } +complex_t* CppyyTestData::get_complex_array() { return m_complex_array; } +complex_t* CppyyTestData::get_complex_array2() { return m_complex_array2; } CppyyTestPod CppyyTestData::get_pod_val() { return m_pod; } CppyyTestPod* CppyyTestData::get_pod_val_ptr() { return &m_pod; } @@ -147,65 +189,95 @@ CppyyTestPod*& CppyyTestData::get_pod_ptrref() { return m_ppod; } CppyyTestPod* CppyyTestData::get_pod_ptr() { return m_ppod; } //- getters const-ref ------------------------------------------------------- -const bool& CppyyTestData::get_bool_cr() { return m_bool; } -const char& CppyyTestData::get_char_cr() { return m_char; } -const signed char& CppyyTestData::get_schar_cr() { return m_schar; } -const unsigned char& CppyyTestData::get_uchar_cr() { return m_uchar; } -const short& CppyyTestData::get_short_cr() { return m_short; } -const unsigned short& CppyyTestData::get_ushort_cr() { return m_ushort; } -const int& CppyyTestData::get_int_cr() { return m_int; } -const unsigned int& CppyyTestData::get_uint_cr() { return m_uint; } -const long& CppyyTestData::get_long_cr() { return m_long; } -const unsigned long& CppyyTestData::get_ulong_cr() { return m_ulong; } -const long long& CppyyTestData::get_llong_cr() { return m_llong; } -const unsigned long long& CppyyTestData::get_ullong_cr() { return m_ullong; } -const Long64_t& CppyyTestData::get_long64_cr() { return m_long64; } -const ULong64_t& CppyyTestData::get_ulong64_cr() { return m_ulong64; } -const float& CppyyTestData::get_float_cr() { return m_float; } -const double& CppyyTestData::get_double_cr() { return m_double; } -const long double& CppyyTestData::get_ldouble_cr() { return m_ldouble; } -const CppyyTestData::EWhat& CppyyTestData::get_enum_cr() { return m_enum; } +const bool& CppyyTestData::get_bool_cr() { return m_bool; } +const char& CppyyTestData::get_char_cr() { return m_char; } +const signed char& CppyyTestData::get_schar_cr() { return m_schar; } +const unsigned char& CppyyTestData::get_uchar_cr() { return m_uchar; } +const wchar_t& CppyyTestData::get_wchar_cr() { return m_wchar; } +const char16_t& CppyyTestData::get_char16_cr() { return m_char16; } +const char32_t& CppyyTestData::get_char32_cr() { return m_char32; } +#if __cplusplus > 201402L +const std::byte& CppyyTestData::get_byte_cr() { return m_byte; } +#endif +const int8_t& CppyyTestData::get_int8_cr() { return m_int8; } +const uint8_t& CppyyTestData::get_uint8_cr() { return m_uint8; } +const short& CppyyTestData::get_short_cr() { return m_short; } +const unsigned short& CppyyTestData::get_ushort_cr() { return m_ushort; } +const int& CppyyTestData::get_int_cr() { return m_int; } +const unsigned int& CppyyTestData::get_uint_cr() { return m_uint; } +const long& CppyyTestData::get_long_cr() { return m_long; } +const unsigned long& CppyyTestData::get_ulong_cr() { return m_ulong; } +const long long& CppyyTestData::get_llong_cr() { return m_llong; } +const unsigned long long& CppyyTestData::get_ullong_cr() { return m_ullong; } +const Long64_t& CppyyTestData::get_long64_cr() { return m_long64; } +const ULong64_t& CppyyTestData::get_ulong64_cr() { return m_ulong64; } +const float& CppyyTestData::get_float_cr() { return m_float; } +const double& CppyyTestData::get_double_cr() { return m_double; } +const long double& CppyyTestData::get_ldouble_cr() { return m_ldouble; } +const complex_t& CppyyTestData::get_complex_cr() { return m_complex; } +const icomplex_t& CppyyTestData::get_icomplex_cr() { return m_icomplex; } +const CppyyTestData::EWhat& CppyyTestData::get_enum_cr() { return m_enum; } //- getters ref ------------------------------------------------------------- -bool& CppyyTestData::get_bool_r() { return m_bool; } -char& CppyyTestData::get_char_r() { return m_char; } -signed char& CppyyTestData::get_schar_r() { return m_schar; } -unsigned char& CppyyTestData::get_uchar_r() { return m_uchar; } -short& CppyyTestData::get_short_r() { return m_short; } -unsigned short& CppyyTestData::get_ushort_r() { return m_ushort; } -int& CppyyTestData::get_int_r() { return m_int; } -unsigned int& CppyyTestData::get_uint_r() { return m_uint; } -long& CppyyTestData::get_long_r() { return m_long; } -unsigned long& CppyyTestData::get_ulong_r() { return m_ulong; } -long long& CppyyTestData::get_llong_r() { return m_llong; } -unsigned long long& CppyyTestData::get_ullong_r() { return m_ullong; } -Long64_t& CppyyTestData::get_long64_r() { return m_long64; } -ULong64_t& CppyyTestData::get_ulong64_r() { return m_ulong64; } -float& CppyyTestData::get_float_r() { return m_float; } -double& CppyyTestData::get_double_r() { return m_double; } -long double& CppyyTestData::get_ldouble_r() { return m_ldouble; } -CppyyTestData::EWhat& CppyyTestData::get_enum_r() { return m_enum; } +bool& CppyyTestData::get_bool_r() { return m_bool; } +char& CppyyTestData::get_char_r() { return m_char; } +signed char& CppyyTestData::get_schar_r() { return m_schar; } +unsigned char& CppyyTestData::get_uchar_r() { return m_uchar; } +wchar_t& CppyyTestData::get_wchar_r() { return m_wchar; } +char16_t& CppyyTestData::get_char16_r() { return m_char16; } +char32_t& CppyyTestData::get_char32_r() { return m_char32; } +#if __cplusplus > 201402L +std::byte& CppyyTestData::get_byte_r() { return m_byte; } +#endif +int8_t& CppyyTestData::get_int8_r() { return m_int8; } +uint8_t& CppyyTestData::get_uint8_r() { return m_uint8; } +short& CppyyTestData::get_short_r() { return m_short; } +unsigned short& CppyyTestData::get_ushort_r() { return m_ushort; } +int& CppyyTestData::get_int_r() { return m_int; } +unsigned int& CppyyTestData::get_uint_r() { return m_uint; } +long& CppyyTestData::get_long_r() { return m_long; } +unsigned long& CppyyTestData::get_ulong_r() { return m_ulong; } +long long& CppyyTestData::get_llong_r() { return m_llong; } +unsigned long long& CppyyTestData::get_ullong_r() { return m_ullong; } +Long64_t& CppyyTestData::get_long64_r() { return m_long64; } +ULong64_t& CppyyTestData::get_ulong64_r() { return m_ulong64; } +float& CppyyTestData::get_float_r() { return m_float; } +double& CppyyTestData::get_double_r() { return m_double; } +long double& CppyyTestData::get_ldouble_r() { return m_ldouble; } +complex_t& CppyyTestData::get_complex_r() { return m_complex; } +icomplex_t& CppyyTestData::get_icomplex_r() { return m_icomplex; } +CppyyTestData::EWhat& CppyyTestData::get_enum_r() { return m_enum; } //- setters ----------------------------------------------------------------- -void CppyyTestData::set_bool(bool b) { m_bool = b; } -void CppyyTestData::set_char(char c) { m_char = c; } -void CppyyTestData::set_schar(signed char sc) { m_schar = sc; } -void CppyyTestData::set_uchar(unsigned char uc) { m_uchar = uc; } -void CppyyTestData::set_short(short s) { m_short = s; } -void CppyyTestData::set_ushort(unsigned short us) { m_ushort = us; } -void CppyyTestData::set_int(int i) { m_int = i; } -void CppyyTestData::set_uint(unsigned int ui) { m_uint = ui; } -void CppyyTestData::set_long(long l) { m_long = l; } -void CppyyTestData::set_ulong(unsigned long ul) { m_ulong = ul; } -void CppyyTestData::set_llong(long long ll) { m_llong = ll; } -void CppyyTestData::set_ullong(unsigned long long ull) { m_ullong = ull; } -void CppyyTestData::set_long64(Long64_t l64) { m_long64 = l64; } -void CppyyTestData::set_ulong64(ULong64_t ul64) { m_ulong64 = ul64; } -void CppyyTestData::set_float(float f) { m_float = f; } -void CppyyTestData::set_double(double d) { m_double = d; } -void CppyyTestData::set_ldouble(long double ld) { m_ldouble = ld; } -void CppyyTestData::set_enum(EWhat w) { m_enum = w; } -void CppyyTestData::set_voidp(void* p) { m_voidp = p; } +void CppyyTestData::set_bool(bool b) { m_bool = b; } +void CppyyTestData::set_char(char c) { m_char = c; } +void CppyyTestData::set_schar(signed char sc) { m_schar = sc; } +void CppyyTestData::set_uchar(unsigned char uc) { m_uchar = uc; } +void CppyyTestData::set_wchar(wchar_t wc) { m_wchar = wc; } +void CppyyTestData::set_char16(char16_t c16) { m_char16 = c16; } +void CppyyTestData::set_char32(char32_t c32) { m_char32 = c32; } +#if __cplusplus > 201402L +void CppyyTestData::set_byte(std::byte b) { m_byte = b; } +#endif +void CppyyTestData::set_int8(int8_t s8) { m_int8 = s8; } +void CppyyTestData::set_uint8(uint8_t u8) { m_uint8 = u8; } +void CppyyTestData::set_short(short s) { m_short = s; } +void CppyyTestData::set_ushort(unsigned short us) { m_ushort = us; } +void CppyyTestData::set_int(int i) { m_int = i; } +void CppyyTestData::set_uint(unsigned int ui) { m_uint = ui; } +void CppyyTestData::set_long(long l) { m_long = l; } +void CppyyTestData::set_ulong(unsigned long ul) { m_ulong = ul; } +void CppyyTestData::set_llong(long long ll) { m_llong = ll; } +void CppyyTestData::set_ullong(unsigned long long ull) { m_ullong = ull; } +void CppyyTestData::set_long64(Long64_t l64) { m_long64 = l64; } +void CppyyTestData::set_ulong64(ULong64_t ul64) { m_ulong64 = ul64; } +void CppyyTestData::set_float(float f) { m_float = f; } +void CppyyTestData::set_double(double d) { m_double = d; } +void CppyyTestData::set_ldouble(long double ld) { m_ldouble = ld; } +void CppyyTestData::set_complex(complex_t cd) { m_complex = cd; } +void CppyyTestData::set_icomplex(icomplex_t ci) { m_icomplex = ci; } +void CppyyTestData::set_enum(EWhat w) { m_enum = w; } +void CppyyTestData::set_voidp(void* p) { m_voidp = p; } void CppyyTestData::set_pod_val(CppyyTestPod p) { m_pod = p; } void CppyyTestData::set_pod_ptr_in(CppyyTestPod* pp) { m_pod = *pp; } @@ -220,24 +292,233 @@ void CppyyTestData::set_pod_void_ptrptr_out(void** pp) { delete *((CppyyTe void CppyyTestData::set_pod_ptr(CppyyTestPod* pp) { m_ppod = pp; } //- setters const-ref ------------------------------------------------------- -void CppyyTestData::set_bool_cr(const bool& b) { m_bool = b; } -void CppyyTestData::set_char_cr(const char& c) { m_char = c; } -void CppyyTestData::set_schar_cr(const signed char& sc) { m_schar = sc; } -void CppyyTestData::set_uchar_cr(const unsigned char& uc) { m_uchar = uc; } -void CppyyTestData::set_short_cr(const short& s) { m_short = s; } -void CppyyTestData::set_ushort_cr(const unsigned short& us) { m_ushort = us; } -void CppyyTestData::set_int_cr(const int& i) { m_int = i; } -void CppyyTestData::set_uint_cr(const unsigned int& ui) { m_uint = ui; } -void CppyyTestData::set_long_cr(const long& l) { m_long = l; } -void CppyyTestData::set_ulong_cr(const unsigned long& ul) { m_ulong = ul; } -void CppyyTestData::set_llong_cr(const long long& ll) { m_llong = ll; } -void CppyyTestData::set_ullong_cr(const unsigned long long& ull) { m_ullong = ull; } -void CppyyTestData::set_long64_cr(const Long64_t& l64) { m_long64 = l64; } -void CppyyTestData::set_ulong64_cr(const ULong64_t& ul64) { m_ulong64 = ul64; } -void CppyyTestData::set_float_cr(const float& f) { m_float = f; } -void CppyyTestData::set_double_cr(const double& d) { m_double = d; } -void CppyyTestData::set_ldouble_cr(const long double& ld) { m_ldouble = ld; } -void CppyyTestData::set_enum_cr(const EWhat& w) { m_enum = w; } +void CppyyTestData::set_bool_cr(const bool& b) { m_bool = b; } +void CppyyTestData::set_char_cr(const char& c) { m_char = c; } +void CppyyTestData::set_schar_cr(const signed char& sc) { m_schar = sc; } +void CppyyTestData::set_uchar_cr(const unsigned char& uc) { m_uchar = uc; } +void CppyyTestData::set_wchar_cr(const wchar_t& wc) { m_wchar = wc; } +void CppyyTestData::set_char16_cr(const char16_t& c16) { m_char16 = c16; } +void CppyyTestData::set_char32_cr(const char32_t& c32) { m_char32 = c32; } +#if __cplusplus > 201402L +void CppyyTestData::set_byte_cr(const std::byte& b) { m_byte = b; } +#endif +void CppyyTestData::set_int8_cr(const int8_t& s8) { m_int8 = s8; } +void CppyyTestData::set_uint8_cr(const uint8_t& u8) { m_uint8 = u8; } +void CppyyTestData::set_short_cr(const short& s) { m_short = s; } +void CppyyTestData::set_ushort_cr(const unsigned short& us) { m_ushort = us; } +void CppyyTestData::set_int_cr(const int& i) { m_int = i; } +void CppyyTestData::set_uint_cr(const unsigned int& ui) { m_uint = ui; } +void CppyyTestData::set_long_cr(const long& l) { m_long = l; } +void CppyyTestData::set_ulong_cr(const unsigned long& ul) { m_ulong = ul; } +void CppyyTestData::set_llong_cr(const long long& ll) { m_llong = ll; } +void CppyyTestData::set_ullong_cr(const unsigned long long& ull) { m_ullong = ull; } +void CppyyTestData::set_long64_cr(const Long64_t& l64) { m_long64 = l64; } +void CppyyTestData::set_ulong64_cr(const ULong64_t& ul64) { m_ulong64 = ul64; } +void CppyyTestData::set_float_cr(const float& f) { m_float = f; } +void CppyyTestData::set_double_cr(const double& d) { m_double = d; } +void CppyyTestData::set_ldouble_cr(const long double& ld) { m_ldouble = ld; } +void CppyyTestData::set_complex_cr(const complex_t& cd) { m_complex = cd; } +void CppyyTestData::set_icomplex_cr(const icomplex_t& ci) { m_icomplex = ci; } +void CppyyTestData::set_enum_cr(const EWhat& w) { m_enum = w; } + +//- setters ref ------------------------------------------------------------- +void CppyyTestData::set_bool_r(bool& b) { b = true; } +void CppyyTestData::set_char_r(char& c) { c = 'a'; } +void CppyyTestData::set_wchar_r(wchar_t& wc) { wc = 'b'; } +void CppyyTestData::set_char16_r(char16_t& c16) { c16 = u'\u6c24'; } +void CppyyTestData::set_char32_r(char32_t& c32) { c32 = U'\U0001f34e'; } +void CppyyTestData::set_schar_r(signed char& sc) { sc = 'c'; } +void CppyyTestData::set_uchar_r(unsigned char& uc) { uc = 'd'; } +#if __cplusplus > 201402L +void CppyyTestData::set_byte_r(std::byte& b) { b = (std::byte)'e'; } +#endif +void CppyyTestData::set_short_r(short& s) { s = -1; } +void CppyyTestData::set_ushort_r(unsigned short& us) { us = 2; } +void CppyyTestData::set_int_r(int& i) { i = -3; } +void CppyyTestData::set_uint_r(unsigned int& ui) { ui = 4; } +void CppyyTestData::set_long_r(long& l) { l = -5; } +void CppyyTestData::set_ulong_r(unsigned long& ul) { ul = 6; } +void CppyyTestData::set_llong_r(long long& ll) { ll = -7; } +void CppyyTestData::set_ullong_r(unsigned long long& ull) { ull = 8; } +void CppyyTestData::set_float_r(float& f) { f = 5.f; } +void CppyyTestData::set_double_r(double& d) { d = -5.; } +void CppyyTestData::set_ldouble_r(long double& ld) { ld = 10.l; } + +//- setters ptr ------------------------------------------------------------- +void CppyyTestData::set_bool_p(bool* b) { *b = true; } +void CppyyTestData::set_char_p(char* c) { *c = 'a'; } +void CppyyTestData::set_wchar_p(wchar_t* wc) { *wc = 'b'; } +void CppyyTestData::set_char16_p(char16_t* c16) { *c16 = u'\u6c24'; } +void CppyyTestData::set_char32_p(char32_t* c32) { *c32 = U'\U0001f34e'; } +void CppyyTestData::set_schar_p(signed char* sc) { *sc = 'c'; } +void CppyyTestData::set_uchar_p(unsigned char* uc) { *uc = 'd'; } +#if __cplusplus > 201402L +void CppyyTestData::set_byte_p(std::byte* b) { *b = (std::byte)'e'; } +#endif +void CppyyTestData::set_short_p(short* s) { *s = -1; } +void CppyyTestData::set_ushort_p(unsigned short* us) { *us = 2; } +void CppyyTestData::set_int_p(int* i) { *i = -3; } +void CppyyTestData::set_uint_p(unsigned int* ui) { *ui = 4; } +void CppyyTestData::set_long_p(long* l) { *l = -5; } +void CppyyTestData::set_ulong_p(unsigned long* ul) { *ul = 6; } +void CppyyTestData::set_llong_p(long long* ll) { *ll = -7; } +void CppyyTestData::set_ullong_p(unsigned long long* ull) { *ull = 8; } +void CppyyTestData::set_float_p(float* f) { *f = 5.f; } +void CppyyTestData::set_double_p(double* d) { *d = -5.; } +void CppyyTestData::set_ldouble_p(long double* ld) { *ld = 10.l; } + +//- setters ptrptr ---------------------------------------------------------- +void CppyyTestData::set_bool_ppa(bool** b) { + (*b) = new bool[3]; + (*b)[0] = true; (*b)[1] = false; (*b)[2] = true; +} +void CppyyTestData::set_char_ppa(char** c) { + (*c) = new char[3]; + (*c)[0] = 'a'; (*c)[1] = 'b'; (*c)[2] = 'c'; +} +void CppyyTestData::set_wchar_ppa(wchar_t** wc) { + (*wc) = new wchar_t[3]; + (*wc)[0] = 'd'; (*wc)[1] = 'e'; (*wc)[2] = 'f'; +} +void CppyyTestData::set_char16_ppa(char16_t** c16) { + (*c16) = new char16_t[3]; + (*c16)[0] = u'\u6c24'; (*c16)[1] = u'\u6c25'; (*c16)[2] = u'\u6c26'; +} +void CppyyTestData::set_char32_ppa(char32_t** c32) { + (*c32) = new char32_t[3]; + (*c32)[0] = U'\U0001f34d'; (*c32)[1] = U'\U0001f34e'; (*c32)[2] = U'\U0001f34f'; +} +void CppyyTestData::set_schar_ppa(signed char** sc) { + (*sc) = new signed char[3]; + (*sc)[0] = 'g'; (*sc)[1] = 'h'; (*sc)[2] = 'j'; +} +void CppyyTestData::set_uchar_ppa(unsigned char** uc) { + (*uc) = new unsigned char[3]; + (*uc)[0] = 'k'; (*uc)[1] = 'l'; (*uc)[2] = 'm'; +} +#if __cplusplus > 201402L +void CppyyTestData::set_byte_ppa(std::byte** b) { + (*b) = new std::byte[3]; + (*b)[0] = (std::byte)'n'; (*b)[1] = (std::byte)'o'; (*b)[2] = (std::byte)'p'; +} +#endif +void CppyyTestData::set_short_ppa(short** s) { + (*s) = new short[3]; + (*s)[0] = -1; (*s)[1] = -2; (*s)[2] = -3; +} +void CppyyTestData::set_ushort_ppa(unsigned short** us) { + (*us) = new unsigned short[3]; + (*us)[0] = 4; (*us)[1] = 5; (*us)[2] = 6; +} +void CppyyTestData::set_int_ppa(int** i) { + (*i) = new int[3]; + (*i)[0] = -7; (*i)[1] = -8; (*i)[2] = -9; +} +void CppyyTestData::set_uint_ppa(unsigned int** ui) { + (*ui) = new unsigned int[3]; + (*ui)[0] = 10; (*ui)[1] = 11; (*ui)[2] = 12; +} +void CppyyTestData::set_long_ppa(long** l) { + (*l) = new long[3]; + (*l)[0] = -13; (*l)[1] = -14; (*l)[2] = -15; +} +void CppyyTestData::set_ulong_ppa(unsigned long** ul) { + (*ul) = new unsigned long[3]; + (*ul)[0] = 16; (*ul)[1] = 17; (*ul)[2] = 18; +} +void CppyyTestData::set_llong_ppa(long long** ll) { + (*ll) = new long long[3]; + (*ll)[0] = -19; (*ll)[1] = -20; (*ll)[2] = -21; +} +void CppyyTestData::set_ullong_ppa(unsigned long long** ull) { + (*ull) = new unsigned long long[3]; + (*ull)[0] = 22; (*ull)[1] = 23; (*ull)[2] = 24; +} +void CppyyTestData::set_float_ppa(float** f) { + (*f) = new float[3]; + (*f)[0] = 5.f; (*f)[1] = 10.f; (*f)[2] = 20.f; +} +void CppyyTestData::set_double_ppa(double** d) { + (*d) = new double[3]; + (*d)[0] = -5; (*d)[1] = -10.; (*d)[2] = -20.; +} +void CppyyTestData::set_ldouble_ppa(long double** ld) { + (*ld) = new long double[3]; + (*ld)[0] = 5.l; (*ld)[1] = 10.f; (*ld)[2] = 20.l; +} + +intptr_t CppyyTestData::set_char_ppm(char** c) { + *c = (char*)malloc(4*sizeof(char)); + return (intptr_t)*c; +} +intptr_t CppyyTestData::set_cchar_ppm(const char** cc) { + *cc = (const char*)malloc(4*sizeof(char)); + return (intptr_t)*cc; +} +intptr_t CppyyTestData::set_wchar_ppm(wchar_t** w) { + *w = (wchar_t*)malloc(4*sizeof(wchar_t)); + return (intptr_t)*w; +} +intptr_t CppyyTestData::set_char16_ppm(char16_t** c16) { + *c16 = (char16_t*)malloc(4*sizeof(char16_t)); + return (intptr_t)*c16; +} +intptr_t CppyyTestData::set_char32_ppm(char32_t** c32) { + *c32 = (char32_t*)malloc(4*sizeof(char32_t)); + return (intptr_t)*c32; +} +intptr_t CppyyTestData::set_cwchar_ppm(const wchar_t** cw) { + *cw = (const wchar_t*)malloc(4*sizeof(wchar_t)); + return (intptr_t)*cw; +} +intptr_t CppyyTestData::set_cchar16_ppm(const char16_t** c16) { + *c16 = (const char16_t*)malloc(4*sizeof(char16_t)); + return (intptr_t)*c16; +} +intptr_t CppyyTestData::set_cchar32_ppm(const char32_t** c32) { + *c32 = (const char32_t*)malloc(4*sizeof(char32_t)); + return (intptr_t)*c32; +} +intptr_t CppyyTestData::set_void_ppm(void** v) { + *v = malloc(4*sizeof(void*)); + return (intptr_t)*v; +} + +intptr_t CppyyTestData::freeit(void* ptr) { + intptr_t out = (intptr_t)ptr; + free(ptr); + return out; +} + +//- setters r-value --------------------------------------------------------- +void CppyyTestData::set_bool_rv(bool&& b) { m_bool = b; } +void CppyyTestData::set_char_rv(char&& c) { m_char = c; } +void CppyyTestData::set_schar_rv(signed char&& sc) { m_schar = sc; } +void CppyyTestData::set_uchar_rv(unsigned char&& uc) { m_uchar = uc; } +void CppyyTestData::set_wchar_rv(wchar_t&& wc) { m_wchar = wc; } +void CppyyTestData::set_char16_rv(char16_t&& c16) { m_char16 = c16; } +void CppyyTestData::set_char32_rv(char32_t&& c32) { m_char32 = c32; } +#if __cplusplus > 201402L +void CppyyTestData::set_byte_rv(std::byte&& b) { m_byte = b; } +#endif +void CppyyTestData::set_int8_rv(int8_t&& s8) { m_int8 = s8; } +void CppyyTestData::set_uint8_rv(uint8_t&& u8) { m_uint8 = u8; } +void CppyyTestData::set_short_rv(short&& s) { m_short = s; } +void CppyyTestData::set_ushort_rv(unsigned short&& us) { m_ushort = us; } +void CppyyTestData::set_int_rv(int&& i) { m_int = i; } +void CppyyTestData::set_uint_rv(unsigned int&& ui) { m_uint = ui; } +void CppyyTestData::set_long_rv(long&& l) { m_long = l; } +void CppyyTestData::set_ulong_rv(unsigned long&& ul) { m_ulong = ul; } +void CppyyTestData::set_llong_rv(long long&& ll) { m_llong = ll; } +void CppyyTestData::set_ullong_rv(unsigned long long&& ull) { m_ullong = ull; } +void CppyyTestData::set_long64_rv(Long64_t&& l64) { m_long64 = l64; } +void CppyyTestData::set_ulong64_rv(ULong64_t&& ul64) { m_ulong64 = ul64; } +void CppyyTestData::set_float_rv(float&& f) { m_float = f; } +void CppyyTestData::set_double_rv(double&& d) { m_double = d; } +void CppyyTestData::set_ldouble_rv(long double&& ld) { m_ldouble = ld; } +void CppyyTestData::set_complex_rv(complex_t&& cd) { m_complex = cd; } +void CppyyTestData::set_icomplex_rv(icomplex_t&& ci) { m_icomplex = ci; } +void CppyyTestData::set_enum_rv(EWhat&& w) { m_enum = w; } //- passers ----------------------------------------------------------------- unsigned char* CppyyTestData::pass_array(unsigned char* a) { return a; } @@ -249,47 +530,66 @@ long* CppyyTestData::pass_array(long* a) { return a; } unsigned long* CppyyTestData::pass_array(unsigned long* a) { return a; } float* CppyyTestData::pass_array(float* a) { return a; } double* CppyyTestData::pass_array(double* a) { return a; } +complex_t* CppyyTestData::pass_array(complex_t* a) { return a; } //- static data members ----------------------------------------------------- -bool CppyyTestData::s_bool = false; -char CppyyTestData::s_char = 'c'; -signed char CppyyTestData::s_schar = 's'; -unsigned char CppyyTestData::s_uchar = 'u'; -short CppyyTestData::s_short = -101; -unsigned short CppyyTestData::s_ushort = 255u; -int CppyyTestData::s_int = -202; -unsigned int CppyyTestData::s_uint = 202u; -long CppyyTestData::s_long = -303l; -unsigned long CppyyTestData::s_ulong = 303ul; -long long CppyyTestData::s_llong = -404ll; -unsigned long long CppyyTestData::s_ullong = 404ull; -Long64_t CppyyTestData::s_long64 = -505ll; -ULong64_t CppyyTestData::s_ulong64 = 505ull; -float CppyyTestData::s_float = -606.f; -double CppyyTestData::s_double = -707.; -long double CppyyTestData::s_ldouble = -808.l; -CppyyTestData::EWhat CppyyTestData::s_enum = CppyyTestData::kNothing; -void* CppyyTestData::s_voidp = (void*)0; +bool CppyyTestData::s_bool = false; +char CppyyTestData::s_char = 'c'; +signed char CppyyTestData::s_schar = 's'; +unsigned char CppyyTestData::s_uchar = 'u'; +wchar_t CppyyTestData::s_wchar = L'U'; +char16_t CppyyTestData::s_char16 = u'\u6c29'; +char32_t CppyyTestData::s_char32 = U'\U0001f34b'; +#if __cplusplus > 201402L +std::byte CppyyTestData::s_byte = (std::byte)'b'; +#endif +int8_t CppyyTestData::s_int8 = - 87; +uint8_t CppyyTestData::s_uint8 = 87; +short CppyyTestData::s_short = -101; +unsigned short CppyyTestData::s_ushort = 255u; +int CppyyTestData::s_int = -202; +unsigned int CppyyTestData::s_uint = 202u; +long CppyyTestData::s_long = -303l; +unsigned long CppyyTestData::s_ulong = 303ul; +long long CppyyTestData::s_llong = -404ll; +unsigned long long CppyyTestData::s_ullong = 404ull; +Long64_t CppyyTestData::s_long64 = -505ll; +ULong64_t CppyyTestData::s_ulong64 = 505ull; +float CppyyTestData::s_float = -606.f; +double CppyyTestData::s_double = -707.; +long double CppyyTestData::s_ldouble = -808.l; +complex_t CppyyTestData::s_complex = {909., -909.}; +icomplex_t CppyyTestData::s_icomplex = {979, -979}; +CppyyTestData::EWhat CppyyTestData::s_enum = CppyyTestData::kNothing; +void* CppyyTestData::s_voidp = (void*)0; +std::string CppyyTestData::s_strv = "Hello"; +std::string* CppyyTestData::s_strp = nullptr; //- strings ----------------------------------------------------------------- -const char* CppyyTestData::get_valid_string(const char* in) { return in; } -const char* CppyyTestData::get_invalid_string() { return (const char*)0; } +const char* CppyyTestData::get_valid_string(const char* in) { return in; } +const char* CppyyTestData::get_invalid_string() { return (const char*)0; } +const wchar_t* CppyyTestData::get_valid_wstring(const wchar_t* in) { return in; } +const wchar_t* CppyyTestData::get_invalid_wstring() { return (const wchar_t*)0; } +const char16_t* CppyyTestData::get_valid_string16(const char16_t* in) { return in; } +const char16_t* CppyyTestData::get_invalid_string16() { return (const char16_t*)0; } +const char32_t* CppyyTestData::get_valid_string32(const char32_t* in) { return in; } +const char32_t* CppyyTestData::get_invalid_string32() { return (const char32_t*)0; } //= global functions ======================================================== -long get_pod_address(CppyyTestData& c) +intptr_t get_pod_address(CppyyTestData& c) { - return (long)&c.m_pod; + return (intptr_t)&c.m_pod; } -long get_int_address(CppyyTestData& c) +intptr_t get_int_address(CppyyTestData& c) { - return (long)&c.m_pod.m_int; + return (intptr_t)&c.m_pod.m_int; } -long get_double_address(CppyyTestData& c) +intptr_t get_double_address(CppyyTestData& c) { - return (long)&c.m_pod.m_double; + return (intptr_t)&c.m_pod.m_double; } @@ -298,6 +598,14 @@ bool g_bool = false; char g_char = 'w'; signed char g_schar = 'v'; unsigned char g_uchar = 'u'; +wchar_t g_wchar = L'U'; +char16_t g_char16 = u'\u6c21'; +char32_t g_char32 = U'\u6c21'; +#if __cplusplus > 201402L +std::byte g_byte = (std::byte)'x'; +#endif +int8_t g_int8 = -66; +uint8_t g_uint8 = 66; short g_short = -88; unsigned short g_ushort = 88u; int g_int = -188; @@ -311,6 +619,8 @@ ULong64_t g_ulong64 = 488ull; float g_float = -588.f; double g_double = -688.; long double g_ldouble = -788.l; +complex_t g_complex = {808., -808.}; +icomplex_t g_icomplex = {909, -909}; EFruit g_enum = kBanana; void* g_voidp = nullptr; @@ -342,16 +652,150 @@ CppyyTestPod* get_null_pod() { return (CppyyTestPod*)0; } +std::string g_some_global_string = "C++"; +std::string get_some_global_string() { return g_some_global_string; } +std::string g_some_global_string2 = "C++"; +std::string get_some_global_string2() { return g_some_global_string2; } + +const char16_t* g_some_global_string16 = u"z\u00df\u6c34"; +const char32_t* g_some_global_string32 = U"z\u00df\u6c34\U0001f34c"; + +std::string SomeStaticDataNS::s_some_static_string = "C++"; +std::string SomeStaticDataNS::get_some_static_string() { return s_some_static_string; } +std::string SomeStaticDataNS::s_some_static_string2 = "C++"; +std::string SomeStaticDataNS::get_some_static_string2() { return s_some_static_string2; } + +StorableData gData{5.}; + + +//= special case of "byte" arrays =========================================== +int64_t sum_uc_data(unsigned char* data, int size) +{ + int64_t total = 0; + for (int i = 0; i < size; ++i) total += int64_t(data[i]); + return total; +} + +#if __cplusplus > 201402L +int64_t sum_byte_data(std::byte* data, int size) +{ + return sum_uc_data((unsigned char*)data, size); +} +#endif + //= function pointer passing ================================================ -int sum_of_int(int i1, int i2) { +int sum_of_int1(int i1, int i2) { return i1+i2; } +int sum_of_int2(int i1, int i2) { + return 2*i1+i2; +} + +int (*sum_of_int_ptr)(int, int) = sum_of_int1; + +int call_sum_of_int(int i1, int i2) { + if (sum_of_int_ptr) + return (*sum_of_int_ptr)(i1, i2); + return -1; +} + double sum_of_double(double d1, double d2) { return d1+d2; } -double call_double_double(double (*d)(double, double), double d1, double d2) { - return d(d1, d2); +double call_double_double(double (*f)(double, double), double d1, double d2) { + if (!f) return -1.; + return f(d1, d2); +} + + +//= callable passing ======================================================== +int call_int_int(int (*f)(int, int), int i1, int i2) { + return f(i1, i2); +} + +void call_void(void (*f)(int), int i) { + f(i); +} + +int call_refi(void (*f)(int&)) { + int i = -1; f(i); return i; +} + +int call_refl(void (*f)(long&)) { + long l = -1L; f(l); return l; +} + +int call_refd(void (*f)(double&)) { + double d = -1.; f(d); return d; +} + + +StoreCallable::StoreCallable(double (*f)(double, double)) : fF(f) { + /* empty */ +} + +void StoreCallable::set_callable(double (*f)(double, double)) { + fF = f; +} + +double StoreCallable::operator()(double d1, double d2) { + return fF(d1, d2); +} + +//= callable through std::function ========================================== +double call_double_double_sf(const std::function<double(double, double)>& f, double d1, double d2) { + return f(d1, d2); +} + +int call_int_int_sf(const std::function<int(int, int)>& f, int i1, int i2) { + return f(i1, i2); +} + +void call_void_sf(const std::function<void(int)>& f, int i) { + f(i); +} + +int call_refi_sf(const std::function<void(int&)>& f) { + int i = -1; f(i); return i; +} + +int call_refl_sf(const std::function<void(long&)>& f) { + long l = -1L; f(l); return l; +} + +int call_refd_sf(const std::function<void(double&)>& f) { + double d = -1.; f(d); return d; +} + + +StoreCallable_sf::StoreCallable_sf(const std::function<double(double, double)>& f) : fF(f) { + /* empty */ } + +void StoreCallable_sf::set_callable(const std::function<double(double, double)>& f) { + fF = f; +} + +double StoreCallable_sf::operator()(double d1, double d2) { + return fF(d1, d2); +} + + +//= array of C strings passing ============================================== +std::vector<std::string> ArrayOfCStrings::takes_array_of_cstrings(const char* args[], int len) +{ + std::vector<std::string> v; + v.reserve(len); + for (int i = 0; i < len; ++i) + v.emplace_back(args[i]); + + return v; +} + + +//= aggregate testing ====================================================== +int AggregateTest::Aggregate1::sInt = 17; +int AggregateTest::Aggregate2::sInt = 27; diff --git a/pypy/module/_cppyy/test/datatypes.h b/pypy/module/_cppyy/test/datatypes.h index 0df18fc68d..0a6cd393a0 100644 --- a/pypy/module/_cppyy/test/datatypes.h +++ b/pypy/module/_cppyy/test/datatypes.h @@ -1,13 +1,21 @@ -// copied from RtypesCore.h ... -#if defined(R__WIN32) && !defined(__CINT__) -typedef __int64 Long64_t; //Portable signed long integer 8 bytes -typedef unsigned __int64 ULong64_t; //Portable unsigned long integer 8 bytes +#ifndef CPPYY_TEST_DATATYPES_H +#define CPPYY_TEST_DATATYPES_H + +#ifdef _WIN32 +typedef __int64 Long64_t; +typedef unsigned __int64 ULong64_t; #else -typedef long long Long64_t; //Portable signed long integer 8 bytes -typedef unsigned long long ULong64_t;//Portable unsigned long integer 8 bytes +typedef long long Long64_t; +typedef unsigned long long ULong64_t; #endif - +#include <cstddef> +#include <cstdint> +#include <complex> +#include <functional> +#include <memory> #include <vector> +#include <wchar.h> +#include <sys/types.h> const int N = 5; @@ -25,6 +33,8 @@ extern std::vector<EFruit> vecFruits; //=========================================================================== +enum class NamedClassEnum { E1 = 42 }; + namespace EnumSpace { enum E {E1 = 1, E2}; class EnumClass { @@ -34,6 +44,8 @@ namespace EnumSpace { }; typedef enum { AA = 1, BB, CC, DD } letter_code; + + enum class NamedClassEnum { E1 = -42 }; } @@ -67,6 +79,9 @@ private: //=========================================================================== +typedef std::complex<double> complex_t; // maps to Py_complex +typedef std::complex<int> icomplex_t; // no equivalent + class CppyyTestData { public: CppyyTestData(); @@ -83,6 +98,14 @@ public: char get_char(); signed char get_schar(); unsigned char get_uchar(); + wchar_t get_wchar(); + char16_t get_char16(); + char32_t get_char32(); +#if __cplusplus > 201402L + std::byte get_byte(); +#endif + int8_t get_int8(); + uint8_t get_uint8(); short get_short(); unsigned short get_ushort(); int get_int(); @@ -96,15 +119,22 @@ public: 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)); + long double get_ldouble_def(long double ld = 1); + complex_t get_complex(); + icomplex_t get_icomplex(); EWhat get_enum(); void* get_voidp(); bool* get_bool_array(); bool* get_bool_array2(); + signed char* get_schar_array(); + signed char* get_schar_array2(); unsigned char* get_uchar_array(); unsigned char* get_uchar_array2(); +#if __cplusplus > 201402L + std::byte* get_byte_array(); + std::byte* get_byte_array2(); +#endif short* get_short_array(); short* get_short_array2(); unsigned short* get_ushort_array(); @@ -118,10 +148,12 @@ public: unsigned long* get_ulong_array(); unsigned long* get_ulong_array2(); - float* get_float_array(); - float* get_float_array2(); - double* get_double_array(); - double* get_double_array2(); + float* get_float_array(); + float* get_float_array2(); + double* get_double_array(); + double* get_double_array2(); + complex_t* get_complex_array(); + complex_t* get_complex_array2(); CppyyTestPod get_pod_val(); // for m_pod CppyyTestPod* get_pod_val_ptr(); @@ -135,6 +167,14 @@ public: const char& get_char_cr(); const signed char& get_schar_cr(); const unsigned char& get_uchar_cr(); + const wchar_t& get_wchar_cr(); + const char16_t& get_char16_cr(); + const char32_t& get_char32_cr(); +#if __cplusplus > 201402L + const std::byte& get_byte_cr(); +#endif + const int8_t& get_int8_cr(); + const uint8_t& get_uint8_cr(); const short& get_short_cr(); const unsigned short& get_ushort_cr(); const int& get_int_cr(); @@ -148,6 +188,8 @@ public: const float& get_float_cr(); const double& get_double_cr(); const long double& get_ldouble_cr(); + const complex_t& get_complex_cr(); + const icomplex_t& get_icomplex_cr(); const EWhat& get_enum_cr(); // getters ref @@ -155,6 +197,14 @@ public: char& get_char_r(); signed char& get_schar_r(); unsigned char& get_uchar_r(); + wchar_t& get_wchar_r(); + char16_t& get_char16_r(); + char32_t& get_char32_r(); +#if __cplusplus > 201402L + std::byte& get_byte_r(); +#endif + int8_t& get_int8_r(); + uint8_t& get_uint8_r(); short& get_short_r(); unsigned short& get_ushort_r(); int& get_int_r(); @@ -168,6 +218,8 @@ public: float& get_float_r(); double& get_double_r(); long double& get_ldouble_r(); + complex_t& get_complex_r(); + icomplex_t& get_icomplex_r(); EWhat& get_enum_r(); // setters @@ -175,6 +227,14 @@ public: void set_char(char); void set_schar(signed char); void set_uchar(unsigned char); + void set_wchar(wchar_t); + void set_char16(char16_t); + void set_char32(char32_t); +#if __cplusplus > 201402L + void set_byte(std::byte); +#endif + void set_int8(int8_t); + void set_uint8(uint8_t); void set_short(short); void set_ushort(unsigned short); void set_int(int); @@ -188,6 +248,8 @@ public: void set_float(float); void set_double(double); void set_ldouble(long double); + void set_complex(complex_t); + void set_icomplex(icomplex_t); void set_enum(EWhat); void set_voidp(void*); @@ -207,6 +269,14 @@ public: void set_char_cr(const char&); void set_schar_cr(const signed char&); void set_uchar_cr(const unsigned char&); + void set_wchar_cr(const wchar_t&); + void set_char16_cr(const char16_t&); + void set_char32_cr(const char32_t&); +#if __cplusplus > 201402L + void set_byte_cr(const std::byte&); +#endif + void set_int8_cr(const int8_t&); + void set_uint8_cr(const uint8_t&); void set_short_cr(const short&); void set_ushort_cr(const unsigned short&); void set_int_cr(const int&); @@ -220,8 +290,121 @@ public: void set_float_cr(const float&); void set_double_cr(const double&); void set_ldouble_cr(const long double&); + void set_complex_cr(const complex_t&); + void set_icomplex_cr(const icomplex_t&); void set_enum_cr(const EWhat&); +// setters ref + void set_bool_r(bool&); + void set_char_r(char&); + void set_wchar_r(wchar_t&); + void set_char16_r(char16_t&); + void set_char32_r(char32_t&); + void set_schar_r(signed char&); + void set_uchar_r(unsigned char&); +#if __cplusplus > 201402L + void set_byte_r(std::byte&); +#endif + void set_short_r(short&); + void set_ushort_r(unsigned short&); + void set_int_r(int&); + void set_uint_r(unsigned int&); + void set_long_r(long&); + void set_ulong_r(unsigned long&); + void set_llong_r(long long&); + void set_ullong_r(unsigned long long&); + void set_float_r(float&); + void set_double_r(double&); + void set_ldouble_r(long double&); + +// setters ptr + void set_bool_p(bool*); + void set_char_p(char*); + void set_wchar_p(wchar_t*); + void set_char16_p(char16_t*); + void set_char32_p(char32_t*); + void set_schar_p(signed char*); + void set_uchar_p(unsigned char*); +#if __cplusplus > 201402L + void set_byte_p(std::byte*); +#endif + void set_short_p(short*); + void set_ushort_p(unsigned short*); + void set_int_p(int*); + void set_uint_p(unsigned int*); + void set_long_p(long*); + void set_ulong_p(unsigned long*); + void set_llong_p(long long*); + void set_ullong_p(unsigned long long*); + void set_float_p(float*); + void set_double_p(double*); + void set_ldouble_p(long double*); + +// setters ptrptr + void set_bool_ppa(bool**); + void set_char_ppa(char**); + void set_wchar_ppa(wchar_t**); + void set_char16_ppa(char16_t**); + void set_char32_ppa(char32_t**); + void set_schar_ppa(signed char**); + void set_uchar_ppa(unsigned char**); +#if __cplusplus > 201402L + void set_byte_ppa(std::byte**); +#endif + void set_short_ppa(short**); + void set_ushort_ppa(unsigned short**); + void set_int_ppa(int**); + void set_uint_ppa(unsigned int**); + void set_long_ppa(long**); + void set_ulong_ppa(unsigned long**); + void set_llong_ppa(long long**); + void set_ullong_ppa(unsigned long long**); + void set_float_ppa(float**); + void set_double_ppa(double**); + void set_ldouble_ppa(long double**); + + intptr_t set_char_ppm(char**); + intptr_t set_cchar_ppm(const char**); + intptr_t set_wchar_ppm(wchar_t**); + intptr_t set_char16_ppm(char16_t**); + intptr_t set_char32_ppm(char32_t**); + intptr_t set_cwchar_ppm(const wchar_t**); + intptr_t set_cchar16_ppm(const char16_t**); + intptr_t set_cchar32_ppm(const char32_t**); + intptr_t set_void_ppm(void**); + + intptr_t freeit(void*); + +// setters r-value + void set_bool_rv(bool&&); + void set_char_rv(char&&); + void set_schar_rv(signed char&&); + void set_uchar_rv(unsigned char&&); + void set_wchar_rv(wchar_t&&); + void set_char16_rv(char16_t&&); + void set_char32_rv(char32_t&&); +#if __cplusplus > 201402L + void set_byte_rv(std::byte&&); +#endif + void set_int8_rv(int8_t&&); + void set_uint8_rv(uint8_t&&); + void set_short_rv(short&&); + void set_ushort_rv(unsigned short&&); + void set_int_rv(int&&); + void set_uint_rv(unsigned int&&); + void set_long_rv(long&&); + void set_ulong_rv(unsigned long&&); + void set_llong_rv(long long&&); + void set_ullong_rv(unsigned long long&&); + void set_long64_rv(Long64_t&&); + void set_ulong64_rv(ULong64_t&&); + void set_float_rv(float&&); + void set_double_rv(double&&); + void set_ldouble_rv(long double&&); + void set_complex_rv(complex_t&&); + void set_icomplex_rv(icomplex_t&&); + void set_enum_rv(EWhat&&); + // passers unsigned char* pass_array(unsigned char*); short* pass_array(short*); @@ -232,6 +415,7 @@ public: unsigned long* pass_array(unsigned long*); float* pass_array(float*); double* pass_array(double*); + complex_t* pass_array(complex_t*); 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); } @@ -242,10 +426,17 @@ public: unsigned long* pass_void_array_L(void* a) { return pass_array((unsigned long*)a); } float* pass_void_array_f(void* a) { return pass_array((float*)a); } double* pass_void_array_d(void* a) { return pass_array((double*)a); } + complex_t* pass_void_array_Z(void* a) { return pass_array((complex_t*)a); } // strings - const char* get_valid_string(const char* in); - const char* get_invalid_string(); + const char* get_valid_string(const char* in); + const char* get_invalid_string(); + const wchar_t* get_valid_wstring(const wchar_t* in); + const wchar_t* get_invalid_wstring(); + const char16_t* get_valid_string16(const char16_t* in); + const char16_t* get_invalid_string16(); + const char32_t* get_valid_string32(const char32_t* in); + const char32_t* get_invalid_string32(); public: // basic types @@ -253,6 +444,14 @@ public: char m_char; signed char m_schar; unsigned char m_uchar; + wchar_t m_wchar; + char16_t m_char16; + char32_t m_char32; +#if __cplusplus > 201402L + std::byte m_byte; +#endif + int8_t m_int8; + uint8_t m_uint8; short m_short; unsigned short m_ushort; int m_int; @@ -267,14 +466,22 @@ public: float m_float; double m_double; long double m_ldouble; + complex_t m_complex; + icomplex_t m_icomplex; EWhat m_enum; void* m_voidp; // array types bool m_bool_array[N]; bool* m_bool_array2; + signed char m_schar_array[N]; + signed char* m_schar_array2; unsigned char m_uchar_array[N]; unsigned char* m_uchar_array2; +#if __cplusplus > 201402L + std::byte m_byte_array[N]; + std::byte* m_byte_array2; +#endif short m_short_array[N]; short* m_short_array2; unsigned short m_ushort_array[N]; @@ -288,10 +495,14 @@ public: unsigned long m_ulong_array[N]; unsigned long* m_ulong_array2; - float m_float_array[N]; - float* m_float_array2; - double m_double_array[N]; - double* m_double_array2; + float m_float_array[N]; + float* m_float_array2; + double m_double_array[N]; + double* m_double_array2; + complex_t m_complex_array[N]; + complex_t* m_complex_array2; + icomplex_t m_icomplex_array[N]; + icomplex_t* m_icomplex_array2; // object types CppyyTestPod m_pod; @@ -302,6 +513,14 @@ public: static char s_char; static signed char s_schar; static unsigned char s_uchar; + static wchar_t s_wchar; + static char16_t s_char16; + static char32_t s_char32; +#if __cplusplus > 201402L + static std::byte s_byte; +#endif + static int8_t s_int8; + static uint8_t s_uint8; static short s_short; static unsigned short s_ushort; static int s_int; @@ -315,8 +534,12 @@ public: static float s_float; static double s_double; static long double s_ldouble; + static complex_t s_complex; + static icomplex_t s_icomplex; static EWhat s_enum; static void* s_voidp; + static std::string s_strv; + static std::string* s_strp; private: bool m_owns_arrays; @@ -324,9 +547,9 @@ private: //= global functions ======================================================== -long get_pod_address(CppyyTestData& c); -long get_int_address(CppyyTestData& c); -long get_double_address(CppyyTestData& c); +intptr_t get_pod_address(CppyyTestData& c); +intptr_t get_int_address(CppyyTestData& c); +intptr_t get_double_address(CppyyTestData& c); //= global variables/pointers =============================================== @@ -334,6 +557,14 @@ extern bool g_bool; extern char g_char; extern signed char g_schar; extern unsigned char g_uchar; +extern wchar_t g_wchar; +extern char16_t g_char16; +extern char32_t g_char32; +#if __cplusplus > 201402L +extern std::byte g_byte; +#endif +extern int8_t g_int8; +extern uint8_t g_uint8; extern short g_short; extern unsigned short g_ushort; extern int g_int; @@ -347,6 +578,8 @@ extern ULong64_t g_ulong64; extern float g_float; extern double g_double; extern long double g_ldouble; +extern complex_t g_complex; +extern icomplex_t g_icomplex; extern EFruit g_enum; extern void* g_voidp; @@ -354,6 +587,14 @@ static const bool g_c_bool = true; static const char g_c_char = 'z'; static const signed char g_c_schar = 'y'; static const unsigned char g_c_uchar = 'x'; +static const wchar_t g_c_wchar = L'U'; +static const char16_t g_c_char16 = u'\u6c34'; +static const char32_t g_c_char32 = U'\U0001f34c'; +#if __cplusplus > 201402L +static const std::byte g_c_byte = (std::byte)'u'; +#endif +static const int8_t g_c_int8 = -12; +static const uint8_t g_c_uint8 = 12; static const short g_c_short = -99; static const unsigned short g_c_ushort = 99u; static const int g_c_int = -199; @@ -367,6 +608,8 @@ static const ULong64_t g_c_ulong64 = 499ull; static const float g_c_float = -599.f; static const double g_c_double = -699.; static const long double g_c_ldouble = -799.l; +static const complex_t g_c_complex = {1., 2.}; +static const icomplex_t g_c_icomplex = {3, 4}; static const EFruit g_c_enum = kApple; static const void* g_c_voidp = nullptr; @@ -381,8 +624,126 @@ void set_global_pod(CppyyTestPod* t); CppyyTestPod* get_global_pod(); CppyyTestPod* get_null_pod(); +extern std::string g_some_global_string; +std::string get_some_global_string(); +extern std::string g_some_global_string2; +std::string get_some_global_string2(); + +extern const char16_t* g_some_global_string16; +extern const char32_t* g_some_global_string32; + +namespace SomeStaticDataNS { + extern std::string s_some_static_string; + std::string get_some_static_string(); + extern std::string s_some_static_string2; + std::string get_some_static_string2(); +} + +struct StorableData { + StorableData(double d) : fData(d) {} + double fData; +}; + +extern StorableData gData; + + +//= special case of "byte" arrays =========================================== +int64_t sum_uc_data(unsigned char* data, int size); +#if __cplusplus > 201402L +int64_t sum_byte_data(std::byte* data, int size); +#endif + //= function pointer passing ================================================ -int sum_of_int(int i1, int i2); +int sum_of_int1(int i1, int i2); +int sum_of_int2(int i1, int i2); +extern int (*sum_of_int_ptr)(int, int); +int call_sum_of_int(int i1, int i2); + double sum_of_double(double d1, double d2); double call_double_double(double (*d)(double, double), double d1, double d2); + +struct sum_of_int_struct { + int (*sum_of_int_ptr)(int, int); +}; + +//= callable passing ======================================================== +int call_int_int(int (*)(int, int), int, int); +void call_void(void (*f)(int), int i); +int call_refi(void (*fcn)(int&)); +int call_refl(void (*fcn)(long&)); +int call_refd(void (*fcn)(double&)); + +class StoreCallable { + double (*fF)(double, double); +public: + StoreCallable(double (*)(double, double)); + void set_callable(double (*)(double, double)); + double operator()(double, double); +}; + + +//= callable through std::function ========================================== +double call_double_double_sf(const std::function<double(double, double)>&, double d1, double d2); + +int call_int_int_sf(const std::function<int(int, int)>&, int, int); +void call_void_sf(const std::function<void(int)>&, int i); +int call_refi_sf(const std::function<void(int&)>&); +int call_refl_sf(const std::function<void(long&)>&); +int call_refd_sf(const std::function<void(double&)>&); + +class StoreCallable_sf { + std::function<double(double, double)> fF; +public: + StoreCallable_sf(const std::function<double(double, double)>&); + void set_callable(const std::function<double(double, double)>&); + double operator()(double, double); +}; + + +//= array of struct variants ================================================ +namespace ArrayOfStruct { + +struct Foo { + int fVal; +}; + +struct Bar1 { + Bar1() : fArr(new Foo[2]) { fArr[0].fVal = 42; fArr[1].fVal = 13; } + Bar1(const Bar1&) = delete; + Bar1& operator=(const Bar1&) = delete; + ~Bar1() { delete[] fArr; } + Foo* fArr; +}; + +struct Bar2 { + Bar2(int num_foo) : fArr(std::unique_ptr<Foo[]>{new Foo[num_foo]}) { + for (int i = 0; i < num_foo; ++i) fArr[i].fVal = 2*i; + } + std::unique_ptr<Foo[]> fArr; +}; + +} // namespace ArrayOfStruct + + +//= array of C strings passing ============================================== +namespace ArrayOfCStrings { + std::vector<std::string> takes_array_of_cstrings(const char* args[], int len); +} + + +//= aggregate testing ====================================================== +namespace AggregateTest { + +struct Aggregate1 { + static int sInt; +}; + +struct Aggregate2 { + static int sInt; + int fInt = 42; +}; + +} + +#endif // !CPPYY_TEST_DATATYPES_H diff --git a/pypy/module/_cppyy/test/datatypes.xml b/pypy/module/_cppyy/test/datatypes.xml index dbed585e06..4970ecc547 100644 --- a/pypy/module/_cppyy/test/datatypes.xml +++ b/pypy/module/_cppyy/test/datatypes.xml @@ -4,9 +4,11 @@ <class name="FourVector" /> <enum name="EFruit" /> + <enum name="NamedClassEnum" /> <enum name="EnumSpace::E" /> <class name="EnumSpace::EnumClass" /> <enum name="EnumSpace::letter_code" /> + <enum name="EnumSpace::NamedClassEnum" /> <function pattern="get_*" /> <function pattern="set_*" /> @@ -17,8 +19,49 @@ <variable name="g_int" /> <variable name="g_pod" /> - <function name="sum_of_int" /> + <variable name="g_some_global_string" /> + <function name="get_some_global_string" /> + <variable name="g_some_global_string2" /> + <function name="get_some_global_string2" /> + + <class name="StorableData" /> + <variable name="gData" /> + + <namespace name="SomeStaticDataNS" /> + <variable name="SomeStaticDataNS::s_some_static_string" /> + <function name="SomeStaticDataNS::get_some_static_string" /> + <variable name="SomeStaticDataNS::s_some_static_string2" /> + <function name="SomeStaticDataNS::get_some_static_string2" /> + + <function name="sum_uc_data" /> + <function name="sum_byte_data" /> + + <function name="sum_of_int1" /> + <function name="sum_of_int2" /> + <variable name="sum_of_int_ptr" /> + <function name="call_sum_of_int" /> <function name="sum_of_double" /> <function name="call_double_double" /> + <function name="call_int_int" /> + <function name="call_void" /> + <class name="StoreCallable" /> + + <function name="sum_of_int_sf" /> + <function name="sum_of_double_sf" /> + <function name="call_double_double_sf" /> + + <function name="call_int_int_sf" /> + <function name="call_void_sf" /> + <class name="StoreCallable_sf" /> + + <namespace name="ArrayOfStruct" /> + <class pattern="ArrayOfStruct::*" /> + + <namespace name="ArrayOfCStrings" /> + <function pattern="ArrayOfCStrings::*" /> + + <namespace name="AggregateTest" /> + <struct pattern="AggregateTest::*" /> + </lcgdict> diff --git a/pypy/module/_cppyy/test/make_dict_win32.py b/pypy/module/_cppyy/test/make_dict_win32.py new file mode 100755 index 0000000000..accd03327e --- /dev/null +++ b/pypy/module/_cppyy/test/make_dict_win32.py @@ -0,0 +1,108 @@ +import glob, os, sys, subprocess + +USES_PYTHON_CAPI = set(('pythonizables',)) + +fn = sys.argv[1] + +if fn == 'all': + all_headers = glob.glob('*.h') + for header in all_headers: + res = os.system(" ".join(['python', sys.argv[0], header[:-2]]+sys.argv[2:])) + if res != 0: + sys.exit(res) + sys.exit(0) +else: + if fn[-4:] == '.cxx': fn = fn[:-4] + elif fn[-2:] == '.h': fn = fn[:-2] + if not os.path.exists(fn+'.h'): + print("file %s.h does not exist" % (fn,)) + sys.exit(1) + +uses_python_capi = False +if fn in USES_PYTHON_CAPI: + uses_python_capi = True + +if os.path.exists(fn+'Dict.dll'): + dct_time = os.stat(fn+'Dict.dll').st_mtime + if not '-f' in sys.argv: + mustbuild = False + for ext in ['.h', '.cxx', '.xml']: + if os.stat(fn+ext).st_mtime > dct_time: + mustbuild = True + break + if not mustbuild: + sys.exit(0) + + # cleanup + for fg in set(glob.glob(fn+"_rflx*") + glob.glob(fn+"Dict*") + \ + glob.glob("*.obj") + glob.glob(fn+"Linkdef.h")): + os.remove(fg) + +def _get_config_exec(): + return [sys.executable, '-m', 'cppyy_backend._cling_config'] + +def get_config(what): + config_exec_args = _get_config_exec() + config_exec_args.append('--'+what) + cli_arg = subprocess.check_output(config_exec_args) + return cli_arg.decode("utf-8").strip() + +def get_python_include_dir(): + incdir = subprocess.check_output([sys.executable, '-c', "import sysconfig; print(sysconfig.get_path('include'))"]) + return incdir.decode("utf-8").strip() + +def get_python_lib_dir(): + libdir = subprocess.check_output([sys.executable, '-c', "import sysconfig; print(sysconfig.get_path('stdlib'))"]) + return os.path.join(os.path.dirname(libdir.decode("utf-8").strip()), 'libs') + +# genreflex option +#DICTIONARY_CMD = "genreflex {fn}.h --selection={fn}.xml --rootmap={fn}Dict.rootmap --rootmap-lib={fn}Dict.dll".format(fn=fn) + +with open(fn+'Linkdef.h', 'w') as linkdef: + linkdef.write("#ifdef __CLING__\n\n") + linkdef.write("#pragma link C++ defined_in %s.h;\n" % fn) + linkdef.write("\n#endif") + +DICTIONARY_CMD = "python -m cppyy_backend._rootcling -f {fn}_rflx.cxx -rmf {fn}Dict.rootmap -rml {fn}Dict.dll {fn}.h {fn}Linkdef.h".format(fn=fn) +if os.system(DICTIONARY_CMD): + sys.exit(1) + +import platform +if '64' in platform.architecture()[0]: + PLATFORMFLAG = '-D_AMD64_' + MACHINETYPE = 'X64' +else: + PLATFORMFLAG = '-D_X86_' + MACHINETYPE = 'IX86' + +cppflags = get_config('cppflags') +if uses_python_capi: + cppflags += ' -I"' + get_python_include_dir() + '"' +BUILDOBJ_CMD_PART = "cl -O2 -nologo -TP -c -nologo " + cppflags + " -FIsehmap.h -Zc:__cplusplus -MD -GR -D_WINDOWS -DWIN32 " + PLATFORMFLAG + " -EHsc- -W3 -wd4141 -wd4291 -wd4244 -wd4049 -D_XKEYCHECK_H -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS {fn}.cxx -Fo{fn}.obj" +BUILDOBJ_CMD = BUILDOBJ_CMD_PART.format(fn=fn) +if os.system(BUILDOBJ_CMD): + sys.exit(1) +BUILDOBJ_CMD = BUILDOBJ_CMD_PART.format(fn=fn+'_rflx') +if os.system(BUILDOBJ_CMD): + sys.exit(1) + +import cppyy_backend +CREATEDEF_CMD = "python bindexplib.py {fn} {fn}Dict".format(fn=fn) +if os.system(CREATEDEF_CMD): + sys.exit(1) + +ldflags = '' +if uses_python_capi: + ldflags = ' /LIBPATH:"' + get_python_lib_dir() + '" ' +CREATELIB_CMD = ("lib -nologo -MACHINE:" + MACHINETYPE + " -out:{fn}Dict.lib {fn}.obj {fn}_rflx.obj -def:{fn}Dict.def " + ldflags).format(fn=fn) +if os.system(CREATELIB_CMD): + sys.exit(1) + +ldflags += get_config('ldflags') +LINKDLL_CMD = ("link -nologo {fn}.obj {fn}_rflx.obj -DLL -out:{fn}Dict.dll {fn}Dict.exp " + ldflags).format(fn=fn) +if os.system(LINKDLL_CMD): + sys.exit(1) + +# cleanup +for fg in set(glob.glob(fn+"_rflx.cxx*") + glob.glob("*.obj") + glob.glob(fn+"Linkdef.h")): + os.remove(fg) diff --git a/pypy/module/_cppyy/test/support.py b/pypy/module/_cppyy/test/support.py index e8cd75e327..f403e48912 100644 --- a/pypy/module/_cppyy/test/support.py +++ b/pypy/module/_cppyy/test/support.py @@ -5,6 +5,28 @@ currpath = py.path.local(__file__).dirpath() def setup_make(targetname): if sys.platform == 'win32': - py.test.skip('Cannot run this Makefile on windows') - from rpython.translator.platform import platform as compiler - compiler.execute_makefile(currpath, [targetname]) + popen = subprocess.Popen([sys.executable, "make_dict_win32.py", targetname], cwd=str(currpath), + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + else: + popen = subprocess.Popen(["make", targetname+"Dict.so"], cwd=str(currpath), + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stdout, _ = popen.communicate() + if popen.returncode: + raise OSError("'make' failed:\n%s" % (stdout,)) + +if sys.hexversion >= 0x3000000: + maxvalue = sys.maxsize +else: + maxvalue = sys.maxint + +IS_WINDOWS = 0 +if 'win32' in sys.platform: + soext = '.dll' + import platform + if '64' in platform.architecture()[0]: + IS_WINDOWS = 64 + maxvalue = 2**31-1 + else: + IS_WINDOWS = 32 +else: + soext = '.so' diff --git a/pypy/module/_cppyy/test/templates.cxx b/pypy/module/_cppyy/test/templates.cxx index bc5ff8bc2b..90c3ec48e6 100644 --- a/pypy/module/_cppyy/test/templates.cxx +++ b/pypy/module/_cppyy/test/templates.cxx @@ -35,3 +35,22 @@ void some_empty() { template void some_empty<int>(); } // namespace T_WithRValue + + +// The following is hidden from the Cling interpreter, but available to the +// linker; it allows for testing whether a function return is picked up from +// the compiled instantation or from the interpreter. + +namespace FailedTypeDeducer { + +template<class T> +class A { +public: + T result() { return T{42}; } +}; + +template class A<int>; + +template class B<int>; + +} // namespace FailedTypeDeducer diff --git a/pypy/module/_cppyy/test/templates.h b/pypy/module/_cppyy/test/templates.h index 98c76db3d1..0b86e08e8a 100644 --- a/pypy/module/_cppyy/test/templates.h +++ b/pypy/module/_cppyy/test/templates.h @@ -18,8 +18,6 @@ #define INLINE #endif - - #ifndef __MSC_VER #include <cxxabi.h> INLINE std::string demangle_it(const char* name, const char* errmsg) { @@ -324,9 +322,13 @@ bool is_valid(T&& new_value) { // variadic templates namespace some_variadic { -#ifdef WIN32 +#ifdef _WIN32 +#ifdef __CLING__ extern __declspec(dllimport) std::string gTypeName; #else +extern __declspec(dllexport) std::string gTypeName; +#endif +#else extern std::string gTypeName; #endif @@ -423,9 +425,13 @@ T fn_T(Args&&... args) { // template with empty body namespace T_WithEmptyBody { -#ifdef WIN32 +#ifdef _WIN32 +#ifdef __CLING__ extern __declspec(dllimport) std::string side_effect; #else +extern __declspec(dllexport) std::string side_effect; +#endif +#else extern std::string side_effect; #endif @@ -492,4 +498,45 @@ public: } // namespace TemplateWithSetItem + +//=========================================================================== +// type reduction examples on gmpxx-like template expressions +namespace TypeReduction { + +template <typename T> +struct BinaryExpr; + +template <typename T> +struct Expr { + Expr() {} + Expr(const BinaryExpr<T>&) {} +}; + +template <typename T> +struct BinaryExpr { + BinaryExpr(const Expr<T>&, const Expr<T>&) {} +}; + +template<typename T> +BinaryExpr<T> operator+(const Expr<T>& e1, const Expr<T>& e2) { + return BinaryExpr<T>(e1, e2); +} + +} // namespace TypeReduction + + +//=========================================================================== +// type deduction examples +namespace FailedTypeDeducer { + +template<class T> +class B { +public: + auto result() { return 5.; } +}; + +extern template class B<int>; + +} + #endif // !CPPYY_TEST_TEMPLATES_H diff --git a/pypy/module/_cppyy/test/templates.xml b/pypy/module/_cppyy/test/templates.xml index 63d9829332..8bda6eede5 100644 --- a/pypy/module/_cppyy/test/templates.xml +++ b/pypy/module/_cppyy/test/templates.xml @@ -33,4 +33,11 @@ <namespace name="T_WithGreedyOverloads" /> <class pattern="T_WithGreedyOverloads::*" /> + <namespace name="TypeReduction" /> + <class pattern="TypeReduction::*" /> + <function pattern="TypeReduction::*" /> + + <namespace name="FailedTypeDeducer" /> + <class pattern="FailedTypeDeducer::*" /> + </lcgdict> diff --git a/pypy/module/_cppyy/test/test_advancedcpp.py b/pypy/module/_cppyy/test/test_advancedcpp.py index 6603b7ed75..6ae146df57 100644 --- a/pypy/module/_cppyy/test/test_advancedcpp.py +++ b/pypy/module/_cppyy/test/test_advancedcpp.py @@ -1,12 +1,12 @@ import py, os, sys -from .support import setup_make +from .support import setup_make, soext currpath = py.path.local(__file__).dirpath() -test_dct = str(currpath.join("advancedcppDict.so")) +test_dct = str(currpath.join("advancedcppDict"))+soext def setup_module(mod): - setup_make("advancedcppDict.so") + setup_make("advancedcpp") def setup_module(mod): if sys.platform == 'win32': diff --git a/pypy/module/_cppyy/test/test_boost.py b/pypy/module/_cppyy/test/test_boost.py new file mode 100644 index 0000000000..a8e2e4d0f2 --- /dev/null +++ b/pypy/module/_cppyy/test/test_boost.py @@ -0,0 +1,185 @@ +import py, os, sys +from pytest import mark, raises +from .support import setup_make + +noboost = False +if not (os.path.exists(os.path.join(os.path.sep, 'usr', 'include', 'boost')) or \ + os.path.exists(os.path.join(os.path.sep, 'usr', 'local', 'include', 'boost'))): + noboost = True + + +@mark.skipif(noboost == True, reason="boost not found") +class AppTestBOOSTANY: + spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) + + def setup_class(cls): + cls.space.appexec([], """(): + import ctypes, _cppyy + _cppyy._post_import_startup() + _cppyy.gbl.gInterpreter.Declare('#include "boost/any.hpp"') + """) + + def test01_any_class(self): + """Availability of boost::any""" + + import _cppyy as cppyy + + assert cppyy.gbl.boost.any + + std = cppyy.gbl.std + any = cppyy.gbl.boost.any + + assert std.list[any] + + def test02_any_usage(self): + """boost::any assignment and casting""" + + import _cppyy as cppyy + + assert cppyy.gbl.boost + + std = cppyy.gbl.std + boost = cppyy.gbl.boost + + val = boost.any() + # test both by-ref and by rvalue + v = std.vector[int]() + val.__assign__(v) + val.__assign__(std.move(std.vector[int](range(100)))) + assert val.type() == cppyy.typeid(std.vector[int]) + + extract = boost.any_cast[std.vector[int]](val) + assert type(extract) is std.vector[int] + assert len(extract) == 100 + extract += range(100) + assert len(extract) == 200 + + val.__assign__(std.move(extract)) # move forced + #assert len(extract) == 0 # not guaranteed by the standard + + # TODO: we hit boost::any_cast<int>(boost::any* operand) instead + # of the reference version which raises + boost.any_cast.__useffi__ = False + try: + # raises(Exception, boost.any_cast[int], val) + assert not boost.any_cast[int](val) + except Exception: + # getting here is good, too ... + pass + + extract = boost.any_cast[std.vector[int]](val) + assert len(extract) == 200 + + +@mark.skipif(noboost == True, reason="boost not found") +class AppTestBOOSTOPERATORS: + spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) + + def setup_class(cls): + cls.space.appexec([], """(): + import ctypes, _cppyy + _cppyy._post_import_startup() + _cppyy.gbl.gInterpreter.Declare('#include "boost/operators.hpp"') + """) + + def test01_ordered(self): + """ordered_field_operators as base used to crash""" + + import _cppyy as cppyy + + cppyy.gbl.gInterpreter.Declare('#include "gmpxx.h"') + cppyy.gbl.gInterpreter.Declare(""" + namespace boost_test { + class Derived : boost::ordered_field_operators<Derived>, boost::ordered_field_operators<Derived, mpq_class> {}; + } + """) + + assert cppyy.gbl.boost_test.Derived + + +@mark.skipif(noboost == True, reason="boost not found") +class AppTestBOOSTVARIANT: + spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) + + def setup_class(cls): + cls.space.appexec([], """(): + import ctypes, _cppyy + _cppyy._post_import_startup() + _cppyy.gbl.gInterpreter.Declare('#include "boost/variant/variant.hpp"') + _cppyy.gbl.gInterpreter.Declare('#include "boost/variant/get.hpp"') + """) + + def test01_variant_usage(self): + """boost::variant usage""" + + # as posted on stackoverflow as example + import _cppyy as cppyy + + try: + cpp = cppyy.gbl + except: + pass + + cpp = cppyy.gbl + std = cpp.std + boost = cpp.boost + + cppyy.gbl.gInterpreter.Declare("""namespace BV { + class A { }; + class B { }; + class C { }; } """) + + VariantType = boost.variant['BV::A, BV::B, BV::C'] + VariantTypeList = std.vector[VariantType] + + v = VariantTypeList() + + v.push_back(VariantType(cpp.BV.A())) + assert v.back().which() == 0 + v.push_back(VariantType(cpp.BV.B())) + assert v.back().which() == 1 + v.push_back(VariantType(cpp.BV.C())) + assert v.back().which() == 2 + + assert type(boost.get['BV::A'](v[0])) == cpp.BV.A + raises(Exception, boost.get['BV::B'], v[0]) + assert type(boost.get['BV::B'](v[1])) == cpp.BV.B + assert type(boost.get['BV::C'](v[2])) == cpp.BV.C + + +@mark.skipif(noboost == True, reason="boost not found") +class AppTestBOOSTERASURE: + spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) + + def setup_class(cls): + cls.space.appexec([], """(): + import ctypes, _cppyy + _cppyy._post_import_startup() + _cppyy.gbl.gInterpreter.Declare('#include "boost/type_erasure/any.hpp"') + _cppyy.gbl.gInterpreter.Declare('#include "boost/type_erasure/member.hpp"') + """) + + def test01_erasure_usage(self): + """boost::type_erasure usage""" + + import _cppyy as cppyy + + cppyy.gbl.gInterpreter.Declare(""" + BOOST_TYPE_ERASURE_MEMBER((has_member_f), f, 0) + + using LengthsInterface = boost::mpl::vector< + boost::type_erasure::copy_constructible<>, + has_member_f<std::vector<int>() const>>; + + using Lengths = boost::type_erasure::any<LengthsInterface>; + + struct Unerased { + std::vector<int> f() const { return std::vector<int>{}; } + }; + + Lengths lengths() { + return Unerased{}; + } + """) + + assert cppyy.gbl.lengths() is not None diff --git a/pypy/module/_cppyy/test/test_cpp11features.py b/pypy/module/_cppyy/test/test_cpp11features.py index 10a45fd110..7b284befa7 100644 --- a/pypy/module/_cppyy/test/test_cpp11features.py +++ b/pypy/module/_cppyy/test/test_cpp11features.py @@ -1,12 +1,12 @@ import py, os, sys -from .support import setup_make - +from .support import setup_make, soext currpath = py.path.local(__file__).dirpath() -test_dct = str(currpath.join("cpp11featuresDict.so")) +test_dct = str(currpath.join("cpp11featuresDict"))+soext def setup_module(mod): - setup_make("cpp11featuresDict.so") + setup_make("cpp11features") + class AppTestCPP11FEATURES: spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) diff --git a/pypy/module/_cppyy/test/test_cppyy.py b/pypy/module/_cppyy/test/test_cppyy.py index 55a4929742..e55d19e428 100644 --- a/pypy/module/_cppyy/test/test_cppyy.py +++ b/pypy/module/_cppyy/test/test_cppyy.py @@ -1,14 +1,13 @@ import py, os, sys - from pypy.module._cppyy import interp_cppyy, executor -from .support import setup_make - +from .support import setup_make, soext currpath = py.path.local(__file__).dirpath() -test_dct = str(currpath.join("example01Dict.so")) +test_dct = str(currpath.join("example01Dict"))+soext def setup_module(mod): - setup_make("example01Dict.so") + setup_make("example01") + class TestCPPYYImplementation: def test01_class_query(self, space): diff --git a/pypy/module/_cppyy/test/test_crossing.py b/pypy/module/_cppyy/test/test_crossing.py index e689c60081..0b371acaae 100644 --- a/pypy/module/_cppyy/test/test_crossing.py +++ b/pypy/module/_cppyy/test/test_crossing.py @@ -1,5 +1,5 @@ import py, os, sys -from .support import setup_make +from .support import setup_make, soext from pypy.interpreter.gateway import interp2app, unwrap_spec from rpython.translator.tool.cbuild import ExternalCompilationInfo @@ -10,12 +10,12 @@ from rpython.tool.udir import udir from pypy.module.cpyext import api from pypy.module.cpyext.state import State - currpath = py.path.local(__file__).dirpath() -test_dct = str(currpath.join("crossingDict.so")) +test_dct = str(currpath.join("crossingDict"))+soext def setup_module(mod): - setup_make("crossingDict.so") + setup_make("crossing") + # from pypy/module/cpyext/test/test_cpyext.py; modified to accept more external # symbols and called directly instead of import_module diff --git a/pypy/module/_cppyy/test/test_datatypes.py b/pypy/module/_cppyy/test/test_datatypes.py index 0a5d26a428..d127020903 100644 --- a/pypy/module/_cppyy/test/test_datatypes.py +++ b/pypy/module/_cppyy/test/test_datatypes.py @@ -1,12 +1,13 @@ import py, os, sys -from .support import setup_make - +from pytest import raises +from .support import setup_make, soext currpath = py.path.local(__file__).dirpath() -test_dct = str(currpath.join("datatypesDict.so")) +test_dct = str(currpath.join("datatypesDict"))+soext def setup_module(mod): - setup_make("datatypesDict.so") + setup_make("datatypes") + class AppTestDATATYPES: spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) @@ -17,12 +18,24 @@ class AppTestDATATYPES: import ctypes, _cppyy _cppyy._post_import_startup() return ctypes.CDLL(%r, ctypes.RTLD_GLOBAL)""" % (test_dct, )) - cls.w_N = cls.space.newint(5) # should be imported from the dictionary + cls.w_N = cls.space.appexec([], """(): + import _cppyy + return _cppyy.gbl.N""") + cls.w_has_byte = cls.space.appexec([], """(): + import _cppyy + return 201402 < _cppyy.gbl.gInterpreter.ProcessLine("__cplusplus;")""") def test01_instance_data_read_access(self): """Read access to instance public data and verify values""" + import sys import _cppyy as cppyy + + if sys.hexversion >= 0x3000000: + pyunicode = str + else: + pyunicode = unicode + CppyyTestData = cppyy.gbl.CppyyTestData c = CppyyTestData() @@ -36,8 +49,18 @@ class AppTestDATATYPES: assert c.m_char == 'a' assert c.m_schar == 'b' assert c.m_uchar == 'c' + assert type(c.m_wchar) == pyunicode + assert c.m_wchar == u'D' + assert type(c.m_char16) == pyunicode + assert c.m_char16 == u'\u00df' + assert type(c.m_char32) == pyunicode + assert c.m_char32 == u'\u00df' # reading integer types + assert c.m_int8 == - 9; assert c.get_int8_cr() == - 9; assert c.get_int8_r() == - 9 + assert c.m_uint8 == 9; assert c.get_uint8_cr() == 9; assert c.get_uint8_r() == 9 + if self.has_byte: + assert c.m_byte == ord('d'); assert c.get_byte_cr() == ord('d'); assert c.get_byte_r() == ord('d') assert c.m_short == -11; assert c.get_short_cr() == -11; assert c.get_short_r() == -11 assert c.m_ushort == 11; assert c.get_ushort_cr() == 11; assert c.get_ushort_r() == 11 assert c.m_int == -22; assert c.get_int_cr() == -22; assert c.get_int_r() == -22 @@ -62,7 +85,7 @@ class AppTestDATATYPES: assert round(c.get_ldouble_def() -1., 24) == 0 assert round(c.get_ldouble_def(2) -2., 24) == 0 - """# complex<double> type + # complex<double> type assert type(c.get_complex()) == complex assert round(c.get_complex().real - 99., 11) == 0 assert round(c.get_complex().imag - 101., 11) == 0 @@ -72,6 +95,7 @@ class AppTestDATATYPES: assert round(c.get_complex_r().real - 99., 11) == 0 assert round(c.get_complex_r().imag - 101., 11) == 0 assert complex(cppyy.gbl.std.complex['double'](1, 2)) == complex(1, 2) + assert repr(cppyy.gbl.std.complex['double'](1, 2)) == '(1+2j)' # complex<int> retains C++ type in all cases (but includes pythonization to # resemble Python's complex more closely @@ -84,7 +108,7 @@ class AppTestDATATYPES: assert type(c.get_icomplex_r()) == cppyy.gbl.std.complex[int] assert round(c.get_icomplex_r().real - 121., 11) == 0 assert round(c.get_icomplex_r().imag - 141., 11) == 0 - assert complex(cppyy.gbl.std.complex['int'](1, 2)) == complex(1, 2)""" + assert complex(cppyy.gbl.std.complex['int'](1, 2)) == complex(1, 2) # reading of enum types assert c.m_enum == CppyyTestData.kNothing @@ -98,8 +122,10 @@ class AppTestDATATYPES: assert c.get_bool_array2()[i] == bool((i+1)%2) # reading of integer array types - names = ['uchar', 'short', 'ushort', 'int', 'uint', 'long', 'ulong'] - alpha = [ (1, 2), (-1, -2), (3, 4), (-5, -6), (7, 8), (-9, -10), (11, 12)] + names = ['schar', 'uchar', 'short', 'ushort', 'int', 'uint', 'long', 'ulong'] + alpha = [ (1, 2), (1, 2), (-1, -2), (3, 4), (-5, -6), (7, 8), (-9, -10), (11, 12)] + if self.has_byte: names.append('byte'); alpha.append((3,4)) + 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 @@ -114,7 +140,10 @@ class AppTestDATATYPES: assert round(c.m_double_array2[k] + 16.*k, 8) == 0 # out-of-bounds checks + raises(IndexError, c.m_schar_array.__getitem__, self.N) raises(IndexError, c.m_uchar_array.__getitem__, self.N) + if self.has_byte: + raises(IndexError, c.m_byte_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) @@ -136,7 +165,14 @@ class AppTestDATATYPES: def test02_instance_data_write_access(self): """Test write access to instance public data and verify values""" + import sys import _cppyy as cppyy + + if sys.hexversion >= 0x3000000: + pyunicode = str + else: + pyunicode = unicode + CppyyTestData = cppyy.gbl.CppyyTestData c = CppyyTestData() @@ -152,11 +188,15 @@ class AppTestDATATYPES: c.m_bool = 0; assert c.get_bool() == False c.set_bool(0); assert c.m_bool == False - raises(ValueError, 'c.set_bool(10)') + raises(ValueError, c.set_bool, 10) # char types through functions c.set_char('c'); assert c.get_char() == 'c' c.set_uchar('e'); assert c.get_uchar() == 'e' + c.set_wchar(u'F'); assert c.get_wchar() == u'F' + assert type(c.get_wchar()) == pyunicode + c.set_char16(u'\u00f2'); assert c.get_char16() == u'\u00f2' + c.set_char32(u'\U0001f31c'); assert c.get_char32() == u'\U0001f31c' # char types through data members c.m_char = 'b'; assert c.get_char() == 'b' @@ -167,14 +207,25 @@ class AppTestDATATYPES: c.m_uchar = 42; assert c.get_uchar() == chr(42) c.set_uchar('e'); assert c.m_uchar == 'e' c.set_uchar(43); assert c.m_uchar == chr(43) - - raises(ValueError, 'c.set_char("string")') - raises(ValueError, 'c.set_char(500)') - raises(ValueError, 'c.set_uchar("string")') - raises(ValueError, 'c.set_uchar(-1)') + c.m_wchar = u'G'; assert c.get_wchar() == u'G' + c.set_wchar(u'H'); assert c.m_wchar == u'H' + c.m_char16 = u'\u00f3'; assert c.get_char16() == u'\u00f3' + c.set_char16(u'\u00f4'); assert c.m_char16 == u'\u00f4' + c.m_char32 = u'\U0001f31d'; assert c.get_char32() == u'\U0001f31d' + c.set_char32(u'\U0001f31e'); assert c.m_char32 == u'\U0001f31e' + + raises(ValueError, c.set_char, "string") + raises(ValueError, c.set_char, 500) + raises(ValueError, c.set_uchar, "string") + raises(ValueError, c.set_uchar, -1) + raises(ValueError, c.set_wchar, "string") + raises(ValueError, c.set_char16, "string") + raises(ValueError, c.set_char32, "string") # integer types - names = ['short', 'ushort', 'int', 'uint', 'long', 'ulong', 'llong', 'ullong'] + names = ['int8', 'uint8', 'short', 'ushort', 'int', 'uint', 'long', 'ulong', 'llong', 'ullong'] + if self.has_byte: names.append('byte') + for i in range(len(names)): setattr(c, 'm_'+names[i], i) assert eval('c.get_%s()' % names[i]) == i @@ -208,9 +259,12 @@ class AppTestDATATYPES: # integer arrays names = ['uchar', 'short', 'ushort', 'int', 'uint', 'long', 'ulong'] + if self.has_byte: names.append('byte') + import array a = range(self.N) atypes = ['B', 'h', 'H', 'i', 'I', 'l', 'L'] + if self.has_byte: atypes.append('B') for j in range(len(names)): b = array.array(atypes[j], a) setattr(c, 'm_'+names[j]+'_array', b) # buffer copies @@ -269,7 +323,16 @@ class AppTestDATATYPES: def test04_class_read_access(self): """Test read access to class public data and verify values""" - import _cppyy as cppyy, sys + import sys + import _cppyy as cppyy + + if sys.hexversion >= 0x3000000: + pylong = int + pyunicode = str + else: + pylong = long + pyunicode = unicode + CppyyTestData = cppyy.gbl.CppyyTestData c = CppyyTestData() @@ -278,10 +341,30 @@ class AppTestDATATYPES: # char types assert CppyyTestData.s_char == 'c' assert c.s_char == 'c' - assert c.s_uchar == 'u' assert CppyyTestData.s_uchar == 'u' + assert c.s_uchar == 'u' + assert CppyyTestData.s_wchar == u'U' + assert c.s_wchar == u'U' + assert CppyyTestData.s_char16 == u'\u6c29' + assert c.s_char16 == u'\u6c29' + assert CppyyTestData.s_char32 == u'\U0001f34b' + assert c.s_char32 == u'\U0001f34b' + + assert type(c.s_wchar) == pyunicode + assert type(CppyyTestData.s_wchar) == pyunicode + assert type(c.s_char16) == pyunicode + assert type(CppyyTestData.s_char16) == pyunicode + assert type(c.s_char32) == pyunicode + assert type(CppyyTestData.s_char32) == pyunicode # integer types + if self.has_byte: + assert CppyyTestData.s_byte == ord('b') + assert c.s_byte == ord('b') + assert CppyyTestData.s_int8 == - 87 + assert c.s_int8 == - 87 + assert CppyyTestData.s_uint8 == 87 + assert c.s_uint8 == 87 assert CppyyTestData.s_short == -101 assert c.s_short == -101 assert c.s_ushort == 255 @@ -290,14 +373,14 @@ class AppTestDATATYPES: assert c.s_int == -202 assert c.s_uint == 202 assert CppyyTestData.s_uint == 202 - assert CppyyTestData.s_long == -303 - assert c.s_long == -303 - assert c.s_ulong == 303 - assert CppyyTestData.s_ulong == 303 - assert CppyyTestData.s_llong == -404 - assert c.s_llong == -404 - assert c.s_ullong == 404 - assert CppyyTestData.s_ullong == 404 + assert CppyyTestData.s_long == -pylong(303) + assert c.s_long == -pylong(303) + assert c.s_ulong == pylong(303) + assert CppyyTestData.s_ulong == pylong(303) + assert CppyyTestData.s_llong == -pylong(404) + assert c.s_llong == -pylong(404) + assert c.s_ullong == pylong(404) + assert CppyyTestData.s_ullong == pylong(404) # floating point types assert round(CppyyTestData.s_float + 606., 5) == 0 @@ -312,7 +395,14 @@ class AppTestDATATYPES: def test05_class_data_write_access(self): """Test write access to class public data and verify values""" - import _cppyy as cppyy, sys + import sys + import _cppyy as cppyy + + if sys.hexversion >= 0x3000000: + pylong = int + else: + pylong = long + CppyyTestData = cppyy.gbl.CppyyTestData c = CppyyTestData() @@ -329,8 +419,25 @@ class AppTestDATATYPES: assert CppyyTestData.s_uchar == 'd' raises(ValueError, setattr, CppyyTestData, 's_uchar', -1) raises(ValueError, setattr, c, 's_uchar', -1) + CppyyTestData.s_wchar = u'K' + assert c.s_wchar == u'K' + c.s_wchar = u'L' + assert CppyyTestData.s_wchar == u'L' + CppyyTestData.s_char16 = u'\u00df' + assert c.s_char16 == u'\u00df' + c.s_char16 = u'\u00ef' + assert CppyyTestData.s_char16 == u'\u00ef' + CppyyTestData.s_char32 = u'\u00df' + assert c.s_char32 == u'\u00df' + c.s_char32 = u'\u00ef' + assert CppyyTestData.s_char32 == u'\u00ef' # integer types + if self.has_byte: + c.s_byte = 66 + assert CppyyTestData.s_byte == 66 + CppyyTestData.s_byte = 66 + assert c.s_byte == 66 c.s_short = -102 assert CppyyTestData.s_short == -102 CppyyTestData.s_short = -203 @@ -349,14 +456,14 @@ class AppTestDATATYPES: assert CppyyTestData.s_uint == 4321 raises(ValueError, setattr, c, 's_uint', -1) raises(ValueError, setattr, CppyyTestData, 's_uint', -1) - CppyyTestData.s_long = -87 - assert c.s_long == -87 - c.s_long = 876 - assert CppyyTestData.s_long == 876 - CppyyTestData.s_ulong = 876 - assert c.s_ulong == 876 - c.s_ulong = 678 - assert CppyyTestData.s_ulong == 678 + CppyyTestData.s_long = -pylong(87) + assert c.s_long == -pylong(87) + c.s_long = pylong(876) + assert CppyyTestData.s_long == pylong(876) + CppyyTestData.s_ulong = pylong(876) + assert c.s_ulong == pylong(876) + c.s_ulong = pylong(678) + assert CppyyTestData.s_ulong == pylong(678) raises(ValueError, setattr, CppyyTestData, 's_ulong', -1) raises(ValueError, setattr, c, 's_ulong', -1) @@ -405,9 +512,9 @@ class AppTestDATATYPES: c.m_double = -1 assert round(c.m_double + 1.0, 8) == 0 - raises(TypeError, c.m_double, 'c') - raises(TypeError, c.m_int, -1.) - raises(TypeError, c.m_int, 1.) + raises(TypeError, setattr, c.m_double, 'c') + raises(TypeError, setattr, c.m_int, -1.) + raises(TypeError, setattr, c.m_int, 1.) c.__destruct__() @@ -433,7 +540,8 @@ class AppTestDATATYPES: import _cppyy as cppyy gbl = cppyy.gbl - raises(ReferenceError, 'gbl.g_pod.m_int') + with raises(ReferenceError): + gbl.g_pod.m_int c = gbl.CppyyTestPod() c.m_int = 42 @@ -722,13 +830,17 @@ class AppTestDATATYPES: CppyyTestData = cppyy.gbl.CppyyTestData c = CppyyTestData() + byte_array_names = [] + if self.has_byte: + byte_array_names = ['get_byte_array', 'get_byte_array2'] for func in ['get_bool_array', 'get_bool_array2', - 'get_uchar_array', 'get_uchar_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', 'get_long_array', 'get_long_array2', - 'get_ulong_array', 'get_ulong_array2']: + 'get_ulong_array', 'get_ulong_array2']+\ + byte_array_names: arr = getattr(c, func)() arr.reshape((self.N,)) assert len(arr) == self.N @@ -791,7 +903,43 @@ class AppTestDATATYPES: c.s_voidp = c2 address_equality_test(c.s_voidp, c2) - def test21_function_pointers(self): + def test21_byte_arrays(self): + """Usage of unsigned char* as byte array and std::byte*""" + + import _cppyy as cppyy + import array, ctypes + + buf = b'123456789' + total = 0 + for c in buf: + try: + total += ord(c) # p2 + except TypeError: + total += c # p3 + + def run(self, f, buf, total): + + # The following create a unique type for fixed-size C arrays: ctypes.c_char_Array_9 + # and neither inherits from a non-sized type nor implements the buffer interface. + # As such, it can't be handled. TODO? + #pbuf = ctypes.create_string_buffer(len(buf), buf) + #assert f(pbuf, len(buf)) == total + + pbuf = array.array('B', buf) + assert f(pbuf, len(buf)) == total + + pbuf = (ctypes.c_ubyte * len(buf)).from_buffer_copy(buf) + assert f(pbuf, len(buf)) == total + + pbuf = ctypes.cast(buf, ctypes.POINTER(ctypes.c_ubyte * len(buf)))[0] + assert f(pbuf, len(buf)) == total + + run(self, cppyy.gbl.sum_uc_data, buf, total) + + if self.has_byte: + run(self, cppyy.gbl.sum_byte_data, buf, total) + + def test22_function_pointers(self): """Function pointer passing""" import os @@ -805,7 +953,7 @@ class AppTestDATATYPES: import _cppyy as cppyy - f1 = cppyy.gbl.sum_of_int + f1 = cppyy.gbl.sum_of_int1 f2 = cppyy.gbl.sum_of_double f3 = cppyy.gbl.call_double_double diff --git a/pypy/module/_cppyy/test/test_fragile.py b/pypy/module/_cppyy/test/test_fragile.py index 1310420033..796b524daf 100644 --- a/pypy/module/_cppyy/test/test_fragile.py +++ b/pypy/module/_cppyy/test/test_fragile.py @@ -1,12 +1,12 @@ import py, os, sys -from .support import setup_make - +from .support import setup_make, soext currpath = py.path.local(__file__).dirpath() -test_dct = str(currpath.join("fragileDict.so")) +test_dct = str(currpath.join("fragileDict"))+soext def setup_module(mod): - setup_make("fragileDict.so") + setup_make("fragile") + class AppTestFRAGILE: spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) @@ -21,12 +21,12 @@ class AppTestFRAGILE: def test01_missing_classes(self): """Test (non-)access to missing classes""" - import _cppyy + import _cppyy as cppyy - raises(AttributeError, getattr, _cppyy.gbl, "no_such_class") + raises(AttributeError, getattr, cppyy.gbl, "no_such_class") - assert _cppyy.gbl.fragile == _cppyy.gbl.fragile - fragile = _cppyy.gbl.fragile + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile raises(AttributeError, getattr, fragile, "no_such_class") @@ -44,10 +44,10 @@ class AppTestFRAGILE: def test02_arguments(self): """Test reporting when providing wrong arguments""" - import _cppyy + import _cppyy as cppyy - assert _cppyy.gbl.fragile == _cppyy.gbl.fragile - fragile = _cppyy.gbl.fragile + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile assert fragile.D == fragile.D assert fragile.D().check() == ord('D') @@ -62,10 +62,10 @@ class AppTestFRAGILE: def test03_unsupported_arguments(self): """Test arguments that are yet unsupported""" - import _cppyy + import _cppyy as cppyy - assert _cppyy.gbl.fragile == _cppyy.gbl.fragile - fragile = _cppyy.gbl.fragile + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile assert fragile.E == fragile.E assert fragile.E().check() == ord('E') @@ -79,10 +79,10 @@ class AppTestFRAGILE: def test04_wrong_arg_addressof(self): """Test addressof() error reporting""" - import _cppyy + import _cppyy as cppyy - assert _cppyy.gbl.fragile == _cppyy.gbl.fragile - fragile = _cppyy.gbl.fragile + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile assert fragile.F == fragile.F assert fragile.F().check() == ord('F') @@ -90,18 +90,18 @@ class AppTestFRAGILE: f = fragile.F() o = object() - _cppyy.addressof(f) - raises(TypeError, _cppyy.addressof, o) - raises(TypeError, _cppyy.addressof, 1) + cppyy.addressof(f) + raises(TypeError, cppyy.addressof, o) + raises(TypeError, cppyy.addressof, 1) # see also test08_void_pointer_passing in test_advancedcpp.py def test05_wrong_this(self): """Test that using an incorrect self argument raises""" - import _cppyy + import _cppyy as cppyy - assert _cppyy.gbl.fragile == _cppyy.gbl.fragile - fragile = _cppyy.gbl.fragile + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile a = fragile.A() assert fragile.A.check(a) == ord('A') @@ -119,43 +119,43 @@ class AppTestFRAGILE: def test06_unnamed_enum(self): """Test that an unnamed enum does not cause infinite recursion""" - import _cppyy + import _cppyy as cppyy - assert _cppyy.gbl.fragile is _cppyy.gbl.fragile - fragile = _cppyy.gbl.fragile - assert _cppyy.gbl.fragile is fragile + assert cppyy.gbl.fragile is cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + assert cppyy.gbl.fragile is fragile g = fragile.G() def test07_unhandled_scoped_datamember(self): """Test that an unhandled scoped data member does not cause infinite recursion""" - import _cppyy + import _cppyy as cppyy - assert _cppyy.gbl.fragile is _cppyy.gbl.fragile - fragile = _cppyy.gbl.fragile - assert _cppyy.gbl.fragile is fragile + assert cppyy.gbl.fragile is cppyy.gbl.fragile + fragile = cppyy.gbl.fragile + assert cppyy.gbl.fragile is fragile h = fragile.H() def test08_operator_bool(self): """Access to global vars with an operator bool() returning False""" - import _cppyy + import _cppyy as cppyy - i = _cppyy.gbl.fragile.I() + i = cppyy.gbl.fragile.I() assert not i - g = _cppyy.gbl.fragile.gI + g = cppyy.gbl.fragile.gI assert not g def test09_documentation(self): """Check contents of documentation""" - import _cppyy + import _cppyy as cppyy - assert _cppyy.gbl.fragile == _cppyy.gbl.fragile - fragile = _cppyy.gbl.fragile + assert cppyy.gbl.fragile == cppyy.gbl.fragile + fragile = cppyy.gbl.fragile d = fragile.D() try: @@ -197,9 +197,9 @@ class AppTestFRAGILE: def test10_dir(self): """Test __dir__ method""" - import _cppyy + import _cppyy as cppyy - members = dir(_cppyy.gbl.fragile) + members = dir(cppyy.gbl.fragile) assert 'A' in members assert 'B' in members assert 'C' in members @@ -215,7 +215,7 @@ class AppTestFRAGILE: def test11_imports(self): """Test ability to import from namespace (or fail with ImportError)""" - import _cppyy + import _cppyy as cppyy # TODO: namespaces aren't loaded (and thus not added to sys.modules) # with just the from ... import statement; actual use is needed @@ -231,51 +231,51 @@ class AppTestFRAGILE: raises(ImportError, fail_import) from cppyy.gbl.fragile import A, B, C, D - assert _cppyy.gbl.fragile.A is A - assert _cppyy.gbl.fragile.B is B - assert _cppyy.gbl.fragile.C is C - assert _cppyy.gbl.fragile.D is D + assert cppyy.gbl.fragile.A is A + assert cppyy.gbl.fragile.B is B + assert cppyy.gbl.fragile.C is C + assert cppyy.gbl.fragile.D is D # according to warnings, can't test "import *" ... from cppyy.gbl.fragile import nested1 - assert _cppyy.gbl.fragile.nested1 is nested1 + assert cppyy.gbl.fragile.nested1 is nested1 assert nested1.__name__ == 'nested1' assert nested1.__module__ == 'cppyy.gbl.fragile' - assert nested1.__cppname__ == 'fragile::nested1' + assert nested1.__cpp_name__ == 'fragile::nested1' from cppyy.gbl.fragile.nested1 import A, nested2 - assert _cppyy.gbl.fragile.nested1.A is A + assert cppyy.gbl.fragile.nested1.A is A assert A.__name__ == 'A' assert A.__module__ == 'cppyy.gbl.fragile.nested1' - assert A.__cppname__ == 'fragile::nested1::A' - assert _cppyy.gbl.fragile.nested1.nested2 is nested2 + assert A.__cpp_name__ == 'fragile::nested1::A' + assert cppyy.gbl.fragile.nested1.nested2 is nested2 assert A.__name__ == 'A' assert A.__module__ == 'cppyy.gbl.fragile.nested1' - assert nested2.__cppname__ == 'fragile::nested1::nested2' + assert nested2.__cpp_name__ == 'fragile::nested1::nested2' from cppyy.gbl.fragile.nested1.nested2 import A, nested3 - assert _cppyy.gbl.fragile.nested1.nested2.A is A + assert cppyy.gbl.fragile.nested1.nested2.A is A assert A.__name__ == 'A' assert A.__module__ == 'cppyy.gbl.fragile.nested1.nested2' - assert A.__cppname__ == 'fragile::nested1::nested2::A' - assert _cppyy.gbl.fragile.nested1.nested2.nested3 is nested3 + assert A.__cpp_name__ == 'fragile::nested1::nested2::A' + assert cppyy.gbl.fragile.nested1.nested2.nested3 is nested3 assert A.__name__ == 'A' assert A.__module__ == 'cppyy.gbl.fragile.nested1.nested2' - assert nested3.__cppname__ == 'fragile::nested1::nested2::nested3' + assert nested3.__cpp_name__ == 'fragile::nested1::nested2::nested3' from cppyy.gbl.fragile.nested1.nested2.nested3 import A - assert _cppyy.gbl.fragile.nested1.nested2.nested3.A is nested3.A + assert cppyy.gbl.fragile.nested1.nested2.nested3.A is nested3.A assert A.__name__ == 'A' assert A.__module__ == 'cppyy.gbl.fragile.nested1.nested2.nested3' - assert A.__cppname__ == 'fragile::nested1::nested2::nested3::A' + assert A.__cpp_name__ == 'fragile::nested1::nested2::nested3::A' def test12_missing_casts(self): """Test proper handling when a hierarchy is not fully available""" - import _cppyy + import _cppyy as cppyy - k = _cppyy.gbl.fragile.K() + k = cppyy.gbl.fragile.K() assert k is k.GimeK(False) assert k is not k.GimeK(True) @@ -292,10 +292,10 @@ class AppTestFRAGILE: return # don't bother; is fixed in cling-support - import _cppyy + import _cppyy as cppyy - M = _cppyy.gbl.fragile.M - N = _cppyy.gbl.fragile.N + M = cppyy.gbl.fragile.M + N = cppyy.gbl.fragile.N assert M.kOnce == N.kOnce assert M.kTwice == N.kTwice diff --git a/pypy/module/_cppyy/test/test_operators.py b/pypy/module/_cppyy/test/test_operators.py index d3eac0dcec..c2959453bb 100644 --- a/pypy/module/_cppyy/test/test_operators.py +++ b/pypy/module/_cppyy/test/test_operators.py @@ -1,12 +1,12 @@ import py, os, sys -from .support import setup_make - +from .support import setup_make, soext currpath = py.path.local(__file__).dirpath() -test_dct = str(currpath.join("operatorsDict.so")) +test_dct = str(currpath.join("operatorsDict"))+soext def setup_module(mod): - setup_make("operatorsDict.so") + setup_make("operators") + class AppTestOPERATORS: spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) @@ -26,8 +26,9 @@ class AppTestOPERATORS: def test01_math_operators(self): """Test overloading of math operators""" - import _cppyy - number = _cppyy.gbl.number + import _cppyy as cppyy + + number = cppyy.gbl.number assert (number(20) + number(10)) == number(30) assert (number(20) + 10 ) == number(30) @@ -48,8 +49,9 @@ class AppTestOPERATORS: def test02_unary_math_operators(self): """Test overloading of unary math operators""" - import _cppyy - number = _cppyy.gbl.number + import _cppyy as cppyy + + number = cppyy.gbl.number n = number(20) n += number(10) @@ -64,8 +66,9 @@ class AppTestOPERATORS: def test03_comparison_operators(self): """Test overloading of comparison operators""" - import _cppyy - number = _cppyy.gbl.number + import _cppyy as cppyy + + number = cppyy.gbl.number assert (number(20) > number(10)) == True assert (number(20) < number(10)) == False @@ -77,8 +80,9 @@ class AppTestOPERATORS: def test04_boolean_operator(self): """Test implementation of operator bool""" - import _cppyy - number = _cppyy.gbl.number + import _cppyy as cppyy + + number = cppyy.gbl.number n = number(20) assert n @@ -89,8 +93,15 @@ class AppTestOPERATORS: def test05_exact_types(self): """Test converter operators of exact types""" - import _cppyy - gbl = _cppyy.gbl + import sys + import _cppyy as cppyy + + if sys.hexversion >= 0x3000000: + pylong = int + else: + pylong = long + + gbl = cppyy.gbl o = gbl.operator_char_star() assert o.m_str == 'operator_char_star' @@ -105,8 +116,8 @@ class AppTestOPERATORS: assert int(o) == -13 o = gbl.operator_long(); o.m_long = 42 - assert o.m_long == 42 - assert long(o) == 42 + assert o.m_long == 42 + assert pylong(o) == 42 o = gbl.operator_double(); o.m_double = 3.1415 assert o.m_double == 3.1415 @@ -115,21 +126,30 @@ class AppTestOPERATORS: def test06_approximate_types(self): """Test converter operators of approximate types""" - import _cppyy, sys - gbl = _cppyy.gbl + import sys + import _cppyy as cppyy + + if sys.hexversion >= 0x3000000: + pylong = int + maxvalue = sys.maxsize + else: + pylong = long + maxvalue = sys.maxint + + gbl = cppyy.gbl o = gbl.operator_short(); o.m_short = 256 assert o.m_short == 256 assert int(o) == 256 o = gbl.operator_unsigned_int(); o.m_uint = 2147483647 + 32 - assert o.m_uint == 2147483647 + 32 - assert long(o) == 2147483647 + 32 + assert o.m_uint == 2147483647 + 32 + assert pylong(o) == 2147483647 + 32 o = gbl.operator_unsigned_long(); - o.m_ulong = sys.maxint + 128 - assert o.m_ulong == sys.maxint + 128 - assert long(o) == sys.maxint + 128 + o.m_ulong = maxvalue + 128 + assert o.m_ulong == maxvalue + 128 + assert pylong(o) == maxvalue + 128 o = gbl.operator_float(); o.m_float = 3.14 assert round(o.m_float - 3.14, 5) == 0. @@ -138,12 +158,12 @@ class AppTestOPERATORS: def test07_virtual_operator_eq(self): """Test use of virtual bool operator==""" - import _cppyy + import _cppyy as cppyy - b1 = _cppyy.gbl.v_opeq_base(1) - b1a = _cppyy.gbl.v_opeq_base(1) - b2 = _cppyy.gbl.v_opeq_base(2) - b2a = _cppyy.gbl.v_opeq_base(2) + b1 = cppyy.gbl.v_opeq_base(1) + b1a = cppyy.gbl.v_opeq_base(1) + b2 = cppyy.gbl.v_opeq_base(2) + b2a = cppyy.gbl.v_opeq_base(2) assert b1 == b1 assert b1 == b1a @@ -152,10 +172,10 @@ class AppTestOPERATORS: assert b2 == b2 assert b2 == b2a - d1 = _cppyy.gbl.v_opeq_derived(1) - d1a = _cppyy.gbl.v_opeq_derived(1) - d2 = _cppyy.gbl.v_opeq_derived(2) - d2a = _cppyy.gbl.v_opeq_derived(2) + d1 = cppyy.gbl.v_opeq_derived(1) + d1a = cppyy.gbl.v_opeq_derived(1) + d2 = cppyy.gbl.v_opeq_derived(2) + d2a = cppyy.gbl.v_opeq_derived(2) # derived operator== returns opposite assert not d1 == d1 diff --git a/pypy/module/_cppyy/test/test_pythonify.py b/pypy/module/_cppyy/test/test_pythonify.py index d3bb5f6624..f7856258e3 100644 --- a/pypy/module/_cppyy/test/test_pythonify.py +++ b/pypy/module/_cppyy/test/test_pythonify.py @@ -1,14 +1,14 @@ import py, os, sys -from .support import setup_make +from .support import setup_make, soext from pypy.module._cppyy import interp_cppyy, executor - currpath = py.path.local(__file__).dirpath() -test_dct = str(currpath.join("example01Dict.so")) +test_dct = str(currpath.join("example01Dict"))+soext def setup_module(mod): - setup_make("example01Dict.so") + setup_make("example01") + class AppTestPYTHONIFY: spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) diff --git a/pypy/module/_cppyy/test/test_pythonization.py b/pypy/module/_cppyy/test/test_pythonization.py index 7ef7a9df7b..14fecf18f5 100644 --- a/pypy/module/_cppyy/test/test_pythonization.py +++ b/pypy/module/_cppyy/test/test_pythonization.py @@ -1,13 +1,13 @@ import py, os, sys from pytest import raises -from .support import setup_make - +from .support import setup_make, soext currpath = py.path.local(__file__).dirpath() -test_dct = str(currpath.join("pythonizablesDict.so")) +test_dct = str(currpath.join("pythonizablesDict"))+soext def setup_module(mod): - setup_make("pythonizablesDict.so") + setup_make("pythonizables") + class AppTestPYTHONIZATION: spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) @@ -172,9 +172,9 @@ class AppTestPYTHONIZATION: import _cppyy as cppyy def root_pythonizor(klass, name): - if name == 'TString': + if name == 'CppyyLegacy::TString': klass.__len__ = klass.Length cppyy.py.add_pythonization(root_pythonizor) - assert len(cppyy.gbl.TString("aap")) == 3 + assert len(cppyy.gbl.CppyyLegacy.TString("aap")) == 3 diff --git a/pypy/module/_cppyy/test/test_regression.py b/pypy/module/_cppyy/test/test_regression.py index 21f82a4f31..70affb2c71 100644 --- a/pypy/module/_cppyy/test/test_regression.py +++ b/pypy/module/_cppyy/test/test_regression.py @@ -1,6 +1,4 @@ import py, os, sys -from .support import setup_make - from pypy.module._cppyy import interp_cppyy, executor diff --git a/pypy/module/_cppyy/test/test_stltypes.py b/pypy/module/_cppyy/test/test_stltypes.py index 8ef0266fda..f4601f1b7c 100644 --- a/pypy/module/_cppyy/test/test_stltypes.py +++ b/pypy/module/_cppyy/test/test_stltypes.py @@ -1,12 +1,12 @@ import py, os, sys -from .support import setup_make - +from .support import setup_make, soext currpath = py.path.local(__file__).dirpath() -test_dct = str(currpath.join("stltypesDict.so")) +test_dct = str(currpath.join("stltypesDict"))+soext def setup_module(mod): - setup_make("stltypesDict.so") + setup_make("stltypes") + class AppTestSTLVECTOR: spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) diff --git a/pypy/module/_cppyy/test/test_templates.py b/pypy/module/_cppyy/test/test_templates.py index 48a4bff32e..3af808b58a 100644 --- a/pypy/module/_cppyy/test/test_templates.py +++ b/pypy/module/_cppyy/test/test_templates.py @@ -1,12 +1,12 @@ -import py, os, sys -from .support import setup_make - +import py, os +from .support import setup_make, soext currpath = py.path.local(__file__).dirpath() -test_dct = str(currpath.join("templatesDict.so")) +test_dct = str(currpath.join("templatesDict"))+soext def setup_module(mod): - setup_make("templatesDict.so") + setup_make("templates") + class AppTestTEMPLATES: spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) @@ -21,13 +21,13 @@ class AppTestTEMPLATES: def test01_template_member_functions(self): """Template member functions lookup and calls""" - import _cppyy + import _cppyy as cppyy + import sys - m = _cppyy.gbl.MyTemplatedMethodClass() + m = cppyy.gbl.MyTemplatedMethodClass() # implicit (called before other tests to check caching) assert m.get_size(1) == m.get_int_size()+1 - assert 'get_size<int>' in dir(_cppyy.gbl.MyTemplatedMethodClass) # pre-instantiated assert m.get_size['char']() == m.get_char_size() @@ -48,22 +48,20 @@ class AppTestTEMPLATES: assert m.get_size[float]() == m.get_float_size() assert m.get_size['double']() == m.get_double_size() assert m.get_size['MyTemplatedMethodClass']() == m.get_self_size() - assert 'get_size<MyTemplatedMethodClass>' in dir(_cppyy.gbl.MyTemplatedMethodClass) # auto through typedef assert m.get_size['MyTMCTypedef_t']() == m.get_self_size() - assert 'get_size<MyTMCTypedef_t>' in dir(_cppyy.gbl.MyTemplatedMethodClass) assert m.get_size['MyTemplatedMethodClass']() == m.get_self_size() def test02_non_type_template_args(self): """Use of non-types as template arguments""" - import _cppyy + import _cppyy as cppyy - _cppyy.gbl.gInterpreter.Declare("template<int i> int nt_templ_args() { return i; };") + cppyy.gbl.gInterpreter.Declare("template<int i> int nt_templ_args() { return i; };") - assert _cppyy.gbl.nt_templ_args[1]() == 1 - assert _cppyy.gbl.nt_templ_args[256]() == 256 + assert cppyy.gbl.nt_templ_args[1]() == 1 + assert cppyy.gbl.nt_templ_args[256]() == 256 def test03_templated_function(self): """Templated global and static functions lookup and calls""" @@ -116,74 +114,76 @@ class AppTestTEMPLATES: def test04_variadic_function(self): """Call a variadic function""" - import _cppyy + import _cppyy as cppyy + std = cppyy.gbl.std - s = _cppyy.gbl.std.ostringstream('(', _cppyy.gbl.std.ios_base.ate) - # Fails; selects void* overload (?!) + s = std.ostringstream('(', std.ios_base.ate) + # Fails; wrong overload on PyPy, none on CPython #s << "(" - _cppyy.gbl.SomeNS.tuplify(s, 1, 4., "aap") + cppyy.gbl.SomeNS.tuplify(s, 1, 4., "aap") assert s.str() == "(1, 4, aap, NULL)" - _cppyy.gbl.gInterpreter.Declare(""" + cppyy.gbl.gInterpreter.Declare(""" template<typename... myTypes> int test04_variadic_func() { return sizeof...(myTypes); } """) - assert _cppyy.gbl.test04_variadic_func['int', 'double', 'void*']() == 3 + assert cppyy.gbl.test04_variadic_func['int', 'double', 'void*']() == 3 def test05_variadic_overload(self): """Call an overloaded variadic function""" - import _cppyy + import _cppyy as cppyy - assert _cppyy.gbl.isSomeInt(3.) == False - assert _cppyy.gbl.isSomeInt(1) == True - assert _cppyy.gbl.isSomeInt() == False - assert _cppyy.gbl.isSomeInt(1, 2, 3) == False + assert cppyy.gbl.isSomeInt(3.) == False + assert cppyy.gbl.isSomeInt(1) == True + assert cppyy.gbl.isSomeInt() == False + assert cppyy.gbl.isSomeInt(1, 2, 3) == False def test06_variadic_sfinae(self): """Attribute testing through SFINAE""" - import _cppyy - Obj1 = _cppyy.gbl.AttrTesting.Obj1 - Obj2 = _cppyy.gbl.AttrTesting.Obj2 - has_var1 = _cppyy.gbl.AttrTesting.has_var1 - call_has_var1 = _cppyy.gbl.AttrTesting.call_has_var1 - - move = _cppyy.gbl.std.move + import _cppyy as cppyy + cppyy.gbl.AttrTesting # load + Obj1 = cppyy.gbl.AttrTesting.Obj1 + Obj2 = cppyy.gbl.AttrTesting.Obj2 + has_var1 = cppyy.gbl.AttrTesting.has_var1 + call_has_var1 = cppyy.gbl.AttrTesting.call_has_var1 assert has_var1(Obj1()) == hasattr(Obj1(), 'var1') assert has_var1(Obj2()) == hasattr(Obj2(), 'var1') assert has_var1(3) == hasattr(3, 'var1') assert has_var1("aap") == hasattr("aap", 'var1') + move = cppyy.gbl.std.move + assert call_has_var1(move(Obj1())) == True assert call_has_var1(move(Obj2())) == False def test07_type_deduction(self): """Traits/type deduction""" - import _cppyy - Obj1 = _cppyy.gbl.AttrTesting.Obj1 - Obj2 = _cppyy.gbl.AttrTesting.Obj2 - select_template_arg = _cppyy.gbl.AttrTesting.select_template_arg + import _cppyy as cppyy + cppyy.gbl.AttrTesting # load + select_template_arg = cppyy.gbl.AttrTesting.select_template_arg + Obj1 = cppyy.gbl.AttrTesting.Obj1 + Obj2 = cppyy.gbl.AttrTesting.Obj2 - # assert select_template_arg[0, Obj1, Obj2].argument == Obj1 + #assert select_template_arg[0, Obj1, Obj2].argument == Obj1 assert select_template_arg[1, Obj1, Obj2].argument == Obj2 raises(TypeError, select_template_arg.__getitem__, 2, Obj1, Obj2) - # TODO, this doesn't work for builtin types as the 'argument' - # typedef will not resolve to a class - #assert select_template_arg[1, int, float].argument == float + # TODO: the following only results in a Cling compilation error + #assert select_template_arg[1, int, float].argument == float def test08_using_of_static_data(self): """Derived class using static data of base""" - import _cppyy + import _cppyy as cppyy # TODO: the following should live in templates.h, but currently fails # in TClass::GetListOfMethods() - _cppyy.gbl.gInterpreter.Declare(""" + cppyy.gbl.gInterpreter.Declare(""" template <typename T> struct BaseClassWithStatic { static T const ref_value; }; @@ -202,12 +202,10 @@ class AppTestTEMPLATES: T m_value; };""") + assert cppyy.gbl.BaseClassWithStatic["size_t"].ref_value == 42 - # TODO: the ref_value property is inaccessible (offset == -1) - # assert _cppyy.gbl.BaseClassWithStatic["size_t"].ref_value == 42 - - b1 = _cppyy.gbl.DerivedClassUsingStatic["size_t"]( 0) - b2 = _cppyy.gbl.DerivedClassUsingStatic["size_t"](100) + b1 = cppyy.gbl.DerivedClassUsingStatic["size_t"]( 0) + b2 = cppyy.gbl.DerivedClassUsingStatic["size_t"](100) # assert b1.ref_value == 42 assert b1.m_value == 0 @@ -215,61 +213,635 @@ class AppTestTEMPLATES: # assert b2.ref_value == 42 assert b2.m_value == 42 + def test09_templated_callable(self): + """Test that templated operator() translates to __call__""" + + import _cppyy as cppyy + + tc = cppyy.gbl.TemplatedCallable() + + assert tc(5) == 5. + + def test10_templated_hidding_methods(self): + """Test that base class methods are not considered when hidden""" + + import _cppyy as cppyy + + B = cppyy.gbl.TemplateHiding.Base + D = cppyy.gbl.TemplateHiding.Derived + + assert B().callme(1) == 2 + assert D().callme() == 2 + assert D().callme(2) == 2 + + def test11_templated_ctor(self): + """Test templated constructors""" + + import _cppyy as cppyy + + cppyy.gbl.gInterpreter.Declare(""" + template <typename T> + class RTTest_SomeClassWithTCtor { + public: + template<typename R> + RTTest_SomeClassWithTCtor(int n, R val) : m_double(n+val) {} + double m_double; + }; + + namespace RTTest_SomeNamespace { + + template <typename T> + class RTTest_SomeClassWithTCtor { + public: + RTTest_SomeClassWithTCtor() : m_double(-1.) {} + template<typename R> + RTTest_SomeClassWithTCtor(int n, R val) : m_double(n+val) {} + double m_double; + }; + + } + """) + + gbl = cppyy.gbl + + assert round(gbl.RTTest_SomeClassWithTCtor[int](1, 3.1).m_double - 4.1, 8) == 0. + + RTTest2 = gbl.RTTest_SomeNamespace.RTTest_SomeClassWithTCtor + assert round(RTTest2[int](1, 3.1).m_double - 4.1, 8) == 0. + assert round(RTTest2[int]().m_double + 1., 8) == 0. + + def test12_template_aliases(self): + """Access to templates made available with 'using'""" + + import _cppyy as cppyy + + # through dictionary + davec = cppyy.gbl.DA_vector["float"]() + davec += range(10) + assert davec[5] == 5 + + # through interpreter + cppyy.gbl.gInterpreter.Declare("template<typename T> using IA_vector = std::vector<T>;") + iavec = cppyy.gbl.IA_vector["float"]() + iavec += range(10) + assert iavec[5] == 5 + + # with variadic template + if cppyy.gbl.gInterpreter.ProcessLine("__cplusplus;") > 201402: + assert cppyy.gbl.using_problem.matryoshka[int, 3].type + assert cppyy.gbl.using_problem.matryoshka[int, 3, 4].type + assert cppyy.gbl.using_problem.make_vector[int , 3] + assert cppyy.gbl.using_problem.make_vector[int , 3]().m_val == 3 + assert cppyy.gbl.using_problem.make_vector[int , 4]().m_val == 4 + + def test13_using_templated_method(self): + """Access to base class templated methods through 'using'""" + + import _cppyy as cppyy + + b = cppyy.gbl.using_problem.Base[int]() + assert type(b.get3()) == int + assert b.get3() == 5 + assert type(b.get3['double'](5)) == float + assert b.get3['double'](5) == 10. + + d = cppyy.gbl.using_problem.Derived[int]() + #assert type(d.get1['double'](5)) == float + #assert d.get1['double'](5) == 10. + + assert type(d.get2()) == int + assert d.get2() == 5 + + assert type(d.get3['double'](5)) == float + assert d.get3['double'](5) == 10. + assert type(d.get3()) == int + assert d.get3() == 5 + + def test14_templated_return_type(self): + """Use of a templated return type""" + + import _cppyy as cppyy + + cppyy.gbl.gInterpreter.Declare(""" + struct RTTest_SomeStruct1 {}; + template<class ...T> struct RTTest_TemplatedList {}; + template<class ...T> auto rttest_make_tlist(T ... args) { + return RTTest_TemplatedList<T...>{}; + } + + namespace RTTest_SomeNamespace { + struct RTTest_SomeStruct2 {}; + template<class ...T> struct RTTest_TemplatedList2 {}; + } + + template<class ...T> auto rttest_make_tlist2(T ... args) { + return RTTest_SomeNamespace::RTTest_TemplatedList2<T...>{}; + } + """) + + rttest_make_tlist = cppyy.gbl.rttest_make_tlist + rttest_make_tlist2 = cppyy.gbl.rttest_make_tlist2 + RTTest_SomeNamespace = cppyy.gbl.RTTest_SomeNamespace + RTTest_SomeStruct1 = cppyy.gbl.RTTest_SomeStruct1 + + assert rttest_make_tlist(RTTest_SomeStruct1()) + assert rttest_make_tlist(RTTest_SomeNamespace.RTTest_SomeStruct2()) + assert rttest_make_tlist2(RTTest_SomeStruct1()) + assert rttest_make_tlist2(RTTest_SomeNamespace.RTTest_SomeStruct2()) + + def test15_rvalue_templates(self): + """Use of a template with r-values; should accept builtin types""" + + import _cppyy as cppyy + + is_valid = cppyy.gbl.T_WithRValue.is_valid + + # bit of regression testing + assert is_valid(3) + assert is_valid['int'](3) # used to crash + + # actual method calls + assert is_valid[int](1) + assert not is_valid(0) + assert is_valid(1.) + assert not is_valid(0.) + + def test16_variadic(self): + """Range of variadic templates""" + + import _cppyy as cppyy + + ns = cppyy.gbl.some_variadic + + def get_tn(ns): + # helper to make all platforms look the same + tn = ns.gTypeName + tn = tn.replace(' ', '') + tn = tn.replace('class', '') + tn = tn.replace('__cdecl', '') + tn = tn.replace('__thiscall', '') + tn = tn.replace('__ptr64', '') + return tn + + # templated class + a = ns.A['int', 'double']() + assert get_tn(ns) == "some_variadic::A<int,double>" + + # static functions + a.sa(1, 1., 'a') + assert get_tn(ns).find("some_variadic::A<int,double>::void(int&&,double&&,std::") == 0 + ns.A['char&', 'double*'].sa(1, 1., 'a') + assert get_tn(ns).find("some_variadic::A<char&,double*>::void(int&&,double&&,std::") == 0 + ns.A['char&', 'double*'].sa_T['int'](1, 1., 'a') + assert get_tn(ns).find("some_variadic::A<char&,double*>::int(int&&,double&&,std::") == 0 + + # member functions + a.a(1, 1., 'a') + assert get_tn(ns).find("void(some_variadic::A<int,double>::*)(int&&,double&&,std::") == 0 + a.a_T['int'](1, 1., 'a') + assert get_tn(ns).find("int(some_variadic::A<int,double>::*)(int&&,double&&,std::") == 0 + + # non-templated class + b = ns.B() + assert get_tn(ns) == "some_variadic::B" + + # static functions + b.sb(1, 1., 'a') + assert get_tn(ns).find("some_variadic::B::void(int&&,double&&,std::") == 0 + ns.B.sb(1, 1., 'a') + assert get_tn(ns).find("some_variadic::B::void(int&&,double&&,std::") == 0 + ns.B.sb_T['int'](1, 1., 'a') + assert get_tn(ns).find("some_variadic::B::int(int&&,double&&,std::") == 0 + + # member functions + b.b(1, 1., 'a') + assert get_tn(ns).find("void(some_variadic::B::*)(int&&,double&&,std::") == 0 + b.b_T['int'](1, 1., 'a') + assert get_tn(ns).find("int(some_variadic::B::*)(int&&,double&&,std::") == 0 + + def test17_empty_body(self): + """Use of templated function with empty body""" + + import _cppyy as cppyy + + f_T = cppyy.gbl.T_WithEmptyBody.some_empty + + assert cppyy.gbl.T_WithEmptyBody.side_effect == "not set" + assert f_T[int]() is None + assert cppyy.gbl.T_WithEmptyBody.side_effect == "side effect" + + def test18_greedy_overloads(self): + """void*/void** should not pre-empt template instantiations""" + + import _cppyy as cppyy + + ns = cppyy.gbl.T_WithGreedyOverloads + + # check that void* does not mask template instantiations + g1 = ns.WithGreedy1() + assert g1.get_size(ns.SomeClass(), True) == -1 + assert g1.get_size(ns.SomeClass()) == cppyy.sizeof(ns.SomeClass) + + # check that void* does not mask template instantiations + g2 = ns.WithGreedy2() + assert g2.get_size(ns.SomeClass()) == cppyy.sizeof(ns.SomeClass) + assert g2.get_size(ns.SomeClass(), True) == -1 + + # check that unknown classes do not mask template instantiations + g3 = ns.WithGreedy3() + assert g3.get_size(ns.SomeClass()) == cppyy.sizeof(ns.SomeClass) + assert g3.get_size(cppyy.nullptr, True) == -1 + + def test19_templated_operator_add(self): + """Templated operator+ is ambiguous: either __pos__ or __add__""" + + import _cppyy as cppyy + gbl = cppyy.gbl + + cppyy.gbl.gInterpreter.Declare(""" + namespace OperatorAddTest { + template <class V> + class CustomVec { + V fX; + public: + CustomVec() : fX(0) {} + CustomVec(const V & a) : fX(a) { } + V X() const { return fX; } + template <class fV> CustomVec operator + (const fV& v) { + CustomVec<V> u; + u.fX = fX + v.fX; + return u; + } + }; } + """) + + c = gbl.OperatorAddTest.CustomVec['double'](5.3) + d = gbl.OperatorAddTest.CustomVec['int'](1) + + q = c + d + + assert round(q.X() - 6.3, 8) == 0. + + def test20_templated_ctor_with_defaults(self): + """Templated constructor with defaults used to be ignored""" + + import _cppyy as cppyy + + cppyy.gbl.gInterpreter.Declare(r""" + namespace TemplatedCtor { class C { + public: + template <typename Integer, typename std::enable_if_t<std::is_integral_v<Integer>, int> = 0> + C(Integer) {} + C(const std::string&) {} + }; } + """) + + assert cppyy.gbl.TemplatedCtor.C(0) + + def test21_type_deduction_with_conversion(self): + """Template instantiation with [] -> std::vector conversion""" + + import _cppyy as cppyy + + cppyy.gbl.gInterpreter.Declare(""" + namespace l2v { + struct Base {}; + struct Derived : Base {}; + + int test1(const std::vector<Base*>& v) { return (int)v.size(); } + + template <typename T> + int test2(const std::vector<Derived*>& v) { return (int)v.size(); } + + template <typename T> + int test2a(std::vector<Derived*> v) { return v.size(); } + + template <typename T> + int test3(const std::vector<Base*>& v) { return (int)v.size(); } + }""") + + l2v = cppyy.gbl.l2v + + d1 = l2v.Derived() + + assert l2v.test1([d1]) == 1 + assert l2v.test1([d1, d1]) == 2 + + assert l2v.test2[int]([d1]) == 1 + assert l2v.test2[int]([d1, d1]) == 2 + + assert l2v.test2a[int]([d1]) == 1 + assert l2v.test2a[int]([d1, d1]) == 2 + + assert l2v.test3[int]([d1]) == 1 + assert l2v.test3[int]([d1, d1]) == 2 -class AppTestBOOSTANY: + def test22_type_deduction_of_proper_integer_size(self): + """Template type from integer arg should be big enough""" + + import _cppyy as cppyy + + cppyy.gbl.gInterpreter.Declare("template <typename T> T PassSomeInt(T t) { return t; }") + + PassSomeInt = cppyy.gbl.PassSomeInt + + for val in [1, 100000000000, -2**32, 2**32-1, 2**64-1 -2**63]: + assert val == PassSomeInt(val) + + for val in [2**64, -2**63-1]: + raises(OverflowError, PassSomeInt, val) + + def test23_overloaded_setitem(self): + """Template with overloaded non-templated and templated setitem""" + + import _cppyy as cppyy + + MyVec = cppyy.gbl.TemplateWithSetItem.MyVec + + v = MyVec["float"](2) + v[0] = 1 # used to throw TypeError + + def test24_stdfunction_templated_arguments(self): + """Use of std::function with templated arguments""" + + import _cppyy as cppyy + + def callback(x): + return sum(x) + + cppyy.gbl.gInterpreter.Declare("""double callback_vector( + const std::function<double(std::vector<double>)>& callback, std::vector<double> x) { + return callback(x); + }""") + + assert cppyy.gbl.std.function['double(std::vector<double>)'] + + assert cppyy.gbl.callback_vector(callback, [1, 2, 3]) == 6 + + cppyy.gbl.gInterpreter.Declare("""double wrap_callback_vector( + double (*callback)(std::vector<double>), std::vector<double> x) { + return callback_vector(callback, x); + }""") + + assert cppyy.gbl.wrap_callback_vector(callback, [4, 5, 6]) == 15 + + assert cppyy.gbl.std.function['double(std::vector<double>)'] + + def test25_partial_templates(self): + """Deduction of types with partial templates""" + + import _cppyy as cppyy + + cppyy.gbl.gInterpreter.Declare("""\ + template <typename A, typename B> + B partial_template_foo1(B b) { return b; } + + template <typename A, typename B> + B partial_template_foo2(B b) { return b; } + + namespace partial_template { + template <typename A, typename B> + B foo1(B b) { return b; } + + template <typename A, typename B> + B foo2(B b) { return b; } + } + """) + + ns = cppyy.gbl.partial_template + + assert cppyy.gbl.partial_template_foo1['double', 'int'](17) == 17 + assert cppyy.gbl.partial_template_foo1['double'](17) == 17 + + assert cppyy.gbl.partial_template_foo1['double'](17) == 17 + assert cppyy.gbl.partial_template_foo1['double', 'int'](17) == 17 + + assert ns.foo1['double', 'int'](17) == 17 + assert ns.foo1['double'](17) == 17 + + assert ns.foo2['double'](17) == 17 + assert ns.foo2['double', 'int'](17) == 17 + + cppyy.gbl.gInterpreter.Declare("""\ + template <typename A, typename... Other, typename B> + B partial_template_bar1(B b) { return b; } + + template <typename A, typename... Other, typename B> + B partial_template_bar2(B b) { return b; } + + namespace partial_template { + template <typename A, typename... Other, typename B> + B bar1(B b) { return b; } + + template <typename A, typename... Other, typename B> + B bar2(B b) { return b; } + }""") + + assert cppyy.gbl.partial_template_bar1['double','int'](17) == 17 + assert cppyy.gbl.partial_template_bar1['double'](17) == 17 + + assert cppyy.gbl.partial_template_bar2['double'](17) == 17 + assert cppyy.gbl.partial_template_bar2['double','int'](17) == 17 + + assert ns.bar1['double','int'](17) == 17 + assert ns.bar1['double'](17) == 17 + + assert ns.bar2['double'](17) == 17 + assert ns.bar2['double','int'](17) == 17 + + def test26_variadic_constructor(self): + """Use of variadic template function as contructor""" + + import _cppyy as cppyy + + cppyy.gbl.gInterpreter.Declare("""\ + namespace VadiadicConstructor { + class Atom { + public: + using mass_type = double; + + Atom() {} + + template<typename... Args> + explicit Atom(const mass_type& mass_in, Args&&... args) : + Atom(std::forward<Args>(args)...) { + constexpr bool is_mass = + std::disjunction_v<std::is_same<std::decay_t<Args>, mass_type>...>; + static_assert(!is_mass, "Please only provide one mass"); + mass() = mass_in; + } + + mass_type& mass() noexcept { + return m_m; + } + + mass_type m_m = 0.0; + }; }""") + + ns = cppyy.gbl.VadiadicConstructor + + a = ns.Atom(1567.0) + assert a.m_m == 1567.0 + + def test27_enum_in_constructor(self): + """Use of enums in template function as constructor""" + + import _cppyy as cppyy + + cppyy.gbl.gInterpreter.Declare("""\ + namespace EnumConstructor { + struct ST { + enum TI { I32 }; + }; + + struct FS { + enum R { EQ, NE, GT, GE, LT, LE }; + + template<typename T> + FS(const std::string&, const ST::TI, R, const T&e) {} + }; }""") + + ns = cppyy.gbl.EnumConstructor + + assert ns.FS('i', ns.ST.I32, ns.FS.EQ, 10) + assert ns.FS('i', ns.ST.TI.I32, ns.FS.R.EQ, 10) + + +class AppTestTEMPLATED_TYPEDEFS: spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) def setup_class(cls): cls.w_test_dct = cls.space.newtext(test_dct) cls.w_templates = cls.space.appexec([], """(): import ctypes, _cppyy - _cppyy._post_import_startup()""") + _cppyy._post_import_startup() + return ctypes.CDLL(%r, ctypes.RTLD_GLOBAL)""" % (test_dct, )) + + def test01_using(self): + """Test presence and validity of using typededs""" + + import _cppyy as cppyy + + tct = cppyy.gbl.TemplatedTypedefs.DerivedWithUsing + dum = cppyy.gbl.TemplatedTypedefs.SomeDummy + + assert tct[int, dum, 4].vsize == 4 + assert tct[int, dum, 8].vsize == 8 + + in_type = tct[int, dum, 4].in_type + assert 'in_type' in dir(tct[int, dum, 4]) + + assert in_type.__name__ == 'in_type' + assert in_type.__cpp_name__ == 'TemplatedTypedefs::DerivedWithUsing<int,TemplatedTypedefs::SomeDummy,4>::in_type' + + in_type_tt = tct[int, dum, 4].in_type_tt + assert 'in_type_tt' in dir(tct[int, dum, 4]) + + assert in_type_tt.__name__ == 'in_type_tt' + assert in_type_tt.__cpp_name__ == 'TemplatedTypedefs::DerivedWithUsing<int,TemplatedTypedefs::SomeDummy,4>::in_type_tt' + + def test02_mapped_type_as_internal(self): + """Test that mapped types can be used as builting""" + + import _cppyy as cppyy + tct = cppyy.gbl.TemplatedTypedefs.DerivedWithUsing + dum = cppyy.gbl.TemplatedTypedefs.SomeDummy + + for argname in ['short', 'unsigned short', 'int']: + in_type = tct[argname, dum, 4].in_type + assert issubclass(in_type, int) + assert in_type(13) == 13 + assert 2*in_type(42) - 84 == 0 + + for argname in ['unsigned int', 'long', 'unsigned long']:# TODO: 'long long', 'unsigned long long' + in_type = tct[argname, dum, 4].in_type + assert issubclass(in_type, pylong) + assert in_type(13) == 13 + assert 2*in_type(42) - 84 == 0 - def test01_any_class(self): - """Usage of boost::any""" + for argname in ['float', 'double', 'long double']: + in_type = tct[argname, dum, 4].in_type + assert issubclass(in_type, float) + assert in_type(13) == 13. + assert 2*in_type(42) - 84. == 0. - import _cppyy + raises(TypeError, tct.__getitem__, 'gibberish', dum, 4) - if not _cppyy.gbl.gInterpreter.Declare('#include "boost/any.hpp"'): - import warnings - warnings.warn('skipping boost/any testing') - return + def test03_mapped_type_as_template_arg(self): + """Test that mapped types can be used as template arguments""" - assert _cppyy.gbl.boost - assert _cppyy.gbl.boost.any + import _cppyy as cppyy + + tct = cppyy.gbl.TemplatedTypedefs.DerivedWithUsing + dum = cppyy.gbl.TemplatedTypedefs.SomeDummy + + in_type = tct['unsigned int', dum, 4].in_type + assert tct['unsigned int', dum, 4] is tct[in_type, dum, 4] + + in_type = tct['long double', dum, 4].in_type + assert tct['long double', dum, 4] is tct[in_type, dum, 4] + assert tct['double', dum, 4] is not tct[in_type, dum, 4] + + def test04_type_deduction(self): + """Usage of type reducer""" + + import _cppyy as cppyy + + cppyy.gbl.gInterpreter.Declare(""" + template <typename T> struct DeductTest_Wrap { + static auto whatis(T t) { return t; } + }; + """) + + w = cppyy.gbl.DeductTest_Wrap[int]() + three = w.whatis(3) + assert three == 3 + + def test05_type_deduction_and_extern(self): + """Usage of type reducer with extern template""" + + import _cppyy as cppyy + import sys - std, boost = _cppyy.gbl.std, _cppyy.gbl.boost + cppyy.gbl.gInterpreter.Declare("""\ + namespace FailedTypeDeducer { - assert std.list[boost.any] + template<class T> + class A { + public: + T result() { return T{5}; } + }; + + extern template class A<int>; + }""") - val = boost.any() - # test both by-ref and by rvalue - v = std.vector[int]() - val.__assign__(v) - val.__assign__(std.move(std.vector[int](range(100)))) + if sys.platform != 'darwin': # feature disabled + assert cppyy.gbl.FailedTypeDeducer.A[int]().result() == 42 + assert cppyy.gbl.FailedTypeDeducer.A['double']().result() == 5. - _cppyy.gbl.gInterpreter.ProcessLine( - "namespace _cppyy_internal { auto* stdvectid = &typeid(std::vector<int>); }") + # FailedTypeDeducer::B is defined in the templates.h header + assert cppyy.gbl.FailedTypeDeducer.B['double']().result() == 5. + assert cppyy.gbl.FailedTypeDeducer.B[int]().result() == 5 - assert val.type() == _cppyy.gbl._cppyy_internal.stdvectid - extract = boost.any_cast[std.vector[int]](val) - assert type(extract) is std.vector[int] - assert len(extract) == 100 - extract += range(100) - assert len(extract) == 200 +class AppTestTEMPLATE_TYPE_REDUCTION: + spaceconfig = dict(usemodules=['_cppyy', '_rawffi', 'itertools']) + + def setup_class(cls): + cls.w_test_dct = cls.space.newtext(test_dct) + cls.w_templates = cls.space.appexec([], """(): + import ctypes, _cppyy + _cppyy._post_import_startup() + return ctypes.CDLL(%r, ctypes.RTLD_GLOBAL)""" % (test_dct, )) + + def test01_reduce_binary(self): + """Squash template expressions for binary operations (like in gmpxx)""" + + import _cppyy as cppyy - val.__assign__(std.move(extract)) # move forced + e1 = cppyy.gbl.TypeReduction.Expr[int]() + e2 = cppyy.gbl.TypeReduction.Expr[int]() - # TODO: we hit boost::any_cast<int>(boost::any* operand) instead - # of the reference version which raises - boost.any_cast.__useffi__ = False - try: - # raises(Exception, boost.any_cast[int], val) - assert not boost.any_cast[int](val) - except Exception: - # getting here is good, too ... - pass + cppyy.py.add_type_reducer('TypeReduction::BinaryExpr<int>', 'TypeReduction::Expr<int>') - extract = boost.any_cast[std.vector[int]](val) - assert len(extract) == 200 + assert type(e1+e2) == cppyy.gbl.TypeReduction.Expr[int] diff --git a/pypy/module/_cppyy/test/test_zjit.py b/pypy/module/_cppyy/test/test_zjit.py index 4604477554..7f55593bf9 100644 --- a/pypy/module/_cppyy/test/test_zjit.py +++ b/pypy/module/_cppyy/test/test_zjit.py @@ -1,5 +1,5 @@ import py, os, sys -from .support import setup_make +from .support import setup_make, soext from rpython.jit.metainterp.test.support import LLJitMixin from rpython.rlib.objectmodel import specialize, instantiate @@ -33,12 +33,11 @@ def get_tlobj(self): return self._tlobj llinterp.LLInterpreter.get_tlobj = get_tlobj - currpath = py.path.local(__file__).dirpath() -test_dct = str(currpath.join("example01Dict.so")) +test_dct = str(currpath.join("example01Dict"))+soext def setup_module(mod): - setup_make("example01Dict.so") + setup_make("example01") class FakeBase(W_Root): @@ -57,10 +56,18 @@ class FakeFloat(FakeBase): typename = "float" def __init__(self, val): self.val = val +class FakeComplex(FakeBase): + typename = "complex" + def __init__(self, rval, ival): + self.obj = (rval, ival) class FakeString(FakeBase): typename = "str" def __init__(self, val): self.val = val +class FakeUnicode(FakeBase): + typename = "unicode" + def __init__(self, val): + self.val = val class FakeTuple(FakeBase): typename = "tuple" def __init__(self, val): @@ -133,8 +140,11 @@ class FakeSpace(object): self.w_AttributeError = FakeException(self, "AttributeError") self.w_Exception = FakeException(self, "Exception") + self.w_ImportError = FakeException(self, "ImportError") self.w_KeyError = FakeException(self, "KeyError") + self.w_LookupError = FakeException(self, "LookupError") self.w_NotImplementedError = FakeException(self, "NotImplementedError") + self.w_OSError = FakeException(self, "OSError") self.w_ReferenceError = FakeException(self, "ReferenceError") self.w_RuntimeError = FakeException(self, "RuntimeError") self.w_SystemError = FakeException(self, "SystemError") @@ -176,6 +186,10 @@ class FakeSpace(object): return FakeFloat(obj) @specialize.argtype(1) + def newcomplex(self, rval, ival): + return FakeComplex(rval, ival) + + @specialize.argtype(1) def newbytes(self, obj): return FakeString(obj) @@ -194,6 +208,18 @@ class FakeSpace(object): assert isinstance(w_obj, FakeFloat) return w_obj.val + def newutf8(self, obj, sz): + return FakeUnicode(obj) + + def unicode_from_object(self, w_obj): + if isinstance (w_obj, FakeUnicode): + return w_obj + return FakeUnicode(w_obj.utf8_w(self)) + + def utf8_len_w(self, w_obj): + assert isinstance(w_obj, FakeUnicode) + return w_obj.val, len(w_obj.val) + @specialize.arg(1) def interp_w(self, RequiredClass, w_obj, can_be_None=False): if can_be_None and w_obj is None: @@ -208,6 +234,7 @@ class FakeSpace(object): def exception_match(self, typ, sub): return typ is sub + @specialize.argtype(1) def is_none(self, w_obj): return w_obj is None |