Commits

wlav committed f5894d2

o) rewrite of TF1 callbacks, now using _cffi_backend
o) release gil on calls into CINT, but lock CINT itself globally

Comments (0)

Files changed (7)

pypy/module/cppyy/__init__.py

         '_template_byname'       : 'interp_cppyy.template_byname',
         '_std_string_name'       : 'interp_cppyy.std_string_name',
         '_set_class_generator'   : 'interp_cppyy.set_class_generator',
+        '_set_function_generator': 'interp_cppyy.set_function_generator',
         '_register_class'        : 'interp_cppyy.register_class',
         '_is_static'             : 'interp_cppyy.is_static',
         'CPPInstance'            : 'interp_cppyy.W_CPPInstance',

pypy/module/cppyy/capi/cint_capi.py

 def identify():
     return 'CINT'
 
-ts_reflect = False
-ts_call    = False
+ts_reflect = True
+ts_call    = True
 ts_memory  = False
 ts_helper  = False
 
     _cintdll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
 with rffi.scoped_str2charp('libCore.so') as ll_libname:
     _coredll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
+with rffi.scoped_str2charp('libHist.so') as ll_libname:
+    _coredll = rdynload.dlopen(ll_libname, rdynload.RTLD_GLOBAL | rdynload.RTLD_NOW)
 
 eci = ExternalCompilationInfo(
     separate_module_files=[srcpath.join("cintcwrapper.cxx")],
     include_dirs=[incpath] + rootincpath,
     includes=["cintcwrapper.h"],
     library_dirs=rootlibpath,
-    libraries=["Core", "Cint"],
+    libraries=["Hist", "Core", "Cint"],
     use_cpp_linker=True,
 )
 
 ### TF1 ----------------------------------------------------------------------
 class State(object):
     def __init__(self, space):
-        self.tfn_pyfuncs = {}
+        self.tfn_pyfuncs = []
+        self.tfn_callbacks = []
 
-_tfn_install = rffi.llexternal(
-    "cppyy_tfn_install",
-    [rffi.CCHARP, rffi.INT], rffi.LONG,
+_create_tf1 = rffi.llexternal(
+    "cppyy_create_tf1",
+    [rffi.CCHARP, rffi.ULONG, rffi.DOUBLE, rffi.DOUBLE, rffi.INT], C_OBJECT,
     releasegil=False,
     compilation_info=eci)
 
         if argc == 6: npar = space.int_w(args_w[5])
 
         # third argument must be a callable python object
-        pyfunc = args_w[2]
-        if not space.is_true(space.callable(pyfunc)):
+        w_callable = args_w[2]
+        if not space.is_true(space.callable(w_callable)):
             raise TypeError("2nd argument is not a valid python callable")
 
-        fid = _tfn_install(funcname, npar)
-        state = space.fromcache(State)
-        state.tfn_pyfuncs[fid] = pyfunc
-        newargs_w = [args_w[1], space.wrap(fid), args_w[3], args_w[4], space.wrap(npar)]
-    except (OperationError, TypeError, IndexError):
+        # 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[1]), funcaddr,
+                      space.float_w(args_w[3]), space.float_w(args_w[4]), npar)
+ 
+        from pypy.module.cppyy import interp_cppyy
+        w_instance = interp_cppyy.wrap_cppobject(space, newinst, tf1_class,
+                                      do_cast=False, python_owns=True, fresh=True)
+
+        # tie all the life times to the TF1 instance
+        space.setattr(w_instance, space.wrap('_callback'), w_callback)
+
+        return w_instance
+    except (OperationError, TypeError, IndexError), e:
         newargs_w = args_w[1:]     # drop class
 
     # return control back to the original, unpythonized overload
     if obj is not None:
         memory_regulator.unregister(obj)
         obj._rawobject = C_NULL_OBJECT
-
-# TFn callback (as above: needs better solution, but this is for CINT only)
-# TODO: it actually can fail ...
-@cpython_api([rffi.LONG, rffi.INT, rffi.DOUBLEP, rffi.DOUBLEP], rffi.DOUBLE, error=CANNOT_FAIL)
-def cppyy_tfn_callback(space, idx, npar, a0, a1):
-    state = space.fromcache(State)
-    pyfunc = state.tfn_pyfuncs[idx]
-    npar = int(npar)
-
-    from pypy.module._rawffi.interp_rawffi import unpack_simple_shape
-    from pypy.module._rawffi.array import W_Array
-    arr = space.interp_w(W_Array, unpack_simple_shape(space, space.wrap('d')))
-    address = rffi.cast(rffi.ULONG, a0)
-    arg0 = arr.fromaddress(space, address, 4)
-    try:
-        if npar != 0:
-            address = rffi.cast(rffi.ULONG, a1)
-            arg1 = arr.fromaddress(space, address, npar)
-            result = space.call_function(pyfunc, arg0, arg1)
-        else:
-            result = space.call_function(pyfunc, arg0)
-        dresult = space.float_w(result)
-    except Exception:
-        dresult = -1.;            # TODO: error handling here ..
-    return dresult

pypy/module/cppyy/include/cintcwrapper.h

     void* cppyy_load_dictionary(const char* lib_name);
 
     /* pythonization helpers */
-   long cppyy_tfn_install(const char* funcname, int npar);
+    cppyy_object_t cppyy_create_tf1(const char* funcname, unsigned long address,
+        double xmin, double xmax, int npar);
 
     cppyy_object_t cppyy_ttree_Branch(
         void* vtree, const char* branchname, const char* classname,

pypy/module/cppyy/interp_cppyy.py

     state = space.fromcache(State)
     state.w_clgen_callback = w_callback
 
+@unwrap_spec(w_callback=W_Root)
+def set_function_generator(space, w_callback):
+    state = space.fromcache(State)
+    state.w_fngen_callback = w_callback
+
 def register_class(space, w_pycppclass):
     w_cppclass = space.findattr(w_pycppclass, space.wrap("_cpp_proxy"))
     cppclass = space.interp_w(W_CPPClass, w_cppclass, can_be_None=False)
         w_pycppclass = space.call_function(state.w_clgen_callback, space.wrap(final_name))
     return w_pycppclass
 
+def get_interface_func(space, w_callable, npar):
+    state = space.fromcache(State)
+    return space.call_function(state.w_fngen_callback, w_callable, space.wrap(npar))
+
 def wrap_cppobject(space, rawobject, cppclass,
                    do_cast=True, python_owns=False, is_ref=False, fresh=False):
     rawobject = rffi.cast(capi.C_OBJECT, rawobject)

pypy/module/cppyy/pythonify.py

 def clgen_callback(name):
     return get_pycppclass(name)
 
+def fngen_callback(func, npar): # todo, some kind of arg transform spec
+    if npar == 0:
+        def wrapper(a0, a1):
+            la0 = [a0[0], a0[1], a0[2], a0[3]]
+            return func(la0)
+        return wrapper
+    else:
+        def wrapper(a0, a1):
+            la0 = [a0[0], a0[1], a0[2], a0[3]]
+            la1 = [a1[i] for i in range(npar)]
+            return func(la0, la1)
+        return wrapper
+
 
 def make_static_function(func_name, cppol):
     def function(*args):
     # class generator callback
     cppyy._set_class_generator(clgen_callback)
 
+    # function generator callback
+    cppyy._set_function_generator(fngen_callback)
+
     # user interface objects (note the two-step of not calling scope_byname here:
     # creation of global functions may cause the creation of classes in the global
     # namespace, so gbl must exist at that point to cache them)

pypy/module/cppyy/src/cintcwrapper.cxx

 // for pythonization
 #include "TTree.h"
 #include "TBranch.h"
+#include "TF1.h"
 #include "TString.h"
 
 #include "Api.h"
     TList*             fAllPubMethod;   //all public methods (including from base classes)
 };
 
-// memory regulation (cppyy_recursive_remove is generated a la cpyext capi calls)
+// memory regulation (cppyy_recursive_remove is generated as a cpyext capi call)
 extern "C" void cppyy_recursive_remove(void*);
 
-// TFN callback helper (generated a la cpyext capi calls)
-extern "C" double cppyy_tfn_callback(long, int, double*, double*);
-
 class Cppyy_MemoryRegulator : public TObject {
 public:
     virtual void RecursiveRemove(TObject* object) {
 
 /* name to opaque C++ scope representation -------------------------------- */
 int cppyy_num_scopes(cppyy_scope_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         /* not supported as CINT does not store classes hierarchically */
 }
 
 char* cppyy_scope_name(cppyy_scope_t handle, int iscope) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         /* not supported as CINT does not store classes hierarchically */
 }
 
 char* cppyy_resolve_name(const char* cppitem_name) {
+    R__LOCKGUARD2(gCINTMutex);
     std::string tname = cppitem_name;
 
     // global namespace?
 }
 
 cppyy_scope_t cppyy_get_scope(const char* scope_name) {
+    R__LOCKGUARD2(gCINTMutex);
+
     // CINT still has trouble with std:: sometimes ... 
     if (strncmp(scope_name, "std::", 5) == 0)
         scope_name = &scope_name[5];
 }
 
 cppyy_type_t cppyy_get_template(const char* template_name) {
+    R__LOCKGUARD2(gCINTMutex);
+
     ClassRefIndices_t::iterator icr = g_classref_indices.find(template_name);
     if (icr != g_classref_indices.end())
         return (cppyy_type_t)icr->second;
 }
 
 cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(klass);
     TClass* clActual = cr->GetActualClass( (void*)obj );
     if (clActual && clActual != cr.GetClass()) {
 
 /* memory management ------------------------------------------------------ */
 cppyy_object_t cppyy_allocate(cppyy_type_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     return (cppyy_object_t)malloc(cr->Size());
 }
 }
 
 void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     cr->Destructor((void*)self, true);
 }
 static inline G__value cppyy_call_T(cppyy_method_t method,
         cppyy_object_t self, int nargs, void* args) {
 
+    R__LOCKGUARD2(gCINTMutex);
+
     G__param* libp = (G__param*)((char*)args - offsetof(G__param, para));
     assert(libp->paran == nargs);
     fixup_args(libp);
 }
 
 char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) {
+    R__LOCKGUARD2(gCINTMutex);
     G__value result = cppyy_call_T(method, self, nargs, args);
     G__pop_tempobject_nodel();
     if (result.ref && *(long*)result.ref) {
 }
 
 cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t handle, int nargs, void* args) {
+    R__LOCKGUARD2(gCINTMutex);
     cppyy_object_t self = (cppyy_object_t)NULL;
     if ((InterpretedFuncs_t::size_type)method >= g_interpreted.size()) {
         G__setgvp((long)G__PVOID);
 
 cppyy_object_t cppyy_call_o(cppyy_type_t method, cppyy_object_t self, int nargs, void* args,
                   cppyy_type_t /*result_type*/ ) {
+    R__LOCKGUARD2(gCINTMutex);
     G__value result = cppyy_call_T(method, self, nargs, args);
     G__pop_tempobject_nodel();
     return G__int(result);
 
 /* scope reflection information ------------------------------------------- */
 int cppyy_is_namespace(cppyy_scope_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cr->GetClassInfo())
         return cr->Property() & G__BIT_ISNAMESPACE;
 }
 
 int cppyy_is_enum(const char* type_name) {
+    R__LOCKGUARD2(gCINTMutex);
     G__TypeInfo ti(type_name);
     return (ti.Property() & G__BIT_ISENUM);
 }
 
 /* type/class reflection information -------------------------------------- */
 char* cppyy_final_name(cppyy_type_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cr->GetClassInfo()) {
         std::string true_name = G__TypeInfo(cr->GetName()).TrueName();
 }
 
 char* cppyy_scoped_final_name(cppyy_type_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cr->GetClassInfo()) {
         std::string true_name = G__TypeInfo(cr->GetName()).TrueName();
 }
 
 int cppyy_num_bases(cppyy_type_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cr->GetListOfBases() != 0)
         return cr->GetListOfBases()->GetSize();
 }
 
 char* cppyy_base_name(cppyy_type_t handle, int base_index) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     TBaseClass* b = (TBaseClass*)cr->GetListOfBases()->At(base_index);
     return type_cppstring_to_cstring(b->GetName());
 }
 
 int cppyy_is_subtype(cppyy_type_t derived_handle, cppyy_type_t base_handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& derived_type = type_from_handle(derived_handle);
     TClassRef& base_type = type_from_handle(base_handle);
     return derived_type->GetBaseClass(base_type) != 0;
 
 size_t cppyy_base_offset(cppyy_type_t derived_handle, cppyy_type_t base_handle,
                        cppyy_object_t address, int /* direction */) {
+    R__LOCKGUARD2(gCINTMutex);
+
     // WARNING: CINT can not handle actual dynamic casts!
     TClassRef& derived_type = type_from_handle(derived_handle);
     TClassRef& base_type = type_from_handle(base_handle);
 
 /* method/function reflection information --------------------------------- */
 int cppyy_num_methods(cppyy_scope_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cr->GetListOfMethods())
         return cr->GetListOfMethods()->GetSize();
 }
 
 cppyy_index_t cppyy_method_index_at(cppyy_scope_t handle, int imeth) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass())
         return (cppyy_index_t)imeth;
 }
 
 cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t handle, const char* name) {
+    R__LOCKGUARD2(gCINTMutex);
+
     std::vector<cppyy_index_t> result;
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
 
 
 char* cppyy_method_name(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TFunction* f = type_get_method(handle, idx);
     std::string name = f->GetName();
     TClassRef& cr = type_from_handle(handle);
 }
 
 char* cppyy_method_result_type(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cppyy_is_constructor(handle, idx))
         return cppstring_to_cstring("constructor");
 }
 
 int cppyy_method_num_args(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TFunction* f = type_get_method(handle, idx);
     return f->GetNargs();
 }
 
 int cppyy_method_req_args(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TFunction* f = type_get_method(handle, idx);
     return f->GetNargs() - f->GetNargsOpt();
 }
 
 char* cppyy_method_arg_type(cppyy_scope_t handle, cppyy_index_t idx, int arg_index) {
+    R__LOCKGUARD2(gCINTMutex);
     TFunction* f = type_get_method(handle, idx);
     TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At(arg_index);
     return type_cppstring_to_cstring(arg->GetFullTypeName());
 }
 
 char* cppyy_method_signature(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     TFunction* f = type_get_method(handle, idx);
     std::ostringstream sig;
 
 
 int cppyy_method_is_template(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     TFunction* f = type_get_method(handle, idx);
     std::string name = f->GetName();
 
 char* cppyy_method_template_arg_name(
         cppyy_scope_t handle, cppyy_index_t idx, cppyy_index_t /*iarg*/) {
+    R__LOCKGUARD2(gCINTMutex);
 // TODO: return only the name for the requested arg
     TClassRef& cr = type_from_handle(handle);
     TFunction* f = type_get_method(handle, idx);
 
 
 cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
+
     TClassRef& cr = type_from_handle(handle);
     TFunction* f = type_get_method(handle, idx);
     if (cr && cr.GetClass() && !cr->IsLoaded()) {
 }
 
 cppyy_index_t cppyy_get_global_operator(cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op) {
+    R__LOCKGUARD2(gCINTMutex);
+
     TClassRef& lccr = type_from_handle(lc);
     TClassRef& rccr = type_from_handle(rc);
 
 
 /* method properties -----------------------------------------------------  */
 int cppyy_is_constructor(cppyy_type_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     TMethod* m = (TMethod*)cr->GetListOfMethods()->At(idx);
     return strcmp(m->GetName(), ((G__ClassInfo*)cr->GetClassInfo())->Name()) == 0;
 }
 
 int cppyy_is_staticmethod(cppyy_type_t handle, cppyy_index_t idx) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     TMethod* m = (TMethod*)cr->GetListOfMethods()->At(idx);
     return m->Property() & G__BIT_ISSTATIC;
 
 /* data member reflection information ------------------------------------- */
 int cppyy_num_datamembers(cppyy_scope_t handle) {
+    R__LOCKGUARD2(gCINTMutex);
+
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass() && cr->GetListOfDataMembers())
         return cr->GetListOfDataMembers()->GetSize();
 }
 
 char* cppyy_datamember_name(cppyy_scope_t handle, int datamember_index) {
+    R__LOCKGUARD2(gCINTMutex);
+
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
 }
 
 char* cppyy_datamember_type(cppyy_scope_t handle, int datamember_index) {
+    R__LOCKGUARD2(gCINTMutex);
+
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass())  {
         TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
 }
 
 size_t cppyy_datamember_offset(cppyy_scope_t handle, int datamember_index) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
 }
 
 int cppyy_datamember_index(cppyy_scope_t handle, const char* name) {
+    R__LOCKGUARD2(gCINTMutex);
+
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         // called from updates; add a hard reset as the code itself caches in
 
 /* data member properties ------------------------------------------------  */
 int cppyy_is_publicdata(cppyy_scope_t handle, int datamember_index) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
 }
 
 int cppyy_is_staticdata(cppyy_scope_t handle, int datamember_index) {
+    R__LOCKGUARD2(gCINTMutex);
     TClassRef& cr = type_from_handle(handle);
     if (cr.GetClass()) {
         TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At(datamember_index);
 
 
 void* cppyy_load_dictionary(const char* lib_name) {
+    R__LOCKGUARD2(gCINTMutex);
     if (0 <= gSystem->Load(lib_name))
         return (void*)1;
     return (void*)0;
 
 
 /* pythonization helpers -------------------------------------------------- */
-static std::map<long, std::pair<long, int> > s_tagnum2fid;
+typedef double (*tfn_callback)(double*, double*);
 
-static int TFNPyCallback(G__value* res, G__CONST char*, struct G__param* libp, int hash) {
-    // This is a generic CINT-installable TFN (with N=1,2,3) callback (used to factor
-    // out some common code), to allow TFN to call back into python.
-
-    std::map<long, std::pair<long, int> >::iterator it = s_tagnum2fid.find(G__value_get_tagnum(res));
-    if (it == s_tagnum2fid.end()) {
-        // TODO: report error here
-        return 0;
-    }
-
-    const std::pair<long, int>& fid_and_npar = it->second;
-
-    // callback (defined in cint_capi.py)
-    double* a0 = (double*)G__int(libp->para[0]);
-    double* a1 = (double*)(fid_and_npar.second ? G__int(libp->para[1]) : 0);
-    double d = cppyy_tfn_callback(fid_and_npar.first, fid_and_npar.second, a0, a1);
-
-    // translate result (TODO: error checking)
-    G__letdouble(res, 100, d);
-    return (1 || hash || res || libp);
-}
-
-long cppyy_tfn_install(const char* funcname, int npar) {
-    // make a new function placeholder known to CINT
-    static Long_t s_fid = (Long_t)cppyy_tfn_install;   // ensures no user function lives there
-    ++s_fid;
-
-    const char* signature = "D - - 0 - - D - - 0 - -";
-
-    // create a return type (typically masked/wrapped by a TPyReturn) for the method
-    G__linked_taginfo pti;
-    pti.tagnum = -1;
-    pti.tagtype = 'c';
-    std::string tagname("::py_");                 // used as a buffer
-    tagname += funcname;
-    pti.tagname = tagname.c_str();
-    int tagnum = G__get_linked_tagnum(&pti);      // creates entry for new names
-
-    // for free functions, add to global scope and add lookup through tp2f 
-    // setup a connection between the pointer and the name
-    Long_t hash = 0, len = 0;
-    G__hash(funcname, hash, len);
-    G__lastifuncposition();
-    G__memfunc_setup(funcname, hash, (G__InterfaceMethod)&TFNPyCallback,
-                     tagnum, tagnum, tagnum, 0, 2, 0, 1, 0, signature,
-                     (char*)0, (void*)s_fid, 0);
-    G__resetifuncposition();
-
-    // setup a name in the global namespace (does not result in calls, so the signature
-    // does not matter; but it makes subsequent GetMethod() calls work)
-    G__MethodInfo meth = G__ClassInfo().AddMethod(
-        funcname, funcname, signature, 1, 0, (void*)&TFNPyCallback);
-
-    // store mapping so that the callback can find it
-    s_tagnum2fid[tagnum] = std::make_pair(s_fid, npar);
-
-    // hard to check result ... assume ok
-    return s_fid;
+cppyy_object_t cppyy_create_tf1(const char* funcname, unsigned long address,
+        double xmin, double xmax, int npar) {
+    return (cppyy_object_t)new TF1(funcname, (tfn_callback)address, xmin, xmax, npar);
 }
 
 cppyy_object_t cppyy_ttree_Branch(void* vtree, const char* branchname, const char* classname,

pypy/module/cppyy/test/test_cint.py

 
         assert f.Eval(0.5) == 0.5
 
+        del f      # force here, to prevent leak-check complaints
+
     def test02_callable_object_callback(self):
         """Test callback of a python callable object"""
 
         assert f.Eval(-0.1) == 4.8
         assert f.Eval(1.3)  == 7.6
 
+        del f      # force here, to prevent leak-check complaints
+
     def test03_fit_with_python_gaussian(self):
         """Test fitting with a python global function"""
 
         assert round(result[1] - 0., 1) == 0  # mean
         assert round(result[2] - 1., 1) == 0  # s.d.
 
+        del f      # force here, to prevent leak-check complaints
+
 
 class AppTestSURPLUS:
     spaceconfig = dict(usemodules=['cppyy', '_rawffi', '_ffi', 'itertools'])
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.