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