ROOT  6.07/01
Reference Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
TTreeReaderValue.cxx
Go to the documentation of this file.
1 // @(#)root/treeplayer:$Id$
2 // Author: Axel Naumann, 2011-09-28
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers and al. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "TTreeReaderValue.h"
13 
14 #include "TTreeReader.h"
15 #include "TBranchClones.h"
16 #include "TBranchElement.h"
17 #include "TBranchRef.h"
18 #include "TBranchSTL.h"
19 #include "TBranchProxyDirector.h"
20 #include "TLeaf.h"
21 #include "TTreeProxyGenerator.h"
22 #include "TTreeReaderValue.h"
23 #include "TRegexp.h"
24 #include "TStreamerInfo.h"
25 #include "TStreamerElement.h"
26 #include "TNtuple.h"
27 #include <vector>
28 
29 /** \class TTreeReaderValue
30 
31 Extracts data from a TTree.
32 */
33 
35 
36 ////////////////////////////////////////////////////////////////////////////////
37 /// Construct a tree value reader and register it with the reader object.
38 
39 ROOT::Internal::TTreeReaderValueBase::TTreeReaderValueBase(TTreeReader* reader /*= 0*/,
40  const char* branchname /*= 0*/,
41  TDictionary* dict /*= 0*/):
42  fBranchName(branchname),
43  fTreeReader(reader),
44  fDict(dict),
45  fProxy(NULL),
46  fLeaf(NULL),
47  fTreeLastOffset(-1),
48  fSetupStatus(kSetupNotSetup),
49  fReadStatus(kReadNothingYet)
50 {
51  if (fTreeReader) fTreeReader->RegisterValueReader(this);
52 }
53 
54 ////////////////////////////////////////////////////////////////////////////////
55 /// Unregister from tree reader, cleanup.
56 
58 {
60 }
61 
62 ////////////////////////////////////////////////////////////////////////////////
63 /// Try to read the value from the TBranchProxy, returns
64 /// the status of the read.
65 
68  if (!fProxy) return kReadNothingYet;
69  if (fProxy->Read()) {
70  fReadStatus = kReadSuccess;
71  } else {
72  fReadStatus = kReadError;
73  }
74  return fReadStatus;
75 }
76 
77 ////////////////////////////////////////////////////////////////////////////////
78 /// If we are reading a leaf, return the corresponding TLeaf.
79 
81  if (fLeafName.Length() > 0){
82 
83  Long64_t newChainOffset = fTreeReader->GetTree()->GetChainOffset();
84 
85  if (newChainOffset != fTreeLastOffset){
86  fTreeLastOffset = newChainOffset;
87 
88  TTree *myTree = fTreeReader->GetTree();
89 
90  if (!myTree) {
91  fReadStatus = kReadError;
92  Error("TTreeReaderValueBase::GetLeaf()", "Unable to get the tree from the TTreeReader");
93  return 0;
94  }
95 
96  TBranch *myBranch = myTree->GetBranch(fBranchName);
97 
98  if (!myBranch) {
99  fReadStatus = kReadError;
100  Error("TTreeReaderValueBase::GetLeaf()", "Unable to get the branch from the tree");
101  return 0;
102  }
103 
104  fLeaf = myBranch->GetLeaf(fLeafName);
105  if (!fLeaf) {
106  Error("TTreeReaderValueBase::GetLeaf()", "Failed to get the leaf from the branch");
107  }
108  }
109  return fLeaf;
110  }
111  else {
112  Error("TTreeReaderValueBase::GetLeaf()", "We are not reading a leaf");
113  return 0;
114  }
115 }
116 
117 ////////////////////////////////////////////////////////////////////////////////
118 /// Returns the memory address of the object being read.
119 
121  if (ProxyRead() != kReadSuccess) return 0;
122 
123  if (fLeafName.Length() > 0){
124  if (GetLeaf()){
125  return fLeaf->GetValuePointer();
126  }
127  else {
128  fReadStatus = kReadError;
129  Error("TTreeReaderValueBase::GetAddress()", "Unable to get the leaf");
130  return 0;
131  }
132  }
133  if (!fStaticClassOffsets.empty()){ // Follow all the pointers
134  Byte_t *address = (Byte_t*)fProxy->GetWhere();
135 
136  for (unsigned int i = 0; i < fStaticClassOffsets.size() - 1; ++i){
137  address = *(Byte_t**)(address + fStaticClassOffsets[i]);
138  }
139 
140  return address + fStaticClassOffsets.back();
141  }
142  return fProxy ? (Byte_t*)fProxy->GetWhere() : 0;
143 }
144 
145 ////////////////////////////////////////////////////////////////////////////////
146 /// Create the proxy object for our branch.
147 
149  if (fProxy) {
150  return;
151  }
152  if (!fTreeReader) {
153  Error("TTreeReaderValueBase::CreateProxy()", "TTreeReader object not set / available for branch %s!",
154  fBranchName.Data());
155  return;
156  }
157  if (!fDict) {
158  TBranch* br = fTreeReader->GetTree()->GetBranch(fBranchName);
159  const char* brDataType = "{UNDETERMINED}";
160  if (br) {
161  TDictionary* brDictUnused = 0;
162  brDataType = GetBranchDataType(br, brDictUnused);
163  }
164  Error("TTreeReaderValueBase::CreateProxy()", "The template argument type T of %s accessing branch %s (which contains data of type %s) is not known to ROOT. You will need to create a dictionary for it.",
165  GetDerivedTypeName(), fBranchName.Data(), brDataType);
166  return;
167  }
168 
169  // Search for the branchname, determine what it contains, and wire the
170  // TBranchProxy representing it to us so we can access its data.
171 
172  TNamedBranchProxy* namedProxy
173  = (TNamedBranchProxy*)fTreeReader->FindObject(fBranchName);
174  if (namedProxy && namedProxy->GetDict() == fDict) {
175  fProxy = namedProxy->GetProxy();
176  return;
177  }
178 
179  TBranch* branch = fTreeReader->GetTree()->GetBranch(fBranchName);
180  TLeaf *myLeaf = NULL;
181  TDictionary* branchActualType = 0;
182 
183  if (!branch) {
184  if (fBranchName.Contains(".")){
185  TRegexp leafNameExpression ("\\.[a-zA-Z0-9_]+$");
186  TString leafName (fBranchName(leafNameExpression));
187  TString branchName = fBranchName(0, fBranchName.Length() - leafName.Length());
188  branch = fTreeReader->GetTree()->GetBranch(branchName);
189  if (!branch){
190  std::vector<TString> nameStack;
191  nameStack.push_back(TString()); //Trust me
192  nameStack.push_back(leafName.Strip(TString::kBoth, '.'));
193  leafName = branchName(leafNameExpression);
194  branchName = branchName(0, branchName.Length() - leafName.Length());
195 
196  branch = fTreeReader->GetTree()->GetBranch(branchName);
197  if (!branch) branch = fTreeReader->GetTree()->GetBranch(branchName + ".");
198  if (leafName.Length()) nameStack.push_back(leafName.Strip(TString::kBoth, '.'));
199 
200  while (!branch && branchName.Contains(".")){
201  leafName = branchName(leafNameExpression);
202  branchName = branchName(0, fBranchName.Length() - leafName.Length());
203  branch = fTreeReader->GetTree()->GetBranch(branchName);
204  if (!branch) branch = fTreeReader->GetTree()->GetBranch(branchName + ".");
205  nameStack.push_back(leafName.Strip(TString::kBoth, '.'));
206  }
207 
208  if (branch && branch->IsA() == TBranchElement::Class()){
209  TBranchElement *myBranchElement = (TBranchElement*)branch;
210 
211  TString traversingBranch = nameStack.back();
212  nameStack.pop_back();
213 
214  bool found = true;
215 
216  TDataType *finalDataType = 0;
217 
218  std::vector<Long64_t> offsets;
219  Long64_t offset = 0;
220  TClass *elementClass = 0;
221 
222  TObjArray *myObjArray = myBranchElement->GetInfo()->GetElements();
223  TVirtualStreamerInfo *myInfo = myBranchElement->GetInfo();
224 
225  while (nameStack.size() && found){
226  found = false;
227 
228  for (int i = 0; i < myObjArray->GetEntries(); ++i){
229 
230  TStreamerElement *tempStreamerElement = (TStreamerElement*)myObjArray->At(i);
231 
232  if (!strcmp(tempStreamerElement->GetName(), traversingBranch.Data())){
233  offset += myInfo->GetElementOffset(i);
234 
235  traversingBranch = nameStack.back();
236  nameStack.pop_back();
237 
238  elementClass = tempStreamerElement->GetClass();
239  if (elementClass) {
240  myInfo = elementClass->GetStreamerInfo(0);
241  myObjArray = myInfo->GetElements();
242  // FIXME: this is odd, why is 'i' not also reset????
243  }
244  else {
245  finalDataType = TDataType::GetDataType((EDataType)tempStreamerElement->GetType());
246  if (!finalDataType) {
247  TDictionary* seType = TDictionary::GetDictionary(tempStreamerElement->GetTypeName());
248  if (seType && seType->IsA() == TDataType::Class()) {
249  finalDataType = TDataType::GetDataType((EDataType)((TDataType*)seType)->GetType());
250  }
251  }
252  }
253 
254  if (tempStreamerElement->IsaPointer()){
255  offsets.push_back(offset);
256  offset = 0;
257  }
258 
259  found = true;
260  break;
261  }
262  }
263  }
264 
265  offsets.push_back(offset);
266 
267  if (found){
268  fStaticClassOffsets = offsets;
269 
270  if (fDict != finalDataType && fDict != elementClass){
271  Error("TTreeReaderValueBase::CreateProxy", "Wrong data type %s", finalDataType ? finalDataType->GetName() : elementClass ? elementClass->GetName() : "UNKNOWN");
272  fProxy = 0;
273  return;
274  }
275  }
276  }
277 
278 
279  if (!fStaticClassOffsets.size()) {
280  Error("TTreeReaderValueBase::CreateProxy()", "The tree does not have a branch called %s. You could check with TTree::Print() for available branches.", fBranchName.Data());
281  fProxy = 0;
282  return;
283  }
284  }
285  else {
286  myLeaf = branch->GetLeaf(TString(leafName(1, leafName.Length())));
287  if (!myLeaf){
288  Error("TTreeReaderValueBase::CreateProxy()",
289  "The tree does not have a branch, nor a sub-branch called %s. You could check with TTree::Print() for available branches.", fBranchName.Data());
290  fProxy = 0;
291  return;
292  }
293  else {
294  TDictionary *tempDict = TDictionary::GetDictionary(myLeaf->GetTypeName());
295  if (tempDict && tempDict->IsA() == TDataType::Class() && TDictionary::GetDictionary(((TDataType*)tempDict)->GetTypeName()) == fDict){
296  //fLeafOffset = myLeaf->GetOffset() / 4;
297  branchActualType = fDict;
298  fLeaf = myLeaf;
299  fBranchName = branchName;
300  fLeafName = leafName(1, leafName.Length());
301  }
302  else {
303  Error("TTreeReaderValueBase::CreateProxy()",
304  "Leaf of type %s cannot be read by TTreeReaderValue<%s>.", myLeaf->GetTypeName(), fDict->GetName());
305  }
306  }
307  }
308  }
309  else {
310  Error("TTreeReaderValueBase::CreateProxy()", "The tree does not have a branch called %s. You could check with TTree::Print() for available branches.", fBranchName.Data());
311  fProxy = 0;
312  return;
313  }
314  }
315 
316  if (!myLeaf && !fStaticClassOffsets.size()) {
317  const char* branchActualTypeName = GetBranchDataType(branch, branchActualType);
318 
319  if (!branchActualType) {
320  Error("TTreeReaderValueBase::CreateProxy()", "The branch %s contains data of type %s, which does not have a dictionary.",
321  fBranchName.Data(), branchActualTypeName ? branchActualTypeName : "{UNDETERMINED TYPE}");
322  fProxy = 0;
323  return;
324  }
325 
326  if (fDict != branchActualType) {
327  TDataType *dictdt = dynamic_cast<TDataType*>(fDict);
328  TDataType *actualdt = dynamic_cast<TDataType*>(branchActualType);
329  if (dictdt && actualdt && dictdt->GetType()>0
330  && dictdt->GetType() == actualdt->GetType()) {
331  // Same numerical type but different TDataType, likely Long64_t
332  } else {
333  Error("TTreeReaderValueBase::CreateProxy()",
334  "The branch %s contains data of type %s. It cannot be accessed by a TTreeReaderValue<%s>",
335  fBranchName.Data(), branchActualType->GetName(),
336  fDict->GetName());
337  return;
338  }
339  }
340  }
341 
342 
343  // Update named proxy's dictionary
344  if (namedProxy && !namedProxy->GetDict()) {
345  namedProxy->SetDict(fDict);
346  fProxy = namedProxy->GetProxy();
347  return;
348  }
349 
350  // Search for the branchname, determine what it contains, and wire the
351  // TBranchProxy representing it to us so we can access its data.
352  // A proxy for branch must not have been created before (i.e. check
353  // fProxies before calling this function!)
354 
355  TString membername;
356 
357  bool isTopLevel = branch->GetMother() == branch;
358  if (!isTopLevel) {
359  membername = strrchr(branch->GetName(), '.');
360  if (membername.IsNull()) {
361  membername = branch->GetName();
362  }
363  }
364  namedProxy = new TNamedBranchProxy(fTreeReader->fDirector, branch, membername);
365  fTreeReader->GetProxies()->Add(namedProxy);
366  fProxy = namedProxy->GetProxy();
367 }
368 
369 ////////////////////////////////////////////////////////////////////////////////
370 /// Retrieve the type of data stored by branch; put its dictionary into
371 /// dict, return its type name. If no dictionary is available, at least
372 /// its type name should be returned.
373 
375  TDictionary* &dict) const
376 {
377  dict = 0;
378  if (branch->IsA() == TBranchElement::Class()) {
379  TBranchElement* brElement = (TBranchElement*)branch;
380  if (brElement->GetType() == TBranchElement::kSTLNode ||
381  brElement->GetType() == TBranchElement::kLeafNode ||
382  brElement->GetType() == TBranchElement::kObjectNode) {
383 
384  TStreamerInfo *streamerInfo = brElement->GetInfo();
385  Int_t id = brElement->GetID();
386 
387  if (id >= 0){
388  TStreamerElement *element = (TStreamerElement*)streamerInfo->GetElements()->At(id);
389  if (element->IsA() == TStreamerSTL::Class()){
390  TStreamerSTL *myStl = (TStreamerSTL*)element;
391  dict = myStl->GetClass();
392  return 0;
393  }
394  }
395 
396  if (brElement->GetType() == 3 || brElement->GetType() == 4) {
397  dict = brElement->GetCurrentClass();
398  return brElement->GetTypeName();
399  }
400 
401  if (brElement->GetTypeName()) dict = TDictionary::GetDictionary(brElement->GetTypeName());
402  if (dict && dict->IsA() == TDataType::Class()) {
403  // Resolve the typedef.
404  dict = TDictionary::GetDictionary(((TDataType*)dict)->GetTypeName());
405  if (dict->IsA() != TDataType::Class()) {
406  // Might be a class.
407  if (dict != fDict) {
408  dict = TClass::GetClass(brElement->GetTypeName());
409  }
410  if (dict != fDict) {
411  dict = brElement->GetCurrentClass();
412  }
413  }
414  }
415  else if (!dict) {
416  dict = brElement->GetCurrentClass();
417  }
418 
419  return brElement->GetTypeName();
420  } else if (brElement->GetType() == TBranchElement::kClonesNode) {
421  dict = TClonesArray::Class();
422  return "TClonesArray";
423  } else if (brElement->GetType() == 31
424  || brElement->GetType() == 41) {
425  // it's a member, extract from GetClass()'s streamer info
426  Error("TTreeReaderValueBase::GetBranchDataType()", "Must use TTreeReaderValueArray to access a member of an object that is stored in a collection.");
427  }
428  else {
429  Error("TTreeReaderValueBase::GetBranchDataType()", "Unknown type and class combination: %i, %s", brElement->GetType(), brElement->GetClassName());
430  }
431  return 0;
432  } else if (branch->IsA() == TBranch::Class()
433  || branch->IsA() == TBranchObject::Class()
434  || branch->IsA() == TBranchSTL::Class()) {
435  if (branch->GetTree()->IsA() == TNtuple::Class()){
437  return dict->GetName();
438  }
439  const char* dataTypeName = branch->GetClassName();
440  if ((!dataTypeName || !dataTypeName[0])
441  && branch->IsA() == TBranch::Class()) {
442  TLeaf *myLeaf = branch->GetLeaf(branch->GetName());
443  if (myLeaf){
444  TDictionary *myDataType = TDictionary::GetDictionary(myLeaf->GetTypeName());
445  if (myDataType && myDataType->IsA() == TDataType::Class()){
446  dict = TDataType::GetDataType((EDataType)((TDataType*)myDataType)->GetType());
447  return myLeaf->GetTypeName();
448  }
449  }
450 
451 
452  // leaflist. Can't represent.
453  Error("TTreeReaderValueBase::GetBranchDataType()", "The branch %s was created using a leaf list and cannot be represented as a C++ type. Please access one of its siblings using a TTreeReaderValueArray:", branch->GetName());
454  TIter iLeaves(branch->GetListOfLeaves());
455  TLeaf* leaf = 0;
456  while ((leaf = (TLeaf*) iLeaves())) {
457  Error("TTreeReaderValueBase::GetBranchDataType()", " %s.%s", branch->GetName(), leaf->GetName());
458  }
459  return 0;
460  }
461  if (dataTypeName) dict = TDictionary::GetDictionary(dataTypeName);
462  return dataTypeName;
463  } else if (branch->IsA() == TBranchClones::Class()) {
464  dict = TClonesArray::Class();
465  return "TClonesArray";
466  } else if (branch->IsA() == TBranchRef::Class()) {
467  // Can't represent.
468  Error("TTreeReaderValueBase::GetBranchDataType()", "The branch %s is a TBranchRef and cannot be represented as a C++ type.", branch->GetName());
469  return 0;
470  } else {
471  Error("TTreeReaderValueBase::GetBranchDataType()", "The branch %s is of type %s - something that is not handled yet.", branch->GetName(), branch->IsA()->GetName());
472  return 0;
473  }
474 
475  return 0;
476 }
477 
Describe Streamer information for one class version.
Definition: TStreamerInfo.h:47
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition: TLeaf.h:37
An array of TObjects.
Definition: TObjArray.h:39
static TDataType * GetDataType(EDataType type)
Given a EDataType type, get the TDataType* that represents it.
Definition: TDataType.cxx:436
long long Long64_t
Definition: RtypesCore.h:69
Int_t GetID() const
virtual TLeaf * GetLeaf(const char *name) const
Return pointer to the 1st Leaf named name in thisBranch.
Definition: TBranch.cxx:1460
const char * GetTypeName() const
TTreeReader is a simple, robust and fast interface to read values from a TTree, TChain or TNtuple...
Definition: TTreeReader.h:48
Int_t GetType() const
Definition: TDataType.h:70
Ssiz_t Length() const
Definition: TString.h:390
const char * GetBranchDataType(TBranch *branch, TDictionary *&dict) const
Retrieve the type of data stored by branch; put its dictionary into dict, return its type name...
tuple offset
Definition: tree.py:93
virtual ~TTreeReaderValueBase()
Unregister from tree reader, cleanup.
Regular expression class.
Definition: TRegexp.h:35
static TDictionary * GetDictionary(const char *name)
Definition: TDictionary.cxx:84
Basic string class.
Definition: TString.h:137
EReadStatus ProxyRead()
Try to read the value from the TBranchProxy, returns the status of the read.
int Int_t
Definition: RtypesCore.h:41
Type GetType(const std::string &Name)
Definition: Systematics.cxx:34
const Detail::TBranchProxy * GetProxy() const
const char * Data() const
Definition: TString.h:349
unsigned char Byte_t
Definition: RtypesCore.h:60
void Class()
Definition: Class.C:29
TStreamerInfo * GetInfo() const
Get streamer info for the branch class.
ClassImp(ROOT::Internal::TTreeReaderValueBase) ROOT
Construct a tree value reader and register it with the reader object.
TLeaf * GetLeaf()
If we are reading a leaf, return the corresponding TLeaf.
virtual Bool_t IsaPointer() const
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition: TTree.cxx:4803
void SetDict(TDictionary *dict)
virtual const char * GetTypeName() const
Definition: TLeaf.h:81
TObjArray * GetElements() const
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist...
Definition: TClass.cxx:4256
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:46
This class defines an abstract interface that must be implemented by all classes that contain diction...
Definition: TDictionary.h:162
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition: TBranch.cxx:1533
virtual void CreateProxy()
Create the proxy object for our branch.
TClass * GetCurrentClass()
Return a pointer to the current type of the data member corresponding to branch element.
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:51
void * GetAddress()
Returns the memory address of the object being read.
TSubString Strip(EStripType s=kTrailing, char c= ' ') const
Return a substring of self stripped at beginning and/or end.
Definition: TString.cxx:1056
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:81
Bool_t IsNull() const
Definition: TString.h:387
TTree * GetTree() const
Definition: TBranch.h:183
A Branch for the case of an object.
TEllipse dict(9, 20, 3, 1.5)
virtual const char * GetTypeName() const
Return type name of element in the branch.
virtual TObjArray * GetElements() const =0
EDataType
Definition: TDataType.h:30
void DeregisterValueReader(ROOT::Internal::TTreeReaderValueBase *reader)
Remove a value reader for this tree.
virtual TTree * GetTree() const
Definition: TTree.h:436
TObjArray * GetListOfLeaves()
Definition: TBranch.h:178
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:494
virtual const char * GetClassName() const
Return the name of the user class whose content is stored in this branch, if any. ...
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2801
TClass * GetClass() const
Int_t GetType() const
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition: TString.h:567
#define NULL
Definition: Rtypes.h:82
Int_t GetType() const
A TTree object has a header with a name and a title.
Definition: TTree.h:98
TObject * At(Int_t idx) const
Definition: TObjArray.h:167
A TTree is a list of TBranches.
Definition: TBranch.h:58
Abstract Interface class describing Streamer information for one class.
virtual const char * GetClassName() const
Return the name of the user class whose content is stored in this branch, if any. ...
Definition: TBranch.cxx:1166
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition: TObject.cxx:379
TDictionary * GetDict() const
virtual Int_t GetElementOffset(Int_t id) const =0
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.