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