Logo ROOT   6.10/09
Reference Guide
TTreeReaderGenerator.cxx
Go to the documentation of this file.
1 // @(#)root/treeplayer:$Id$
2 // Author: Akos Hajdu 22/06/2015
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2015, 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 "TTreeReaderGenerator.h"
13 #include <algorithm>
14 #include <stdio.h>
15 #include <fstream>
16 
17 #include "TBranchElement.h"
18 #include "TChain.h"
19 #include "TClass.h"
20 #include "TClassEdit.h"
21 #include "TClonesArray.h"
22 #include "TError.h"
23 #include "TFile.h"
24 #include "TLeaf.h"
25 #include "TLeafC.h"
26 #include "TLeafObject.h"
27 #include "TROOT.h"
28 #include "TStreamerElement.h"
29 #include "TStreamerInfo.h"
30 #include "TTree.h"
32 #include "TVirtualStreamerInfo.h"
33 
34 namespace ROOT {
35 namespace Internal {
36 
37  ////////////////////////////////////////////////////////////////////////////////
38  /// Constructor. Analyzes the tree and writes selector.
39 
40  TTreeReaderGenerator::TTreeReaderGenerator(TTree* tree, const char *classname, Option_t *option) :
41  TTreeGeneratorBase(tree, option), fClassname(classname),
42  fIncludeAllLeaves(kFALSE), fIncludeAllTopmost(kFALSE)
43  {
44  ParseOptions();
46  WriteSelector();
47  }
48 
49  ////////////////////////////////////////////////////////////////////////////////
50  /// Add a reader to the generated code.
51 
53  TString branchName, TBranchDescriptor *parent, Bool_t isLeaf)
54  {
55  if(BranchNeedsReader(branchName, parent, isLeaf)) {
56  // Ignore unknown types
57  if (dataType.EqualTo("")) {
58  Warning("AddReader", "Ingored branch %s because type is unknown.", branchName.Data());
59  return;
60  }
61  // Loop through existing readers to check duplicate branch names
62  TIter next(&fListOfReaders);
63  TTreeReaderDescriptor *descriptor;
64  while ( ( descriptor = (TTreeReaderDescriptor*)next() ) ) {
65  if (descriptor->fBranchName.EqualTo(branchName)) {
66  Warning("AddReader", "Ignored branch %s because a branch with the same name already exists. "
67  "TTreeReader requires an unique name for the branches. You may need to "
68  "put a dot at the end of the name of top-level branches.", branchName.Data());
69  return;
70  }
71  }
72  name.ReplaceAll('.', '_'); // Replace dots with underscore
73  // Remove array dimensions from name
74  while (name.Index('[') >= 0 && name.Index(']') >= 0 && name.Index(']') > name.Index('[')) {
75  name.Remove(name.Index('['), name.Index(']') - name.Index('[') + 1);
76  }
77  fListOfReaders.Add( new TTreeReaderDescriptor(type, dataType, name, branchName) );
78  }
79  }
80 
81  ////////////////////////////////////////////////////////////////////////////////
82  /// Analyse sub-branches of 'branch' recursively and extract readers.
83 
85  {
86  if (info==0) info = branch->GetInfo();
87 
88  TIter branches(branch->GetListOfBranches());
89 
90  return AnalyzeBranches(desc, branches, info);
91  }
92 
93  ////////////////////////////////////////////////////////////////////////////////
94  /// Analyse sub-branches 'branches' recursively and extract readers.
95 
97  {
98  UInt_t lookedAt = 0; // Number of sub-branches analyzed
99  ELocation outer_isclones = kOut; // Is the parent branch a container
100  TString containerName; // Container name
101  TString subBranchPrefix; // Prefix of sub-branch (if the elements and sub-branches do not match).
102  Bool_t skipped = false; // Should the branch be skipped
103 
104  // Check for containers (TClonesArray or STL)
105  {
106  TIter peek = branches;
107  TBranchElement *branch = (TBranchElement*)peek();
108  if (desc && desc->IsClones()) {
109  outer_isclones = kClones;
110  containerName = "TClonesArray";
111  } else if (desc && desc->IsSTL()) {
112  outer_isclones = kSTL;
113  containerName = desc->fContainerName;
114  } else if (!desc && branch && branch->GetBranchCount() == branch->GetMother()) {
115  if ( ((TBranchElement*)(branch->GetMother()))->GetType()==3) {
116  outer_isclones = kClones;
117  containerName = "TClonesArray";
118  } else {
119  outer_isclones = kSTL;
120  containerName = branch->GetMother()->GetClassName();
121  }
122  }
123  // FIXME: this is wrong because 'branch' is the first sub-branch and even though
124  // it can be a collection, it does not mean that the other sub-branches are
125  // collections as well.
126  /* else if (branch->GetType() == 3) {
127  outer_isclones = kClones;
128  containerName = "TClonesArray";
129  } else if (branch->GetType() == 4) {
130  outer_isclones = kSTL;
131  containerName = branch->GetMother()->GetSubBranch(branch)->GetClassName();
132  }*/
133  if (desc) {
134  subBranchPrefix = desc->fSubBranchPrefix;
135  } else {
136  TBranchElement *mom = (TBranchElement*)branch->GetMother();
137  subBranchPrefix = mom->GetName();
138  if (subBranchPrefix[subBranchPrefix.Length()-1]=='.') {
139  subBranchPrefix.Remove(subBranchPrefix.Length()-1);
140  } else if (mom->GetType()!=3 && mom->GetType() != 4) {
141  subBranchPrefix = "";
142  }
143  }
144  }
145 
146  // Loop through elements (i.e., sub-branches). The problem is that the elements
147  // and sub-branches do not always match. For example suppose that class A contains
148  // members x and y, and there is a class B inheriting from A and containing an extra
149  // member z. It is possible that B has two elements: A and z but three sub-branches
150  // x, y and z. Therefore, the branch iterator is treated differently.
151  TIter elements( info->GetElements() );
152  for( TStreamerElement *element = (TStreamerElement*)elements();
153  element;
154  element = (TStreamerElement*)elements() )
155  {
156  Bool_t isBase = false; // Does the element correspond to a base class
157  Bool_t usedBranch = kTRUE; // Does the branch correspond to the element (i.e., they match)
158  Bool_t isLeaf = true; // Is the branch a leaf (i.e. no sub-branches)
159  TIter peek = branches; // Iterator for sub-branches
160  // Always start with the first available sub-branch and if it does not match the element,
161  // try the next ones
162  TBranchElement *branch = (TBranchElement*)peek();
163  // There is a problem if there are more elements than branches
164  if (branch==0) {
165  if (desc) {
166  Error("AnalyzeBranches","Ran out of branches when looking in branch %s, class %s",
167  desc->fBranchName.Data(), info->GetName());
168  } else {
169  Error("AnalyzeBranches","Ran out of branches when looking in class %s, element %s",
170  info->GetName(), element->GetName());
171  }
172  return lookedAt;
173  }
174 
175  if (info->GetClass()->GetCollectionProxy() && strcmp(element->GetName(),"This")==0) {
176  continue; // Skip the artifical streamer element.
177  }
178 
179  if (element->GetType() == -1) {
180  continue; // This is an ignored TObject base class.
181  }
182 
183  // Get branch name
184  TString branchname = branch->GetName();
185  TString branchEndName;
186  {
187  TLeaf *leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
188  if (leaf && outer_isclones == kOut
189  && !(branch->GetType() == 3 || branch->GetType() == 4)) branchEndName = leaf->GetName();
190  else branchEndName = branch->GetName();
191  Int_t pos;
192  pos = branchEndName.Index(".");
193  if (pos!=-1) {
194  if (subBranchPrefix.Length() && branchEndName.BeginsWith(subBranchPrefix)) {
195  branchEndName.Remove(0, subBranchPrefix.Length() + 1);
196  }
197  }
198  }
199 
200  TString dataType; // Data type of reader
201  TTreeReaderDescriptor::ReaderType readerType = TTreeReaderDescriptor::ReaderType::kValue;
202  Bool_t ispointer = false;
203  ELocation isclones = outer_isclones; // Is the actual sub-branch a collection (inherit from parent branch)
204  // Get data type
205  switch(element->GetType()) {
206  // Built-in types
207  case TVirtualStreamerInfo::kBool: { dataType = "Bool_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
208  case TVirtualStreamerInfo::kChar: { dataType = "Char_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
209  case TVirtualStreamerInfo::kShort: { dataType = "Short_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
210  case TVirtualStreamerInfo::kInt: { dataType = "Int_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
211  case TVirtualStreamerInfo::kLong: { dataType = "Long_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
212  case TVirtualStreamerInfo::kLong64: { dataType = "Long64_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
213  case TVirtualStreamerInfo::kFloat: { dataType = "Float_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
214  case TVirtualStreamerInfo::kFloat16: { dataType = "Float16_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
215  case TVirtualStreamerInfo::kDouble: { dataType = "Double_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
216  case TVirtualStreamerInfo::kDouble32:{ dataType = "Double32_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
217  case TVirtualStreamerInfo::kUChar: { dataType = "UChar_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
218  case TVirtualStreamerInfo::kUShort: { dataType = "unsigned short"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
219  case TVirtualStreamerInfo::kUInt: { dataType = "unsigned int"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
220  case TVirtualStreamerInfo::kULong: { dataType = "ULong_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
221  case TVirtualStreamerInfo::kULong64: { dataType = "ULong64_t"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
222  case TVirtualStreamerInfo::kBits: { dataType = "unsigned int"; readerType = TTreeReaderDescriptor::ReaderType::kValue; break; }
223  // Character arrays
224  case TVirtualStreamerInfo::kCharStar: { dataType = "Char_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
225  // Array of built-in types [8]
226  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kBool: { dataType = "Bool_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
227  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kChar: { dataType = "Char_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
228  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kShort: { dataType = "Short_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
229  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kInt: { dataType = "Int_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
230  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kLong: { dataType = "Long_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
231  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kLong64: { dataType = "Long64_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
232  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kFloat: { dataType = "Float_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
233  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kFloat16: { dataType = "Float16_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
234  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kDouble: { dataType = "Double_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
235  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kDouble32:{ dataType = "Double32_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
236  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kUChar: { dataType = "UChar_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
237  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kUShort: { dataType = "unsigned short"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
238  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kUInt: { dataType = "unsigned int"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
239  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kULong: { dataType = "ULong_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
240  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kULong64: { dataType = "ULong64_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
241  case TVirtualStreamerInfo::kOffsetL + TVirtualStreamerInfo::kBits: { dataType = "unsigned int"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
242  // Array of built-in types [n]
243  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kBool: { dataType = "Bool_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
244  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kChar: { dataType = "Char_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
245  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kShort: { dataType = "Short_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
246  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kInt: { dataType = "Int_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
247  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kLong: { dataType = "Long_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
248  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kLong64: { dataType = "Long64_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
249  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kFloat: { dataType = "Float_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
250  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kFloat16: { dataType = "Float16_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
251  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kDouble: { dataType = "Double_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
252  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kDouble32:{ dataType = "Double32_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
253  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kUChar: { dataType = "UChar_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
254  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kUShort: { dataType = "unsigned short"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
255  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kUInt: { dataType = "unsigned int"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
256  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kULong: { dataType = "ULong_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
257  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kULong64: { dataType = "ULong64_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
258  case TVirtualStreamerInfo::kOffsetP + TVirtualStreamerInfo::kBits: { dataType = "unsigned int"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
259  // array counter [n]
260  case TVirtualStreamerInfo::kCounter: { dataType = "Int_t"; readerType = TTreeReaderDescriptor::ReaderType::kArray; break; }
261  // other stuff (containers, classes, ...)
270  // set as pointers and fall through to the next switches
271  ispointer = true;
273  // This means an array of objects, but then fall through
274  readerType = TTreeReaderDescriptor::ReaderType::kArray;
282  TClass *cl = element->GetClassPointer();
283  R__ASSERT(cl);
284  dataType = cl->GetName();
285  // Check for containers
286  if (cl == TClonesArray::Class()) { // TClonesArray
287  isclones = kClones;
288  containerName = "TClonesArray";
289  if (outer_isclones != kOut) { // If the parent is already a collection
290  isclones = outer_isclones;
291  dataType = "TClonesArray";
292  } else {
293  readerType = TTreeReaderDescriptor::ReaderType::kArray;
294  dataType = GetContainedClassName(branch, element, ispointer);
295  }
296  } else if (cl->GetCollectionProxy()) { // STL collection
297  isclones = kSTL;
298  containerName = cl->GetName();
299  if (outer_isclones != kOut || containerName.EqualTo("vector<bool>")) {
300  // If the parent is already a collection we can only add this collection as a whole
301  // Also TTreeReaderArray does currently not support vectors of bool so
302  // that need to be added as a whole.
303  // Also getting the inner type of vector would return "unsigned" so the full
304  // name has to be compared
305  isclones = outer_isclones;
306  dataType = cl->GetName();
307  } else {
308  readerType = TTreeReaderDescriptor::ReaderType::kArray;
309  TClass *valueClass = cl->GetCollectionProxy()->GetValueClass();
310  if (valueClass) { // Get class inside container
311  dataType = valueClass->GetName();
312  }
313  else { // Get built-in type inside container
314  TDataType *valueClassBuiltIn = TDataType::GetDataType(cl->GetCollectionProxy()->GetType());
315  if (valueClassBuiltIn) dataType = valueClassBuiltIn->GetName();
316  else Error("AnalyzeBranches", "Could not get type from collection %s in branch %s", cl->GetName(), branch->GetName());
317  }
318  }
319  }
320 
321  // Analyze the actual element
322  // Possible cases:
323  // - Base class
324  // - Element and branch matches
325  // - Non-split: do nothing
326  // - Split: recurse with sub-sub-branches
327  // - Element and branch does not match: recurse with same branches
328  // - Not base class
329  // - Element and branch matches
330  // - Non-split: do nothing
331  // - Split: recurse with sub-sub-branches
332  // - Element and branch does not match: recurse with same branches
333  TBranch *parent = branch->GetMother()->GetSubBranch(branch);
334  TVirtualStreamerInfo *objInfo = 0;
335  if (branch->GetListOfBranches()->GetEntries()) {
336  objInfo = ((TBranchElement*)branch->GetListOfBranches()->At(0))->GetInfo();
337  } else {
338  objInfo = branch->GetInfo();
339  }
340  if (element->IsBase()) { // Base class
341  isBase = true;
342  if (cl == TObject::Class() && info->GetClass()->CanIgnoreTObjectStreamer())
343  {
344  continue; // Ignore TObject
345  }
346 
347  TBranchDescriptor *bdesc = 0;
348 
349  if (branchEndName == element->GetName()) { // The element and the branch matches
350  if (branch->GetListOfBranches()->GetEntries() == 0) { // The branch contains a non-split base class
351  // FIXME: nothing to do in such cases, because readers cannot access
352  // non-split members and a reader for the whole branch will be added
353  } else { // The branch contains a split base class
354  Int_t pos = branchname.Last('.');
355  if (pos != -1) {
356  branchname.Remove(pos);
357  }
358  TString local_prefix = desc ? desc->fSubBranchPrefix : TString(parent->GetName());
359  bdesc = new TBranchDescriptor(cl->GetName(), objInfo, branchname.Data(), local_prefix.Data(),
360  isclones, containerName, desc);
361  // Recurse: analyze sub-branches of the sub-branch
362  lookedAt += AnalyzeBranches(bdesc, branch, objInfo);
363  isLeaf = false;
364 
365  }
366  } else { // The element and the branch does not match, we need to loop over the next branches
367  Int_t pos = branchname.Last('.');
368  if (pos != -1) {
369  branchname.Remove(pos);
370  }
371  TString local_prefix = desc ? desc->fSubBranchPrefix : TString(parent->GetName());
372  objInfo = GetBaseClass(element);
373  if (objInfo == 0) {
374  continue; // There is no data in this base class
375  }
376  cl = objInfo->GetClass();
377  bdesc = new TBranchDescriptor(cl->GetName(), objInfo, branchname.Data(), local_prefix.Data(),
378  isclones, containerName, desc);
379  usedBranch = kFALSE;
380  // Recurse: analyze the sub-elements with the same branches
381  lookedAt += AnalyzeBranches(bdesc, branches, objInfo);
382  }
383  delete bdesc;
384  } else { // Not base class
385  TBranchDescriptor *bdesc = 0;
386  if (branchEndName == element->GetName()) { // The element and the branch matches
387  if (branch->GetListOfBranches()->GetEntries() == 0) { // The branch contains a non-split class
388  // FIXME: nothing to do in such cases, because readers cannot access
389  // non-split members and a reader for the whole branch will be added
390  } else { // The branch contains a split class
391  if (isclones != kOut) {
392  // We have to guess the version number!
393  cl = TClass::GetClass(dataType);
394  objInfo = GetStreamerInfo(branch, branch->GetListOfBranches(), cl);
395  }
396  bdesc = new TBranchDescriptor(cl->GetName(), objInfo, branch->GetName(), branch->GetName(),
397  isclones, containerName, desc);
398  // Recurse: analyze sub-branches of the sub-branch
399  lookedAt += AnalyzeBranches(bdesc, branch, objInfo);
400  isLeaf = false;
401  }
402  } else { // The element and the branch does not match, we need to loop over the next branches
403  TString local_prefix = desc ? desc->fSubBranchPrefix : TString(parent->GetName());
404  if (local_prefix.Length()) local_prefix += ".";
405  local_prefix += element->GetName();
406  objInfo = branch->GetInfo();
407  Int_t pos = branchname.Last('.');
408  if (pos != -1) {
409  branchname.Remove(pos);
410  }
411  if (isclones != kOut) {
412  // We have to guess the version number!
413  cl = TClass::GetClass(dataType);
414  objInfo = GetStreamerInfo(branch, branches, cl);
415  }
416  bdesc = new TBranchDescriptor(cl->GetName(), objInfo, branchname.Data(), local_prefix.Data(),
417  isclones, containerName, desc);
418  usedBranch = kFALSE;
419  skipped = kTRUE;
420  // Recurse: analyze the sub-elements with the same branches
421  lookedAt += AnalyzeBranches(bdesc, branches, objInfo);
422  }
423  delete bdesc;
424  }
425 
426  break;
427  }
428  default:
429  Error("AnalyzeBranch", "Unsupported type for %s (%d).", branch->GetName(), element->GetType());
430  }
431 
432  if (!isBase && !skipped) { // Add reader for the whole branch
433  if (outer_isclones != kOut && readerType == TTreeReaderDescriptor::ReaderType::kArray) {
434  Error("AnalyzeBranch", "Arrays inside collections are not supported yet (branch: %s).", branch->GetName());
435  } else {
436  if (outer_isclones != kOut || isclones != kOut) {
437  readerType = TTreeReaderDescriptor::ReaderType::kArray;
438  }
439  AddReader(readerType, dataType, branch->GetName(), branch->GetName(), desc, isLeaf);
440  }
441  }
442 
443  // If the branch was used, jump to the next
444  if (usedBranch) {
445  branches.Next();
446  ++lookedAt;
447  }
448  }
449 
450  return lookedAt;
451  }
452 
453  ////////////////////////////////////////////////////////////////////////////////
454  /// Analyze branch and add the variables found. The number of analyzed
455  /// sub-branches is returned.
456 
458  {
459  UInt_t extraLookedAt = 0;
460  TString prefix;
461 
462  TString branchName = branch->GetName();
463 
464  TObjArray *leaves = branch->GetListOfLeaves();
465  Int_t nleaves = leaves ? leaves->GetEntriesFast() : 0;
466 
467  // Loop through leaves and analyze them
468  for(int l=0;l<nleaves;l++) {
469  TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
470  extraLookedAt += AnalyzeOldLeaf(leaf, nleaves);
471  }
472 
473  return extraLookedAt;
474  }
475 
476  ////////////////////////////////////////////////////////////////////////////////
477  /// Analyze the leaf and add the variables found.
478 
480  {
481  if (leaf->IsA()==TLeafObject::Class()) {
482  Error("AnalyzeOldLeaf","TLeafObject not supported yet");
483  return 0;
484  }
485 
486  TString leafTypeName = leaf->GetTypeName();
487  Int_t pos = leafTypeName.Last('_');
488  //if (pos != -1) leafTypeName.Remove(pos); // FIXME: this is not required since it makes Float_t -> Float
489 
490  // Analyze dimensions
491  UInt_t dim = 0;
492  std::vector<Int_t> maxDim;
493 
494  TString dimensions;
495  TString temp = leaf->GetName();
496  pos = temp.Index("[");
497  if (pos != -1) {
498  if (pos) temp.Remove(0, pos);
499  dimensions.Append(temp);
500  }
501  temp = leaf->GetTitle();
502  pos = temp.Index("[");
503  if (pos != -1) {
504  if (pos) temp.Remove(0, pos);
505  dimensions.Append(temp);
506  }
507 
508  Int_t dimlen = dimensions.Length();
509 
510  if (dimlen) {
511  const char *current = dimensions.Data();
512 
513  Int_t index;
514  Int_t scanindex ;
515  while (current) {
516  current++;
517  if (current[0] == ']') {
518  maxDim.push_back(-1); // maxDim[dim] = -1; // Loop over all elements;
519  } else {
520  scanindex = sscanf(current,"%d",&index);
521  if (scanindex) {
522  maxDim.push_back(index); // maxDim[dim] = index;
523  } else {
524  maxDim.push_back(-2); // maxDim[dim] = -2; // Index is calculated via a variable.
525  }
526  }
527  dim ++;
528  current = (char*)strstr( current, "[" );
529  }
530  }
531 
532  if (dim == 0 && leaf->IsA() == TLeafC::Class()) {
533  dim = 1; // For C style strings
534  }
535 
536  TTreeReaderDescriptor::ReaderType type = TTreeReaderDescriptor::ReaderType::kValue;
537  TString dataType;
538  switch (dim) {
539  case 0: {
540  type = TTreeReaderDescriptor::ReaderType::kValue;
541  dataType = leafTypeName;
542  break;
543  }
544  case 1: {
545  type = TTreeReaderDescriptor::ReaderType::kArray;
546  dataType = leafTypeName;
547  break;
548  }
549  default: {
550  // TODO: transform this
551  /*type = "TArrayProxy<";
552  for(Int_t ind = dim - 2; ind > 0; --ind) {
553  type += "TMultiArrayType<";
554  }
555  type += "TArrayType<";
556  type += leaf->GetTypeName();
557  type += ",";
558  type += maxDim[dim-1];
559  type += "> ";
560  for(Int_t ind = dim - 2; ind > 0; --ind) {
561  type += ",";
562  type += maxDim[ind];
563  type += "> ";
564  }
565  type += ">";*/
566  break;
567  }
568  }
569 
570  // If there are multiple leaves (leaflist) the name of the branch is
571  // <branch_name>.<leaf_name>
572  // (Otherwise the brach name does not change)
573  TString branchName = leaf->GetBranch()->GetName();
574  if (nleaves > 1) {
575  branchName.Form("%s.%s", leaf->GetBranch()->GetName(), leaf->GetName());
576  }
577 
578  AddReader(type, dataType, leaf->GetName(), branchName, 0, kTRUE);
579 
580  return 0;
581  }
582 
583  ////////////////////////////////////////////////////////////////////////////////
584  /// Check whether a branch should have a corresponding reader added, depending
585  /// on the options provided by the user.
586 
588  {
589  if (isLeaf) { // Branch is a leaf
590  // Include if all leaves should be included or it is contained in any of the lists.
591  if (fIncludeAllLeaves) return kTRUE;
592  if (std::find(fIncludeLeaves.begin(), fIncludeLeaves.end(), branchName) != fIncludeLeaves.end()) return kTRUE;
593  if (std::find(fIncludeStruct.begin(), fIncludeStruct.end(), branchName) != fIncludeStruct.end()) return kTRUE;
594  if (!parent) { // Branch is topmost (top-level leaf)
595  if (fIncludeAllTopmost) return kTRUE;
596  } else { // Branch is not topmost
597  while (parent) { // Check if any parent is in the list of "include as leaves"
598  if (std::find(fIncludeLeaves.begin(), fIncludeLeaves.end(), parent->fBranchName) != fIncludeLeaves.end()) {
599  return kTRUE;
600  }
601  parent = parent->fParent;
602  }
603  }
604  } else { // Branch is not a leaf (has sub-branches)
605  if (std::find(fIncludeStruct.begin(), fIncludeStruct.end(), branchName) != fIncludeStruct.end()) return kTRUE;
606  if (!parent) { // Branch is topmost
607  if (fIncludeAllTopmost) return kTRUE;
608  }
609  }
610  return false;
611  }
612 
613  ////////////////////////////////////////////////////////////////////////////////
614  /// Parse the user options.
615 
617  if (fOptionStr.EqualTo("")) { // Empty -> include all leaves
619  } else if (fOptionStr.EqualTo("@")) { // "@" -> include all topmost
621  } else { // Otherwise split at ";" to get names
622  TObjArray *tokens = fOptionStr.Tokenize(TString(";"));
623  for (Int_t i = 0; i < tokens->GetEntries(); ++i) {
624  TString token = ((TObjString*)tokens->At(i))->GetString();
625  if ( token.Length() == 0 || (token.Length() == 1 && token[0] == '@') ) {
626  Warning("ParseOptions", "Ignored empty branch name in option string.");
627  } else if (token[0] == '@') { // "@X" means include X as a whole
628  token = TString(token.Data()+1);
629  fIncludeStruct.push_back(token);
630  } else { // "X" means include leaves of X
631  fIncludeLeaves.push_back(token);
632  }
633  if (!fTree->GetBranch(token)) { // Display a warning for non-existing branch names
634  Warning("ParseOptions", "Tree %s does not contain a branch named %s.", fTree->GetName(), token.Data());
635  }
636  }
637  delete tokens;
638  }
639  }
640 
641  ////////////////////////////////////////////////////////////////////////////////
642  /// Analyze tree and extract readers.
643 
645  {
646  TIter next(tree->GetListOfBranches());
647  TBranch *branch;
648 
649  // Loop through branches
650  while ( (branch = (TBranch*)next()) ) {
651  TVirtualStreamerInfo *info = 0;
652  // Get the name and the class of the branch
653  const char *branchName = branch->GetName();
654  const char *branchClassName = branch->GetClassName();
655  TClass *cl = TClass::GetClass(branchClassName);
656 
657  // Add headers for user classes
658  if (branchClassName && strlen(branchClassName)) {
659  AddHeader(cl);
660  }
661 
662  TString type = "unknown"; // Type of branch
663  ELocation isclones = kOut; // Type of container
664  TString containerName = ""; // Name of container
665  TBranchDescriptor *desc = 0;
666  // Check whether the branch is a container
667  if (cl) {
668  // Check if it is a TClonesArray
669  if (cl == TClonesArray::Class()) {
670  isclones = kClones;
671  containerName = "TClonesArray";
672  if (branch->IsA()==TBranchElement::Class()) {
673  // Get the class inside the TClonesArray
674  const char *cname = ((TBranchElement*)branch)->GetClonesName();
675  TClass *ncl = TClass::GetClass(cname);
676  if (ncl) {
677  cl = ncl;
678  info = GetStreamerInfo(branch, branch->GetListOfBranches(), cl);
679  } else {
680  Error("AnalyzeTree",
681  "Introspection of TClonesArray in older file not implemented yet.");
682  }
683  } else {
684  TClonesArray **ptr = (TClonesArray**)branch->GetAddress();
685  TClonesArray *clones = 0;
686  if (ptr==0) {
687  clones = new TClonesArray;
688  branch->SetAddress(&clones);
689  ptr = &clones;
690  }
691  branch->GetEntry(0);
692  TClass *ncl = *ptr ? (*ptr)->GetClass() : 0;
693  if (ncl) {
694  cl = ncl;
695  } else {
696  Error("AnalyzeTree",
697  "Introspection of TClonesArray for %s failed.",branch->GetName());
698  }
699  }
700  // Check if it is an STL container
701  } else if (cl->GetCollectionProxy()) {
702  isclones = kSTL;
703  containerName = cl->GetName();
704  // Get the type inside container
705  if (cl->GetCollectionProxy()->GetValueClass()) { // Class inside container
706  cl = cl->GetCollectionProxy()->GetValueClass();
707  } else { // RAW type (or missing class) inside container
708  // TODO: CheckForMissingClass?
709  // TTreeReaderArray does currently not support vectors of bool so that need to
710  // be added as a TTreeReaderValue<vector<bool>>. Also getting the inner type of
711  // vector would return "unsigned" so the full name has to be compared.
712  if (containerName.EqualTo("vector<bool>")) {
713  AddReader(TTreeReaderDescriptor::ReaderType::kValue,
714  containerName,
715  branch->GetName(), branch->GetName(), 0, kTRUE);
716  } else { // Otherwise we can generate a TTreeReaderArray with the inner type
717  AddReader(TTreeReaderDescriptor::ReaderType::kArray,
719  branch->GetName(), branch->GetName(), 0, kTRUE);
720  }
721  continue; // Nothing else to with this branch in these cases
722  }
723  }
724 
725  // Check class inside container and create a descriptor or add a reader
726  if (cl) {
727  if (cl->TestBit(TClass::kIsEmulation) || branchName[strlen(branchName)-1] == '.' || branch->GetSplitLevel()) {
728  TBranchElement *be = dynamic_cast<TBranchElement*>(branch);
729  TVirtualStreamerInfo *beinfo = (be && isclones == kOut)
730  ? be->GetInfo() : cl->GetStreamerInfo(); // the 2nd hand need to be fixed
731  // Create descriptor
732  desc = new TBranchDescriptor(cl->GetName(), beinfo, branchName, branchName, isclones, containerName);
733  info = beinfo;
734  } else {
735  // Add a reader for non-split classes
736  AddReader(isclones == kOut ?
737  TTreeReaderDescriptor::ReaderType::kValue
738  : TTreeReaderDescriptor::ReaderType::kArray,
739  cl->GetName(), branchName, branchName, 0, kTRUE);
740  // TODO: can't we just put a continue here?
741  }
742  }
743  }
744 
745  // Analyze sub-branches (if exist) and add readers
746  if (branch->GetListOfBranches()->GetEntries() == 0) { // Branch is non-splitted
747  if (cl) { // Non-split object
748  if (desc) { // If there is a descriptor add reader (otherwise
749  // it was already added).
750  AddReader(isclones == kOut ?
751  TTreeReaderDescriptor::ReaderType::kValue
752  : TTreeReaderDescriptor::ReaderType::kArray,
753  desc->GetName(), desc->fBranchName, desc->fBranchName, 0, kTRUE);
754  }
755  } else { // Top-level RAW type
756  AnalyzeOldBranch(branch); // Analyze branch and extract readers
757  }
758  } else { // Branch is splitted
759  TIter subnext( branch->GetListOfBranches() );
760  if (desc) {
761  // Analyze sub-branches and extract readers
762  TBranchElement *branchElem = dynamic_cast<TBranchElement*>(branch);
763  if (branchElem) {
764  AnalyzeBranches(desc, branchElem, info);
765  } else {
766  Error("AnalyzeTree", "Cannot analyze branch %s because it is not a TBranchElement.", branchName);
767  }
768  // Also add a reader for the whole branch
769  AddReader(isclones == kOut ?
770  TTreeReaderDescriptor::ReaderType::kValue
771  : TTreeReaderDescriptor::ReaderType::kArray,
772  desc->GetName(), desc->fBranchName, desc->fBranchName, 0, kFALSE);
773  }
774  }
775  delete desc;
776  }
777  }
778 
779  ////////////////////////////////////////////////////////////////////////////////
780  /// Generate code for selector class.
781 
783  {
784  // If no name is given, set to default (name of the tree)
785  if (!fClassname) fClassname = fTree->GetName();
786 
787  TString treefile;
788  if (fTree->GetDirectory() && fTree->GetDirectory()->GetFile()) {
789  treefile = fTree->GetDirectory()->GetFile()->GetName();
790  } else {
791  treefile = "Memory Directory";
792  }
793  // In the case of a chain, the GetDirectory information usually does
794  // pertain to the Chain itself but to the currently loaded tree.
795  // So we can not rely on it.
796  Bool_t ischain = fTree->InheritsFrom(TChain::Class());
797  Bool_t isHbook = fTree->InheritsFrom("THbookTree");
798  if (isHbook)
799  treefile = fTree->GetTitle();
800 
801  //======================Generate classname.h=====================
802  TString thead;
803  thead.Form("%s.h", fClassname.Data());
804  std::ofstream ofs (thead, std::ofstream::out);
805  if (!ofs) {
806  Error("WriteSelector","cannot open output file %s", thead.Data());
807  return;
808  }
809  // Print header
810  TDatime td;
811  ofs <<
812 R"CODE(//////////////////////////////////////////////////////////
813 // This class has been automatically generated on
814 // )CODE" << td.AsString() << R"CODE( by ROOT version )CODE" << gROOT->GetVersion() << std::endl;
815  if (!ischain) {
816  ofs << "// from TTree " << fTree->GetName() << "/" << fTree->GetTitle() << std::endl
817  << "// found on file: " << treefile << std::endl;
818  } else {
819  ofs << "// from TChain " << fTree->GetName() << "/" << fTree->GetTitle() << std::endl;
820  }
821  ofs <<
822 R"CODE(//////////////////////////////////////////////////////////
823 
824 #ifndef )CODE" << fClassname << R"CODE(_h
825 #define )CODE" << fClassname << R"CODE(_h
826 
827 #include <TROOT.h>
828 #include <TChain.h>
829 #include <TFile.h>
830 )CODE";
831  if (isHbook) ofs << "#include <THbookFile.h>" << std::endl;
832  ofs <<
833 R"CODE(#include <TSelector.h>
834 #include <TTreeReader.h>
835 #include <TTreeReaderValue.h>
836 #include <TTreeReaderArray.h>
837 
838 // Headers needed by this particular selector
839 )CODE";
840 
841  TIter next(&fListOfHeaders);
842  TObject *header;
843  while ( (header = next()) ) {
844  ofs << header->GetTitle() << std::endl;
845  }
846  ofs << std::endl << std::endl;
847 
848  // Generate class declaration with TTreeReaderValues and Arrays
849  ofs <<
850 R"CODE(class )CODE" << fClassname << R"CODE( : public TSelector {
851 public :
852  TTreeReader fReader; //!the tree reader
853  TTree *fChain = 0; //!pointer to the analyzed TTree or TChain
854 
855  // Readers to access the data (delete the ones you do not need).
856 )CODE";
857  next = &fListOfReaders;
858  TTreeReaderDescriptor *descriptor;
859  while ( ( descriptor = (TTreeReaderDescriptor*)next() ) ) {
860  ofs << " TTreeReader" << (descriptor->fType == TTreeReaderDescriptor::ReaderType::kValue ? "Value" : "Array")
861  << "<" << descriptor->fDataType
862  << "> " << descriptor->fName
863  << " = {fReader, \"" << descriptor->fBranchName << "\"};" << std::endl;
864  }
865  // Generate class member functions prototypes
866  ofs <<
867 R"CODE(
868 
869  )CODE" << fClassname << R"CODE((TTree * /*tree*/ =0) { }
870  virtual ~)CODE" << fClassname << R"CODE(() { }
871  virtual Int_t Version() const { return 2; }
872  virtual void Begin(TTree *tree);
873  virtual void SlaveBegin(TTree *tree);
874  virtual void Init(TTree *tree);
875  virtual Bool_t Notify();
876  virtual Bool_t Process(Long64_t entry);
877  virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0) { return fChain ? fChain->GetTree()->GetEntry(entry, getall) : 0; }
878  virtual void SetOption(const char *option) { fOption = option; }
879  virtual void SetObject(TObject *obj) { fObject = obj; }
880  virtual void SetInputList(TList *input) { fInput = input; }
881  virtual TList *GetOutputList() const { return fOutput; }
882  virtual void SlaveTerminate();
883  virtual void Terminate();
884 
885  ClassDef()CODE" << fClassname << R"CODE(,0);
886 
887 };
888 
889 #endif
890 
891 #ifdef )CODE" << fClassname << R"CODE(_cxx
892 void )CODE" << fClassname << R"CODE(::Init(TTree *tree)
893 {
894  // The Init() function is called when the selector needs to initialize
895  // a new tree or chain. Typically here the reader is initialized.
896  // It is normally not necessary to make changes to the generated
897  // code, but the routine can be extended by the user if needed.
898  // Init() will be called many times when running on PROOF
899  // (once per file to be processed).
900 
901  fReader.SetTree(tree);
902 }
903 
904 Bool_t )CODE" << fClassname << R"CODE(::Notify()
905 {
906  // The Notify() function is called when a new file is opened. This
907  // can be either for a new TTree in a TChain or when when a new TTree
908  // is started when using PROOF. It is normally not necessary to make changes
909  // to the generated code, but the routine can be extended by the
910  // user if needed. The return value is currently not used.
911 
912  return kTRUE;
913 }
914 
915 
916 #endif // #ifdef )CODE" << fClassname << R"CODE(_cxx
917 )CODE";
918  ofs.close();
919 
920  //======================Generate classname.C=====================
921  TString tcimp;
922  tcimp.Form("%s.C", fClassname.Data());
923  std::ofstream ofsc (tcimp, std::ofstream::out);
924  if (!ofsc) {
925  Error("WriteSelector","cannot open output file %s", tcimp.Data());
926  return;
927  }
928 
929  ofsc <<
930 R"CODE(#define )CODE" << fClassname << R"CODE(_cxx
931 // The class definition in )CODE" << fClassname << R"CODE(.h has been generated automatically
932 // by the ROOT utility TTree::MakeSelector(). This class is derived
933 // from the ROOT class TSelector. For more information on the TSelector
934 // framework see $ROOTSYS/README/README.SELECTOR or the ROOT User Manual.
935 
936 
937 // The following methods are defined in this file:
938 // Begin(): called every time a loop on the tree starts,
939 // a convenient place to create your histograms.
940 // SlaveBegin(): called after Begin(), when on PROOF called only on the
941 // slave servers.
942 // Process(): called for each event, in this function you decide what
943 // to read and fill your histograms.
944 // SlaveTerminate: called at the end of the loop on the tree, when on PROOF
945 // called only on the slave servers.
946 // Terminate(): called at the end of the loop on the tree,
947 // a convenient place to draw/fit your histograms.
948 //
949 // To use this file, try the following session on your Tree T:
950 //
951 // root> T->Process(")CODE" << fClassname << R"CODE(.C")
952 // root> T->Process(")CODE" << fClassname << R"CODE(.C","some options")
953 // root> T->Process(")CODE" << fClassname << R"CODE(.C+")
954 //
955 
956 
957 #include ")CODE" << thead << R"CODE("
958 #include <TH2.h>
959 #include <TStyle.h>
960 
961 void )CODE" << fClassname << R"CODE(::Begin(TTree * /*tree*/)
962 {
963  // The Begin() function is called at the start of the query.
964  // When running with PROOF Begin() is only called on the client.
965  // The tree argument is deprecated (on PROOF 0 is passed).
966 
967  TString option = GetOption();
968 }
969 
970 void )CODE" << fClassname << R"CODE(::SlaveBegin(TTree * /*tree*/)
971 {
972  // The SlaveBegin() function is called after the Begin() function.
973  // When running with PROOF SlaveBegin() is called on each slave server.
974  // The tree argument is deprecated (on PROOF 0 is passed).
975 
976  TString option = GetOption();
977 
978 }
979 
980 Bool_t )CODE" << fClassname << R"CODE(::Process(Long64_t entry)
981 {
982  // The Process() function is called for each entry in the tree (or possibly
983  // keyed object in the case of PROOF) to be processed. The entry argument
984  // specifies which entry in the currently loaded tree is to be processed.
985  // When processing keyed objects with PROOF, the object is already loaded
986  // and is available via the fObject pointer.
987  //
988  // This function should contain the \"body\" of the analysis. It can contain
989  // simple or elaborate selection criteria, run algorithms on the data
990  // of the event and typically fill histograms.
991  //
992  // The processing can be stopped by calling Abort().
993  //
994  // Use fStatus to set the return value of TTree::Process().
995  //
996  // The return value is currently not used.
997 
998  fReader.SetEntry(entry);
999 
1000  return kTRUE;
1001 }
1002 
1003 void )CODE" << fClassname << R"CODE(::SlaveTerminate()
1004 {
1005  // The SlaveTerminate() function is called after all entries or objects
1006  // have been processed. When running with PROOF SlaveTerminate() is called
1007  // on each slave server.
1008 
1009 }
1010 
1011 void )CODE" << fClassname << R"CODE(::Terminate()
1012 {
1013  // The Terminate() function is the last function to be called during
1014  // a query. It always runs on the client, it can be used to present
1015  // the results graphically or save the results to file.
1016 
1017 })CODE";
1018  ofsc.close();
1019  }
1020 
1021 } // namespace Internal
1022 } // namespace ROOT
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
virtual const char * GetClassName() const
Return the name of the user class whose content is stored in this branch, if any. ...
Definition: TBranch.cxx:1256
std::string GetName(const std::string &scope_name)
Definition: Cppyy.cxx:145
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition: TLeaf.h:32
An array of TObjects.
Definition: TObjArray.h:37
static TDataType * GetDataType(EDataType type)
Given a EDataType type, get the TDataType* that represents it.
Definition: TDataType.cxx:440
UInt_t AnalyzeOldLeaf(TLeaf *leaf, Int_t nleaves)
Analyze the leaf and add the variables found.
Int_t GetType() const
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
Bool_t EqualTo(const char *cs, ECaseCompare cmp=kExact) const
Definition: TString.h:581
virtual TClass * GetClass() const =0
Collectable string class.
Definition: TObjString.h:28
const char Option_t
Definition: RtypesCore.h:62
virtual TClass * GetValueClass() const =0
TString & ReplaceAll(const TString &s1, const TString &s2)
Definition: TString.h:640
Bool_t TestBit(UInt_t f) const
Definition: TObject.h:159
TBranch * GetSubBranch(const TBranch *br) const
Find the parent branch of child.
Definition: TBranch.cxx:1646
virtual const char * GetTypeName() const
Definition: TLeaf.h:76
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:4360
void AnalyzeTree(TTree *tree)
Analyze tree and extract readers.
void AddHeader(TClass *cl)
Add a header inclusion request.
TStreamerInfo * GetInfo() const
Get streamer info for the branch class.
#define R__ASSERT(e)
Definition: TError.h:96
#define gROOT
Definition: TROOT.h:375
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:587
TTreeReaderGenerator(TTree *tree, const char *classname, Option_t *option)
Constructor. Analyzes the tree and writes selector.
Basic string class.
Definition: TString.h:129
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2814
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
TObject * At(Int_t idx) const
Definition: TObjArray.h:165
virtual EDataType GetType() const =0
TString GetContainedClassName(TBranchElement *branch, TStreamerElement *element, Bool_t ispointer)
Get name of class inside a container.
UInt_t AnalyzeBranches(TBranchDescriptor *desc, TBranchElement *branch, TVirtualStreamerInfo *info)
Analyse sub-branches of &#39;branch&#39; recursively and extract readers.
TBranchElement * GetBranchCount() const
void WriteSelector()
Generate code for selector class.
virtual TObjArray * GetListOfBranches()
Definition: TTree.h:405
void Class()
Definition: Class.C:29
TString & Append(const char *cs)
Definition: TString.h:497
TObjArray * GetListOfBranches()
Definition: TBranch.h:182
virtual TFile * GetFile() const
Definition: TDirectory.h:145
virtual TBranch * GetBranch(const char *name)
Return pointer to the branch with the given name in this tree or its friends.
Definition: TTree.cxx:4979
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:44
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:436
Bool_t BeginsWith(const char *s, ECaseCompare cmp=kExact) const
Definition: TString.h:563
TObject * Next()
Definition: TCollection.h:153
TVirtualStreamerInfo * GetStreamerInfo(TBranch *branch, TIter current, TClass *cl)
Return the correct TStreamerInfo of class &#39;cl&#39; in the list of branches (current) [Assuming these bran...
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2332
unsigned int UInt_t
Definition: RtypesCore.h:42
Int_t GetEntriesFast() const
Definition: TObjArray.h:64
Ssiz_t Length() const
Definition: TString.h:388
TLine * l
Definition: textangle.C:4
Bool_t CanIgnoreTObjectStreamer()
Definition: TClass.h:348
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:71
void Warning(const char *location, const char *msgfmt,...)
A Branch for the case of an object.
const Bool_t kFALSE
Definition: RtypesCore.h:92
TString & Remove(Ssiz_t pos)
Definition: TString.h:621
TObjArray * Tokenize(const TString &delim) const
This function is used to isolate sequential tokens in a TString.
Definition: TString.cxx:2251
TObject * UncheckedAt(Int_t i) const
Definition: TObjArray.h:89
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition: TString.cxx:875
virtual TObjArray * GetElements() const =0
TDirectory * GetDirectory() const
Definition: TTree.h:380
int type
Definition: TGX11.cxx:120
void ParseOptions()
Parse the user options.
const char * AsString() const
Return the date & time as a string (ctime() format).
Definition: TDatime.cxx:101
TObjArray * GetListOfLeaves()
Definition: TBranch.h:183
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:2885
TClass * GetClass() const
Definition: TClonesArray.h:57
Mother of all ROOT objects.
Definition: TObject.h:37
virtual const char * GetTitle() const
Returns title of object.
Definition: TObject.cxx:408
An array of clone (identical) objects.
Definition: TClonesArray.h:32
virtual void Add(TObject *obj)
Definition: TList.h:77
Bool_t BranchNeedsReader(TString branchName, TBranchDescriptor *parent, Bool_t isLeaf)
Check whether a branch should have a corresponding reader added, depending on the options provided by...
Int_t GetEntries() const
Return the number of objects in array (i.e.
Definition: TObjArray.cxx:494
Definition: tree.py:1
A TTree object has a header with a name and a title.
Definition: TTree.h:78
void AddReader(TTreeReaderDescriptor::ReaderType type, TString dataType, TString name, TString branchName, TBranchDescriptor *parent=0, Bool_t isLeaf=kTRUE)
Add a reader to the generated code.
UInt_t AnalyzeOldBranch(TBranch *branch)
Analyze branch and add the variables found.
TBranch * GetBranch() const
Definition: TLeaf.h:65
A TTree is a list of TBranches.
Definition: TBranch.h:57
Abstract Interface class describing Streamer information for one class.
TVirtualStreamerInfo * GetBaseClass(TStreamerElement *element)
Check if element is a base class and if yes, return the base class.
const Bool_t kTRUE
Definition: RtypesCore.h:91
TBranch * GetMother() const
Get our top-level parent branch in the tree.
Definition: TBranch.cxx:1625
void Error(ErrorHandler_t func, int code, const char *va_(fmt),...)
Write error message and call a handler, if required.
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:48
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition: TDatime.h:37
const char * Data() const
Definition: TString.h:347