Commits

wlav  committed 3f8bc92

for CINT backend: TTree reading of builtin types

  • Participants
  • Parent commits a06891d
  • Branches reflex-support

Comments (0)

Files changed (4)

File pypy/module/cppyy/capi/cint_capi.py

 
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.rpython.lltypesystem import rffi
+
 from pypy.rlib import libffi, rdynload
 
-from pypy.module.itertools import interp_itertools
-
 
 __all__ = ['identify', 'eci', 'c_load_dictionary']
 
     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
-    space = tree.space            # holds the class cache in State
     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)
     w_klassname = space.call_method(w_branch, "GetClassName")
-    klass = interp_cppyy.scope_byname(space, space.str_w(w_klassname))
-    w_obj = klass.construct()
-    #space.call_method(w_branch, "SetStatus", space.wrap(1)) 
-    activate_branch(space, w_branch)
-    space.call_method(w_branch, "SetObject", w_obj)
-    space.call_method(w_branch, "GetEntry", space.wrap(0))
-    space.setattr(w_self, args_w[0], w_obj)
-    return w_obj
+    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(0))
+        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])
+        w_typename = space.call_method(w_leaf, "GetTypeName" )
+        from pypy.module.cppyy import capi
+        typename = capi.c_resolve_name(space.str_w(w_typename))
+        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)
+        from pypy.module._cffi_backend import cdataobj, newtype
+        cdata = cdataobj.W_CData(space, address, newtype.new_primitive_type(space, typename))
+        space.setattr(w_self, space.wrap('_'+attr), space.wrap(cdata))
+        return space.getattr(w_self, args_w[0])
 
 class W_TTreeIter(Wrappable):
     def __init__(self, space, w_tree):

File pypy/module/cppyy/interp_cppyy.py

         try:
             return self.space.call_method(self.space.wrap(self), "_cppyy_as_builtin")
         except OperationError, e:
-            if not e.match(self.space, self.space.w_AttributeError):
+            if not (e.match(self.space, self.space.w_TypeError) or
+                    e.match(self.space, self.space.w_AttributeError)):
+                # TODO: TypeError is raised by call_method if the method is not found;
+                # it'd be a lot nicer if only AttributeError were raise
                 raise
         return None
 
             if not e.match(self.space, self.space.w_TypeError):
                 raise
 
-        # fallback 1: convert the object to a builin equivalent
+        # fallback 1: convert the object to a builtin equivalent
         w_as_builtin = self._get_as_builtin()
         if w_as_builtin is not None:
             return self.space.eq(w_as_builtin, w_other)

File pypy/module/cppyy/src/cintcwrapper.cxx

 }
 
 cppyy_scope_t cppyy_get_scope(const char* scope_name) {
+    // CINT still has trouble with std:: sometimes ... 
+    if (strncmp(scope_name, "std::", 5) == 0)
+        scope_name = &scope_name[5];
+
     ClassRefIndices_t::iterator icr = g_classref_indices.find(scope_name);
     if (icr != g_classref_indices.end())
         return (cppyy_type_t)icr->second;
     if (strcmp(scope_name, "#define") == 0)
         return (cppyy_type_t)NULL;
 
-     // use TClass directly, to enable auto-loading
+    // use TClass directly, to enable auto-loading
     TClassRef cr(TClass::GetClass(scope_name, kTRUE, kTRUE));
     if (!cr.GetClass())
         return (cppyy_type_t)NULL;

File pypy/module/cppyy/test/test_cint.py

 
 
 class AppTestCINTTTree:
-    spaceconfig = dict(usemodules=['cppyy'])
+    spaceconfig = dict(usemodules=['cppyy', 'array', '_rawffi', '_cffi_backend'])
 
     def setup_class(cls):
         cls.w_N = cls.space.wrap(5)
         cls.w_tname = cls.space.wrap("test")
         cls.w_title = cls.space.wrap("test tree")
         cls.w_iotypes = cls.space.appexec([], """():
-            import cppyy
+            import cppyy, _cffi_backend
+            _cffi_backend.new_primitive_type      # prevents leak-checking complaints on _cffi_backend
             return cppyy.load_reflection_info(%r)""" % (iotypes_dct,))
 
     def test01_write_stdvector(self):
         f.Write()
         f.Close()
 
-    def test02_read_stdvector(self):
+    def test02_file_open(self):
+
+        from cppyy import gbl
+
+        f = gbl.TFile.Open(self.fname)
+        s = str(f)            # should not raise
+        r = repr(f)
+
+        f.Close()
+
+    def test03_read_stdvector(self):
         """Test reading of a single branched TTree with an std::vector<double>"""
 
         from cppyy import gbl
 
         f.Close()
 
-    def test03_write_some_data_object(self):
+    def test04_write_some_data_object(self):
         """Test writing of a complex data object"""
 
         from cppyy import gbl
         f.Write()
         f.Close()
 
-    def test04_read_some_data_object(self):
+    def test05_read_some_data_object(self):
         """Test reading of a complex data object"""
 
         from cppyy import gbl
         #
         f.Close()
 
-    def test05_branch_activation(self):
+    def test06_branch_activation(self):
         """Test of automatic branch activation"""
 
         from cppyy import gbl
             i += 1
         assert i == self.N
 
+    def test07_write_builtin(self):
+        """Test writing of a builtins"""
+
+        from cppyy import gbl               # bootstraps, only needed for tests
+        from cppyy.gbl import TFile, TTree
+        from cppyy.gbl.std import vector
+
+        f = TFile(self.fname, "RECREATE")
+        mytree = TTree(self.tname, self.title)
+        mytree._python_owns = False
+
+        import array
+        a = array.array('i', [0])
+        b = array.array('d', [0.])
+
+        mytree.Branch("myi", a, "myi/I")
+        mytree.Branch("myd", b, "myd/D")
+
+        for i in range(self.N):
+            a[0] = i
+            b[0] = i/2.
+            mytree.Fill()
+        f.Write()
+        f.Close()
+
+    def test08_read_builtin(self):
+        """Test reading of a single branched TTree with an std::vector<double>"""
+
+        from cppyy import gbl
+        from cppyy.gbl import TFile
+
+        f = TFile(self.fname)
+        mytree = f.Get(self.tname)
+
+        i = 0
+        for event in mytree:
+            assert event.myi == i
+            assert event.myd == i/2.
+            i += 1
+        assert i == self.N
+
+        f.Close()
+
 
 class AppTestRegression:
     spaceconfig = dict(usemodules=['cppyy'])