def ttree_Branch(space, w_self, args_w): """Pythonized version of TTree::Branch(): takes proxy objects and by-passes the CINT-manual layer.""" from pypy.module.cppyy import interp_cppyy tree_class = interp_cppyy.scope_byname(space, "TTree") # sigs to modify (and by-pass CINT): # 1. (const char*, const char*, T**, Int_t=32000, Int_t=99) # 2. (const char*, T**, Int_t=32000, Int_t=99) argc = len(args_w) # basic error handling of wrong arguments is best left to the original call, # so that error messages etc. remain consistent in appearance: the following # block may raise TypeError or IndexError to break out anytime try: if argc < 2 or 5 < argc: raise TypeError("wrong number of arguments") tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self, can_be_None=True) if (tree is None) or (tree.cppclass != tree_class): raise TypeError("not a TTree") # first argument must always always be cont char* branchname = space.str_w(args_w[0]) # if args_w[1] is a classname, then case 1, else case 2 try: classname = space.str_w(args_w[1]) addr_idx = 2 w_address = args_w[addr_idx] except (OperationError, TypeError): addr_idx = 1 w_address = args_w[addr_idx] bufsize, splitlevel = 32000, 99 if addr_idx+1 < argc: bufsize = space.c_int_w(args_w[addr_idx+1]) if addr_idx+2 < argc: splitlevel = space.c_int_w(args_w[addr_idx+2]) # now retrieve the W_CPPInstance and build other stub arguments space = tree.space # holds the class cache in State cppinstance = space.interp_w(interp_cppyy.W_CPPInstance, w_address) address = rffi.cast(rffi.VOIDP, cppinstance.get_rawobject()) klassname = cppinstance.cppclass.full_name() vtree = rffi.cast(rffi.VOIDP, tree.get_rawobject()) # call the helper stub to by-pass CINT vbranch = _ttree_Branch(vtree, branchname, klassname, address, bufsize, splitlevel) branch_class = interp_cppyy.scope_byname(space, "TBranch") w_branch = interp_cppyy.wrap_cppobject(space, vbranch, branch_class) return w_branch except (OperationError, TypeError, IndexError): pass # return control back to the original, unpythonized overload ol = tree_class.get_overload("Branch") return ol.call(w_self, args_w)
def test01_class_query(self, space): # NOTE: this test needs to run before test_pythonify.py dct = interp_cppyy.load_dictionary(space, test_dct) w_cppyyclass = interp_cppyy.scope_byname(space, "example01") w_cppyyclass2 = interp_cppyy.scope_byname(space, "example01") assert space.is_w(w_cppyyclass, w_cppyyclass2) adddouble = w_cppyyclass.methods["staticAddToDouble"] func, = adddouble.functions assert func.executor is None func._setup(None) # creates executor assert isinstance(func.executor, executor._executors['double']) assert func.arg_defs == [("double", "")]
def test01_class_query(self): # NOTE: this test needs to run before test_pythonify.py dct = interp_cppyy.load_dictionary(space, test_dct) w_cppyyclass = interp_cppyy.scope_byname(space, "example01") w_cppyyclass2 = interp_cppyy.scope_byname(space, "example01") assert space.is_w(w_cppyyclass, w_cppyyclass2) adddouble = w_cppyyclass.methods["staticAddToDouble"] func, = adddouble.functions assert func.executor is None func._setup(None) # creates executor assert isinstance(func.executor, executor.DoubleExecutor) assert func.arg_defs == [("double", "")]
def tf1_tf1(space, w_self, args_w): """Pythonized version of TF1 constructor: takes functions and callable objects, and allows a callback into them.""" from pypy.module.cppyy import interp_cppyy tf1_class = interp_cppyy.scope_byname(space, "TF1") # expected signature: # 1. (char* name, pyfunc, double xmin, double xmax, int npar = 0) argc = len(args_w) try: if argc < 4 or 5 < argc: raise TypeError("wrong number of arguments") # first argument must be a name funcname = space.str_w(args_w[0]) # last (optional) argument is number of parameters npar = 0 if argc == 5: npar = space.int_w(args_w[4]) # second argument must be a callable python object w_callable = args_w[1] if not space.is_true(space.callable(w_callable)): raise TypeError("2nd argument is not a valid python callable") # generate a pointer to function from pypy.module._cffi_backend import newtype, ctypefunc, func c_double = newtype.new_primitive_type(space, 'double') c_doublep = newtype.new_pointer_type(space, c_double) # wrap the callable as the signature needs modifying w_ifunc = interp_cppyy.get_interface_func(space, w_callable, npar) w_cfunc = ctypefunc.W_CTypeFunc(space, [c_doublep, c_doublep], c_double, False) w_callback = func.callback(space, w_cfunc, w_ifunc, None) funcaddr = rffi.cast(rffi.ULONG, w_callback.get_closure()) # so far, so good; leaves on issue: CINT is expecting a wrapper, but # we need the overload that takes a function pointer, which is not in # the dictionary, hence this helper: newinst = _create_tf1(space.str_w(args_w[0]), funcaddr, space.float_w(args_w[2]), space.float_w(args_w[3]), npar) # w_self is a null-ptr bound as TF1 from pypy.module.cppyy.interp_cppyy import W_CPPInstance, memory_regulator cppself = space.interp_w(W_CPPInstance, w_self, can_be_None=False) cppself._rawobject = newinst memory_regulator.register(cppself) # tie all the life times to the TF1 instance space.setattr(w_self, space.wrap('_callback'), w_callback) # by definition for __init__ return None except (OperationError, TypeError, IndexError), e: newargs_w = args_w[1:] # drop class
def get_converter(space, name, default): # The matching of the name to a converter should follow: # 1) full, exact match # 1a) const-removed match # 2) match of decorated, unqualified type # 3) accept ref as pointer (for the stubs, const& can be # by value, but that does not work for the ffi path) # 4) generalized cases (covers basically all user classes) # 5) void converter, which fails on use name = capi.c_resolve_name(space, name) # 1) full, exact match try: return _converters[name](space, default) except KeyError: pass # 1a) const-removed match try: return _converters[helper.remove_const(name)](space, default) except KeyError: pass # 2) match of decorated, unqualified type compound = helper.compound(name) clean_name = capi.c_resolve_name(space, helper.clean_type(name)) try: # array_index may be negative to indicate no size or no size found array_size = helper.array_size(name) return _a_converters[clean_name + compound](space, array_size) except KeyError: pass # 3) TODO: accept ref as pointer # 4) generalized cases (covers basically all user classes) from pypy.module.cppyy import interp_cppyy cppclass = interp_cppyy.scope_byname(space, clean_name) if cppclass: # type check for the benefit of the annotator from pypy.module.cppyy.interp_cppyy import W_CPPClass cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False) if compound == "*": return InstancePtrConverter(space, cppclass) elif compound == "&": return InstanceRefConverter(space, cppclass) elif compound == "**": return InstancePtrPtrConverter(space, cppclass) elif compound == "": return InstanceConverter(space, cppclass) elif capi.c_is_enum(space, clean_name): return _converters['unsigned'](space, default) # 5) void converter, which fails on use # # return a void converter here, so that the class can be build even # when some types are unknown; this overload will simply fail on use return VoidConverter(space, name)
def get_converter(space, name, default): # The matching of the name to a converter should follow: # 1) full, exact match # 1a) const-removed match # 2) match of decorated, unqualified type # 3) accept ref as pointer (for the stubs, const& can be # by value, but that does not work for the ffi path) # 4) generalized cases (covers basically all user classes) # 5) void converter, which fails on use name = capi.c_resolve_name(space, name) # 1) full, exact match try: return _converters[name](space, default) except KeyError: pass # 1a) const-removed match try: return _converters[helper.remove_const(name)](space, default) except KeyError: pass # 2) match of decorated, unqualified type compound = helper.compound(name) clean_name = capi.c_resolve_name(space, helper.clean_type(name)) try: # array_index may be negative to indicate no size or no size found array_size = helper.array_size(name) return _a_converters[clean_name+compound](space, array_size) except KeyError: pass # 3) TODO: accept ref as pointer # 4) generalized cases (covers basically all user classes) from pypy.module.cppyy import interp_cppyy cppclass = interp_cppyy.scope_byname(space, clean_name) if cppclass: # type check for the benefit of the annotator from pypy.module.cppyy.interp_cppyy import W_CPPClass cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False) if compound == "*": return InstancePtrConverter(space, cppclass) elif compound == "&": return InstanceRefConverter(space, cppclass) elif compound == "**": return InstancePtrPtrConverter(space, cppclass) elif compound == "": return InstanceConverter(space, cppclass) elif capi.c_is_enum(space, clean_name): return _converters['unsigned'](space, default) # 5) void converter, which fails on use # # return a void converter here, so that the class can be build even # when some types are unknown; this overload will simply fail on use return VoidConverter(space, name)
def get_executor(space, name): # Matching of 'name' to an executor factory goes through up to four levels: # 1) full, qualified match # 2) drop '&': by-ref is pretty much the same as by-value, python-wise # 3) types/classes, either by ref/ptr or by value # 4) additional special cases # # If all fails, a default is used, which can be ignored at least until use. name = capi.c_resolve_name(space, name) # 1) full, qualified match try: return _executors[name](space, None) except KeyError: pass compound = helper.compound(name) clean_name = capi.c_resolve_name(space, helper.clean_type(name)) # 1a) clean lookup try: return _executors[clean_name + compound](space, None) except KeyError: pass # 2) drop '&': by-ref is pretty much the same as by-value, python-wise if compound and compound[len(compound) - 1] == '&': # TODO: this does not actually work with Reflex (?) try: return _executors[clean_name](space, None) except KeyError: pass # 3) types/classes, either by ref/ptr or by value from pypy.module.cppyy import interp_cppyy cppclass = interp_cppyy.scope_byname(space, clean_name) if cppclass: # type check for the benefit of the annotator from pypy.module.cppyy.interp_cppyy import W_CPPClass cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False) if compound == '': return InstanceExecutor(space, cppclass) elif compound == '*' or compound == '&': return InstancePtrExecutor(space, cppclass) elif compound == '**' or compound == '*&': return InstancePtrPtrExecutor(space, cppclass) elif capi.c_is_enum(space, clean_name): return _executors['unsigned int'](space, None) # 4) additional special cases if compound == '*': return _executors['void*']( space, None) # allow at least passing of the pointer # currently used until proper lazy instantiation available in interp_cppyy return FunctionExecutor(space, None)
def get_executor(space, name): # Matching of 'name' to an executor factory goes through up to four levels: # 1) full, qualified match # 2) drop '&': by-ref is pretty much the same as by-value, python-wise # 3) types/classes, either by ref/ptr or by value # 4) additional special cases # # If all fails, a default is used, which can be ignored at least until use. name = capi.c_resolve_name(space, name) # 1) full, qualified match try: return _executors[name](space, None) except KeyError: pass compound = helper.compound(name) clean_name = capi.c_resolve_name(space, helper.clean_type(name)) # 1a) clean lookup try: return _executors[clean_name+compound](space, None) except KeyError: pass # 2) drop '&': by-ref is pretty much the same as by-value, python-wise if compound and compound[len(compound)-1] == '&': # TODO: this does not actually work with Reflex (?) try: return _executors[clean_name](space, None) except KeyError: pass # 3) types/classes, either by ref/ptr or by value from pypy.module.cppyy import interp_cppyy cppclass = interp_cppyy.scope_byname(space, clean_name) if cppclass: # type check for the benefit of the annotator from pypy.module.cppyy.interp_cppyy import W_CPPClass cppclass = space.interp_w(W_CPPClass, cppclass, can_be_None=False) if compound == '': return InstanceExecutor(space, cppclass) elif compound == '*' or compound == '&': return InstancePtrExecutor(space, cppclass) elif compound == '**' or compound == '*&': return InstancePtrPtrExecutor(space, cppclass) elif capi.c_is_enum(space, clean_name): return _executors['unsigned int'](space, None) # 4) additional special cases if compound == '*': return _executors['void*'](space, None) # allow at least passing of the pointer # currently used until proper lazy instantiation available in interp_cppyy return FunctionExecutor(space, None)
def f(): lib = interp_cppyy.load_dictionary(space, "./example01Dict.so") cls = interp_cppyy.scope_byname(space, "example01") inst = cls.get_overload("example01").call(None, [FakeInt(0)]) cppmethod = cls.get_overload(method_name) assert isinstance(inst, interp_cppyy.W_CPPInstance) i = 10 while i > 0: drv.jit_merge_point(inst=inst, cppmethod=cppmethod, i=i) cppmethod.call(inst, [FakeInt(i)]) i -= 1 return 7
def __init__(self, space, extra): from pypy.module.cppyy import interp_cppyy cppclass = interp_cppyy.scope_byname(space, "TString") InstanceConverter.__init__(self, space, cppclass)
def ttree_getattr(space, w_self, args_w): """Specialized __getattr__ for TTree's that allows switching on/off the reading of individual branchs.""" from pypy.module.cppyy import interp_cppyy tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self) space = tree.space # holds the class cache in State # prevent recursion attr = space.str_w(args_w[0]) if attr and attr[0] == '_': raise OperationError(space.w_AttributeError, args_w[0]) # try the saved cdata (for builtin types) try: w_cdata = space.getattr(w_self, space.wrap('_'+attr)) from pypy.module._cffi_backend import cdataobj cdata = space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False) return cdata.convert_to_object() except OperationError: pass # setup branch as a data member and enable it for reading w_branch = space.call_method(w_self, "GetBranch", args_w[0]) if not space.is_true(w_branch): raise OperationError(space.w_AttributeError, args_w[0]) activate_branch(space, w_branch) # figure out from where we're reading entry = space.int_w(space.call_method(w_self, "GetReadEntry")) if entry == -1: entry = 0 # setup cache structure w_klassname = space.call_method(w_branch, "GetClassName") if space.is_true(w_klassname): # some instance klass = interp_cppyy.scope_byname(space, space.str_w(w_klassname)) w_obj = klass.construct() space.call_method(w_branch, "SetObject", w_obj) space.call_method(w_branch, "GetEntry", space.wrap(entry)) space.setattr(w_self, args_w[0], w_obj) return w_obj else: # builtin data w_leaf = space.call_method(w_self, "GetLeaf", args_w[0]) space.call_method(w_branch, "GetEntry", space.wrap(entry)) # location w_address = space.call_method(w_leaf, "GetValuePointer") buf = space.buffer_w(w_address) from pypy.module._rawffi import buffer assert isinstance(buf, buffer.RawFFIBuffer) address = rffi.cast(rffi.CCHARP, buf.datainstance.ll_buffer) # placeholder w_typename = space.call_method(w_leaf, "GetTypeName" ) from pypy.module.cppyy import capi typename = capi.c_resolve_name(space, space.str_w(w_typename)) if typename == 'bool': typename = '_Bool' w_address = space.call_method(w_leaf, "GetValuePointer") from pypy.module._cffi_backend import cdataobj, newtype cdata = cdataobj.W_CData(space, address, newtype.new_primitive_type(space, typename)) # cache result space.setattr(w_self, space.wrap('_'+attr), space.wrap(cdata)) return space.getattr(w_self, args_w[0])
def __init__(self, space, cppclass): from pypy.module.cppyy import interp_cppyy cppclass = interp_cppyy.scope_byname(space, capi.std_string_name) InstancePtrExecutor.__init__(self, space, cppclass)
def ttree_Branch(space, w_self, args_w): """Pythonized version of TTree::Branch(): takes proxy objects and by-passes the CINT-manual layer.""" from pypy.module.cppyy import interp_cppyy tree_class = interp_cppyy.scope_byname(space, "TTree") # sigs to modify (and by-pass CINT): # 1. (const char*, const char*, T**, Int_t=32000, Int_t=99) # 2. (const char*, T**, Int_t=32000, Int_t=99) argc = len(args_w) # basic error handling of wrong arguments is best left to the original call, # so that error messages etc. remain consistent in appearance: the following # block may raise TypeError or IndexError to break out anytime try: if argc < 2 or 5 < argc: raise TypeError("wrong number of arguments") tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self, can_be_None=True) if (tree is None) or (tree.cppclass != tree_class): raise TypeError("not a TTree") # first argument must always always be cont char* branchname = space.str_w(args_w[0]) # if args_w[1] is a classname, then case 1, else case 2 try: classname = space.str_w(args_w[1]) addr_idx = 2 w_address = args_w[addr_idx] except (OperationError, TypeError): addr_idx = 1 w_address = args_w[addr_idx] bufsize, splitlevel = 32000, 99 if addr_idx + 1 < argc: bufsize = space.c_int_w(args_w[addr_idx + 1]) if addr_idx + 2 < argc: splitlevel = space.c_int_w(args_w[addr_idx + 2]) # now retrieve the W_CPPInstance and build other stub arguments space = tree.space # holds the class cache in State cppinstance = space.interp_w(interp_cppyy.W_CPPInstance, w_address) address = rffi.cast(rffi.VOIDP, cppinstance.get_rawobject()) klassname = cppinstance.cppclass.full_name() vtree = rffi.cast(rffi.VOIDP, tree.get_rawobject()) # call the helper stub to by-pass CINT vbranch = _ttree_Branch(vtree, branchname, klassname, address, bufsize, splitlevel) branch_class = interp_cppyy.scope_byname(space, "TBranch") w_branch = interp_cppyy.wrap_cppobject(space, vbranch, branch_class) return w_branch except (OperationError, TypeError, IndexError): pass # return control back to the original, unpythonized overload ol = tree_class.get_overload("Branch") return ol.call(w_self, args_w)
def __init__(self, space, extra): from pypy.module.cppyy import interp_cppyy cppclass = interp_cppyy.scope_byname(space, capi.std_string_name) InstancePtrConverter.__init__(self, space, cppclass)
def ttree_getattr(space, w_self, args_w): """Specialized __getattr__ for TTree's that allows switching on/off the reading of individual branchs.""" from pypy.module.cppyy import interp_cppyy tree = space.interp_w(interp_cppyy.W_CPPInstance, w_self) space = tree.space # holds the class cache in State # prevent recursion attr = space.str_w(args_w[0]) if attr and attr[0] == '_': raise OperationError(space.w_AttributeError, args_w[0]) # try the saved cdata (for builtin types) try: w_cdata = space.getattr(w_self, space.wrap('_' + attr)) from pypy.module._cffi_backend import cdataobj cdata = space.interp_w(cdataobj.W_CData, w_cdata, can_be_None=False) return cdata.convert_to_object() except OperationError: pass # setup branch as a data member and enable it for reading w_branch = space.call_method(w_self, "GetBranch", args_w[0]) if not space.is_true(w_branch): raise OperationError(space.w_AttributeError, args_w[0]) activate_branch(space, w_branch) # figure out from where we're reading entry = space.r_longlong_w(space.call_method(w_self, "GetReadEntry")) if entry == -1: entry = 0 # setup cache structure w_klassname = space.call_method(w_branch, "GetClassName") if space.is_true(w_klassname): # some instance klass = interp_cppyy.scope_byname(space, space.str_w(w_klassname)) w_obj = klass.construct() # 0x10000 = kDeleteObject; reset because we own the object space.call_method(w_branch, "ResetBit", space.wrap(0x10000)) space.call_method(w_branch, "SetObject", w_obj) space.call_method(w_branch, "GetEntry", space.wrap(entry)) space.setattr(w_self, args_w[0], w_obj) return w_obj else: # builtin data w_leaf = space.call_method(w_self, "GetLeaf", args_w[0]) space.call_method(w_branch, "GetEntry", space.wrap(entry)) # location w_address = space.call_method(w_leaf, "GetValuePointer") buf = space.getarg_w('s*', w_address) from pypy.module._rawffi import buffer assert isinstance(buf, buffer.RawFFIBuffer) address = rffi.cast(rffi.CCHARP, buf.datainstance.ll_buffer) # placeholder w_typename = space.call_method(w_leaf, "GetTypeName") from pypy.module.cppyy import capi typename = capi.c_resolve_name(space, space.str_w(w_typename)) if typename == 'bool': typename = '_Bool' w_address = space.call_method(w_leaf, "GetValuePointer") from pypy.module._cffi_backend import cdataobj, newtype cdata = cdataobj.W_CData(space, address, newtype.new_primitive_type(space, typename)) # cache result space.setattr(w_self, space.wrap('_' + attr), space.wrap(cdata)) return space.getattr(w_self, args_w[0])