Jpp  19.1.0
the software that should make you happy
JTreeBranchAddresses.hh
Go to the documentation of this file.
1 #ifndef __JTREE_BRANCH_ADDRESSES_H__
2 #define __JTREE_BRANCH_ADDRESSES_H__
3 
4 #include <iostream>
5 
6 #include "JLang/JException.hh"
7 #include "JROOT/JRootAddress.hh"
8 #include "JROOT/JRootClass.hh"
9 #include "Jeep/JPrint.hh"
10 #include "Jeep/JStreamToolkit.hh"
11 #include "TDataMember.h"
12 #include "TTree.h"
13 
14 namespace JROOT {
15 
16 /* to_vector converts a list of Root TObjects into a list
17  * of those objects names
18  */
19 inline std::vector<std::string> to_vector(TCollection* col)
20 {
22 
23  TIter next(col);
24  TObject* object{nullptr};
25  while ((object = next()) != nullptr) {
26  names.emplace_back(object->GetName());
27  }
28  return names;
29 }
30 
31 using JLANG::JException;
32 
33 /**
34  * Class responsible to setup TTree branch addresses
35  * for reading objects of type T.
36  *
37  */
38 template <typename T>
40 
41  public:
42  /*
43  * Set the branch(es) address(es) to read objects of type T.
44  *
45  * If the tree contains a single branch we assume that branch contains
46  * objects of type T.
47  *
48  * If the tree contains several branches we check whether those branches
49  * correspond to the full list of T data members. If that's the case
50  * the tree is a flat (one branch per data member) representation of T
51  * and setup the branches accordingly. If not, we throw an exception.
52  */
53  void setBranchAddress(TTree& tree)
54  {
55  TObjArray* branches = tree.GetListOfBranches();
56  // single branch
57  if (branches->GetEntries() == 1) {
58  tree.SetBranchAddress(branches->First()->GetName(), &this->address);
59  return;
60  }
61 
62  // if more than one branch, check those are the data members of T
63  TClass* t_class = TClass::GetClass<T>();
64  if (t_class == nullptr) {
65  THROW(JException, "Could not get class " << typeid(T).name());
66  }
67 
68  auto branch_names = to_vector(tree.GetListOfBranches());
69  auto all_member_names = to_vector(t_class->GetListOfRealData());
70 
71  std::vector<std::string> member_names;
72 
73  // remove TObject specific members
74  std::copy_if(all_member_names.begin(), all_member_names.end(), std::back_inserter(member_names),
75  [](const std::string& member_name)
76  { return !JRootClass::is_tobject_member(member_name.c_str()); });
77 
78  std::sort(branch_names.begin(), branch_names.end());
79  std::sort(member_names.begin(), member_names.end());
80 
81  // all members must have a corresponding branch
82  // (but more branches are allowed, we just don't handle them here)
83  if (std::includes(branch_names.begin(), branch_names.end(), member_names.begin(),
84  member_names.end())) {
85 
86  this->address = new T;
87 
88  auto* base = reinterpret_cast<uint8_t*>(this->address);
89 
90  for (const auto& member_name : member_names) {
91  auto* member = static_cast<TDataMember*>(t_class->GetDataMember(member_name.c_str()));
92  tree.SetBranchAddress(member_name.c_str(),
93  reinterpret_cast<void*>(base + member->GetOffset()));
94  }
95  return;
96  }
97 
98  // if we cannot configure the tree, try to give some relevant information
99  // to the user who will have to deal with the exception...
100  THROW(JException, "Members of type " << typeid(T).name() << "\n"
101  << JEEP::JEEPZ() << member_names << "\nBranches in tree\n"
102  << JEEP::JEEPZ() << branch_names);
103  }
104 };
105 } // namespace JROOT
106 
107 #endif
Exceptions.
#define THROW(JException_t, A)
Marco for throwing exception with std::ostream compatible message.
Definition: JException.hh:712
I/O formatting auxiliaries.
General exception.
Definition: JException.hh:24
Class responsible to setup TTree branch addresses for reading objects of type T.
Auxiliary classes and methods for ROOT I/O.
std::vector< std::string > to_vector(TCollection *col)
Auxiliary data structure for streaming of STL containers.
Auxiliary classd for address handling within TTree or TChain.
Definition: JRootAddress.hh:19
Definition: JRoot.hh:19