Jpp 19.3.0-rc.3
the software that should make you happy
Loading...
Searching...
No Matches
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"
8#include "JROOT/JRoot.hh"
9#include "Jeep/JPrint.hh"
11#include "TDataMember.h"
12#include "TTree.h"
13
14namespace JROOT {
15
16/* to_vector converts a list of Root TObjects into a list
17 * of those objects names
18 */
19inline 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
32
33/**
34 * Class responsible to setup TTree branch addresses
35 * for reading objects of type T.
36 *
37 */
38template <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 !JRoot::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.
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.