Logo ROOT  
Reference Guide
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
Loading...
Searching...
No Matches
TTreeFormula.cxx
Go to the documentation of this file.
1// @(#)root/treeplayer:$Id$
2// Author: Rene Brun 19/01/96
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include "TROOT.h"
13#include "TTreeFormula.h"
14#include "TList.h"
15#include "TTree.h"
16#include "TBuffer.h"
17#include "TBranch.h"
18#include "TBranchObject.h"
19#include "TBranchElement.h"
20#include "TClonesArray.h"
21#include "TLeafB.h"
22#include "TLeafC.h"
23#include "TLeafElement.h"
24#include "TLeafObject.h"
25#include "TMethodCall.h"
26#include "TCutG.h"
27#include "TRandom.h"
28#include "TInterpreter.h"
29#include "TDataType.h"
30#include "TStreamerInfo.h"
31#include "TStreamerElement.h"
32#include "TArrayI.h"
33#include "TAxis.h"
34#include "TError.h"
36#include "TString.h"
37#include "TMath.h"
38
39#include "TVirtualRefProxy.h"
40#include "TTreeFormulaManager.h"
41#include "TFormLeafInfo.h"
42#include "TMethod.h"
44#include "strlcpy.h"
45#include "snprintf.h"
46#include "TEntryList.h"
47
48#include <cctype>
49#include <cstdio>
50#include <cmath>
51#include <cstdlib>
52#include <typeinfo>
53#include <algorithm>
54
55const Int_t kMaxLen = 2048;
56
57/** \class TTreeFormula
58Used to pass a selection expression to the Tree drawing routine. See TTree::Draw
59
60A TreeFormula can contain any arithmetic expression including
61standard operators and mathematical functions separated by operators.
62Examples of valid expression:
63~~~{.cpp}
64 "x<y && sqrt(z)>3.2"
65~~~
66TTreeFormula now relies on a variety of TFormLeafInfo classes to handle the
67reading of the information. Here is the list of theses classes:
68 - TFormLeafInfo
69 - TFormLeafInfoDirect
70 - TFormLeafInfoNumerical
71 - TFormLeafInfoClones
72 - TFormLeafInfoCollection
73 - TFormLeafInfoPointer
74 - TFormLeafInfoMethod
75 - TFormLeafInfoMultiVarDim
76 - TFormLeafInfoMultiVarDimDirect
77 - TFormLeafInfoCast
78
79The following method are available from the TFormLeafInfo interface:
80
81 - AddOffset(Int_t offset, TStreamerElement* element)
82 - GetCounterValue(TLeaf* leaf) : return the size of the array pointed to.
83 - GetObjectAddress(TLeafElement* leaf) : Returns the location of the object pointed to.
84 - GetMultiplicity() : Returns info on the variability of the number of elements
85 - GetNdata(TLeaf* leaf) : Returns the number of elements
86 - GetNdata() : Used by GetNdata(TLeaf* leaf)
87 - GetValue(TLeaf *leaf, Int_t instance = 0) : Return the value
88 - GetValuePointer(TLeaf *leaf, Int_t instance = 0) : Returns the address of the value
89 - GetLocalValuePointer(TLeaf *leaf, Int_t instance = 0) : Returns the address of the value of 'this' LeafInfo
90 - IsString()
91 - ReadValue(char *where, Int_t instance = 0) : Internal function to interpret the location 'where'
92 - Update() : react to the possible loading of a shared library.
93*/
94
96
97////////////////////////////////////////////////////////////////////////////////
98
99inline static void R__LoadBranch(TBranch* br, Long64_t entry, bool quickLoad)
100{
101 if (!quickLoad || (br->GetReadEntry() != entry)) {
102 br->GetEntry(entry);
103 }
104}
105
106////////////////////////////////////////////////////////////////////////////////
107/// \class TDimensionInfo
108/// A small helper class to help in keeping track of the array
109/// dimensions encountered in the analysis of the expression.
110
111class TDimensionInfo : public TObject {
112public:
113 Int_t fCode; // Location of the leaf in TTreeFormula::fCode
114 Int_t fOper; // Location of the Helper using the leaf in TTreeFormula::fOper
119 ~TDimensionInfo() override {};
120};
121
122////////////////////////////////////////////////////////////////////////////////
123/// TreeFormula constructor only valid for ROOT I/O purposes.
124
125TTreeFormula::TTreeFormula(TRootIOCtor*): ROOT::v5::TFormula(), fQuickLoad(false), fNeedLoading(true),
126 fDidBooleanOptimization(false), fDimensionSetup(nullptr)
127
128{
129 fTree = nullptr;
130 fLookupType = nullptr;
131 fNindex = 0;
132 fNcodes = 0;
133 fAxis = nullptr;
134 fHasCast = false;
135 fManager = nullptr;
136 fMultiplicity = 0;
137 fConstLD = nullptr;
138
139 Int_t j,k;
140 for (j=0; j<kMAXCODES; j++) {
141 fNdimensions[j] = 0;
142 fCodes[j] = 0;
143 fNdata[j] = 1;
144 fHasMultipleVarDim[j] = false;
145 for (k = 0; k<kMAXFORMDIM; k++) {
146 fIndexes[j][k] = -1;
147 fCumulSizes[j][k] = 1;
148 fVarIndexes[j][k] = nullptr;
149 }
150 }
151}
152
153////////////////////////////////////////////////////////////////////////////////
154/// Normal TTree Formula Constructor
155
156TTreeFormula::TTreeFormula(const char *name,const char *expression, TTree *tree)
157 :ROOT::v5::TFormula(), fTree(tree), fQuickLoad(false), fNeedLoading(true),
158 fDidBooleanOptimization(false), fDimensionSetup(nullptr)
159{
160 Init(name,expression);
161}
162
163////////////////////////////////////////////////////////////////////////////////
164/// Constructor used during the expansion of an alias
165
166TTreeFormula::TTreeFormula(const char *name,const char *expression, TTree *tree,
167 const std::vector<std::string>& aliases)
168 :ROOT::v5::TFormula(), fTree(tree), fQuickLoad(false), fNeedLoading(true),
169 fDidBooleanOptimization(false), fDimensionSetup(nullptr), fAliasesUsed(aliases)
170{
171 Init(name,expression);
172}
173
174////////////////////////////////////////////////////////////////////////////////
175/// Initialization called from the constructors.
176
177void TTreeFormula::Init(const char*name, const char* expression)
178{
180
183 fNcodes = 0;
184 fMultiplicity = 0;
185 fAxis = nullptr;
186 fHasCast = false;
187 fConstLD = nullptr;
188 Int_t i,j,k;
190 fManager->Add(this);
191
192 for (j=0; j<kMAXCODES; j++) {
193 fNdimensions[j] = 0;
195 fCodes[j] = 0;
196 fNdata[j] = 1;
197 fHasMultipleVarDim[j] = false;
198 for (k = 0; k<kMAXFORMDIM; k++) {
199 fIndexes[j][k] = -1;
200 fCumulSizes[j][k] = 1;
201 fVarIndexes[j][k] = nullptr;
202 }
203 }
204
206
207 if (Compile(expression)) {
208 fTree = nullptr; fNdim = 0;
209 if(savedir) savedir->cd();
210 return;
211 }
212
213 if (fNcodes >= kMAXFOUND) {
214 Warning("TTreeFormula","Too many items in expression:%s",expression);
216 }
217 SetName(name);
218
219 for (i=0;i<fNoper;i++) {
220
221 if (GetAction(i)==kDefinedString) {
224 if (!leafc) continue;
225
226 // We have a string used as a string
227
228 // This dormant portion of code would be used if (when?) we allow the histogramming
229 // of the integral content (as opposed to the string content) of strings
230 // held in a variable size container delimited by a null (as opposed to
231 // a fixed size container or variable size container whose size is controlled
232 // by a variable). In GetNdata, we will then use strlen to grab the current length.
233 //fCumulSizes[i][fNdimensions[i]-1] = 1;
234 //fUsedSizes[fNdimensions[i]-1] = -TMath::Abs(fUsedSizes[fNdimensions[i]-1]);
235 //fUsedSizes[0] = - TMath::Abs( fUsedSizes[0]);
236
237 if (fNoper == 1) {
238 // If the string is by itself, then it can safely be histogrammed as
239 // in a string based axis. To histogram the number inside the string
240 // just make it part of a useless expression (for example: mystring+0)
242 }
243 continue;
244 }
245 if (GetAction(i)==kJump && GetActionParam(i)==(fNoper-1)) {
246 // We have cond ? string1 : string2
248 }
249 }
250 if (fNoper == 1 && GetAction(0)==kStringConst) {
252 }
253 if (fNoper==1 && GetAction(0)==kAliasString) {
256 if (subform->IsString()) SetBit(kIsCharacter);
257 } else if (fNoper==2 && GetAction(0)==kAlternateString) {
260 if (subform->IsString()) SetBit(kIsCharacter);
261 }
262
263 fManager->Sync();
264
265 // Let's verify the indexes and dies if we need to.
266 Int_t k0,k1;
267 for(k0 = 0; k0 < fNcodes; k0++) {
268 for(k1 = 0; k1 < fNdimensions[k0]; k1++ ) {
269 // fprintf(stderr,"Saw %d dim %d and index %d\n",k1, fFixedSizes[k0][k1], fIndexes[k0][k1]);
270 if ( fIndexes[k0][k1]>=0 && fFixedSizes[k0][k1]>=0
271 && fIndexes[k0][k1]>=fFixedSizes[k0][k1]) {
272 Error("TTreeFormula",
273 "Index %d for dimension #%d in %s is too high (max is %d)",
274 fIndexes[k0][k1],k1+1, expression,fFixedSizes[k0][k1]-1);
275 fTree = nullptr; fNdim = 0;
276 if(savedir) savedir->cd();
277 return;
278 }
279 }
280 }
281
282 // Create a list of unique branches to load.
283 for(k=0; k<fNcodes ; k++) {
284 TLeaf *leaf = k <= fLeaves.GetLast() ? (TLeaf*)fLeaves.UncheckedAt(k) : nullptr;
285 TBranch *branch = nullptr;
286 if (leaf) {
287 branch = leaf->GetBranch();
288 if (fBranches.FindObject(branch)) branch = nullptr;
289 }
291 }
292
293 if (IsInteger(false)) SetBit(kIsInteger);
294
296 // Call TTree::GetEntries() to insure that it is already calculated.
297 // This will need to be done anyway at the first iteration and insure
298 // that it will not mess up the branch reading (because TTree::GetEntries
299 // opens all the file in the chain and 'stays' on the last file.
300
303 fTree->GetEntries();
304 if (treenumber != fTree->GetTreeNumber()) {
305 if (readentry >= 0) {
307 }
309 } else {
310 if (readentry >= 0) {
312 }
313 }
314
315 }
316
317 if(savedir) savedir->cd();
318}
319
320////////////////////////////////////////////////////////////////////////////////
321/// Tree Formula default destructor.
322
324{
325 if (fManager) {
326 fManager->Remove(this);
327 if (fManager->fFormulas.GetLast()<0) {
328 delete fManager;
329 fManager = nullptr;
330 }
331 }
332 // Objects in fExternalCuts are not owned and should not be deleted
333 // fExternalCuts.Clear();
338 if (fLookupType) delete [] fLookupType;
339 for (int j=0; j<fNcodes; j++) {
340 for (int k = 0; k<fNdimensions[j]; k++) {
341 if (fVarIndexes[j][k]) delete fVarIndexes[j][k];
342 fVarIndexes[j][k] = nullptr;
343 }
344 }
345 if (fDimensionSetup) {
347 delete fDimensionSetup;
348 }
349 delete[] fConstLD;
350}
351
352////////////////////////////////////////////////////////////////////////////////
353/// This method is used internally to decode the dimensions of the variables.
354
357 Int_t& virt_dim) {
358 if (info) {
360 //if (fIndexes[code][info->fDim]<0) { // removed because the index might be out of bounds!
361 info->fVirtDim = virt_dim;
362 fManager->AddVarDims(virt_dim); // if (!fVarDims[virt_dim]) fVarDims[virt_dim] = new TArrayI;
363 //}
364 }
365
366 Int_t vsize = 0;
367 bool scalarindex = false;
368
369 if (fIndexes[code][fNdimensions[code]]==-2) {
371 // ASSERT(indexvar!=0);
372 Int_t index_multiplicity = indexvar->GetMultiplicity();
373 switch (index_multiplicity) {
374 case 0:
375 scalarindex = true;
376 vsize = 1;
377 break;
378 case -1:
379 case 2:
380 vsize = indexvar->GetNdata();
381 break;
382 case 1:
383 vsize = -1;
384 break;
385 };
386 } else vsize = size;
387
388 fCumulSizes[code][fNdimensions[code]] = size;
389
390 if ( !scalarindex && fIndexes[code][fNdimensions[code]] < 0 ) {
392 }
393
394 fNdimensions[code] ++;
395
396}
397
398////////////////////////////////////////////////////////////////////////////////
399/// This method is used internally to decode the dimensions of the variables.
400
402{
403 // We assume that there are NO white spaces in the info string
404 const char * current;
406
407 current = info;
408 vardim = 0;
409 // the next value could be before the string but
410 // that's okay because the next operation is ++
411 // (this is to avoid (?) a if statement at the end of the
412 // loop)
413 if (current[0] != '[') current--;
414 while (current) {
415 current++;
416 scanindex = sscanf(current,"%d",&size);
417 // if scanindex is 0 then we have a name index thus a variable
418 // array (or TClonesArray!).
419
420 if (scanindex==0) size = -1;
421
423
424 if (fNdimensions[code] >= kMAXFORMDIM) {
425 // NOTE: test that fNdimensions[code] is NOT too big!!
426
427 break;
428 }
429 current = (char*)strstr( current, "[" );
430 }
431 return vardim;
432}
433
434
435////////////////////////////////////////////////////////////////////////////////
436/// This method stores the dimension information for later usage.
437
445
446////////////////////////////////////////////////////////////////////////////////
447/// This method is used internally to decode the dimensions of the variables.
448
450 TFormLeafInfo * /* maininfo */,
451 bool useCollectionObject) {
452 Int_t ndim, size, current, vardim;
453 vardim = 0;
454
455 const TStreamerElement * elem = leafinfo->fElement;
456 TClass* c = elem ? elem->GetClassPointer() : nullptr;
457
459 if (multi) {
460 // We have a second variable dimensions
462 multi->fDim = fNdimensions[code];
463 return RegisterDimensions(code, -1, multi);
464 }
465 if (elem->IsA() == TStreamerBasicPointer::Class()) {
466
467 if (elem->GetArrayDim()>0) {
468
469 ndim = elem->GetArrayDim();
470 size = elem->GetMaxIndex(0);
471 vardim += RegisterDimensions(code, -1);
472 } else {
473 ndim = 1;
474 size = -1;
475 }
476
478 TClass *cl = leafinfo->fClass;
480 TStreamerElement* counter = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(array->GetCountName(),offset);
481#if 1
482 leafinfo->fCounter = new TFormLeafInfo(cl,offset,counter);
483#else /* Code is not ready yet see revision 14078 */
484 if (maininfo==0 || maininfo==leafinfo || 1) {
485 leafinfo->fCounter = new TFormLeafInfo(cl,offset,counter);
486 } else {
487 leafinfo->fCounter = maininfo->DeepCopy();
489 while(currentinfo->fNext && currentinfo->fNext->fNext) currentinfo=currentinfo->fNext;
490 delete currentinfo->fNext;
491 currentinfo->fNext = new TFormLeafInfo(cl,offset,counter);
492 }
493#endif
494 } else if (!useCollectionObject && elem->GetClassPointer() == TClonesArray::Class() ) {
495
496 ndim = 1;
497 size = -1;
498
501 TStreamerElement *counter = ((TStreamerInfo*)clonesClass->GetStreamerInfo())->GetStreamerElement("fLast",c_offset);
502 leafinfo->fCounter = new TFormLeafInfo(clonesClass,c_offset,counter);
503
504 } else if (!useCollectionObject && elem->GetClassPointer() && elem->GetClassPointer()->GetCollectionProxy() ) {
505
506 if ( typeid(*leafinfo) == typeid(TFormLeafInfoCollection) ) {
507 ndim = 1;
508 size = -1;
509 } else {
511 ndim = 1;
512 size = 1;
513 }
514
515 } else if ( c && c->GetReferenceProxy() && c->GetReferenceProxy()->HasCounter() ) {
516 ndim = 1;
517 size = -1;
518 } else if (elem->GetArrayDim()>0) {
519
520 ndim = elem->GetArrayDim();
521 size = elem->GetMaxIndex(0);
522
523 } else if ( elem->GetNewType()== TStreamerInfo::kCharStar) {
524
525 // When we implement being able to read the length from
526 // strlen, we will have:
527 // ndim = 1;
528 // size = -1;
529 // until then we more or so die:
530 ndim = 1;
531 size = 1; //NOTE: changed from 0
532
533 } else return 0;
534
535 current = 0;
536 do {
538
539 if (fNdimensions[code] >= kMAXFORMDIM) {
540 // NOTE: test that fNdimensions[code] is NOT too big!!
541
542 break;
543 }
544 current++;
545 size = elem->GetMaxIndex(current);
546 } while (current<ndim);
547
548 return vardim;
549}
550
551////////////////////////////////////////////////////////////////////////////////
552/// This method is used internally to decode the dimensions of the variables.
553
555 TBranchElement * leafcount2 = branch->GetBranchCount2();
556 if (leafcount2) {
557 // With have a second variable dimensions
558 TBranchElement *leafcount = dynamic_cast<TBranchElement*>(branch->GetBranchCount());
559
560 R__ASSERT(leafcount); // The function should only be called on a functional TBranchElement object
561
565 fHasMultipleVarDim[code] = true;
566
567 info->fCounter = new TFormLeafInfoDirect(leafcount);
568 info->fCounter2 = new TFormLeafInfoDirect(leafcount2);
569 info->fDim = fNdimensions[code];
570 //if (fIndexes[code][info->fDim]<0) {
571 // info->fVirtDim = virt_dim;
572 // if (!fVarDims[virt_dim]) fVarDims[virt_dim] = new TArrayI;
573 //}
574 return RegisterDimensions(code, -1, info);
575 }
576 return 0;
577}
578
579////////////////////////////////////////////////////////////////////////////////
580/// This method is used internally to decode the dimensions of the variables.
581
584
585 // Let see if we can understand the structure of this branch.
586 // Usually we have: leafname[fixed_array] leaftitle[var_array]\type
587 // (with fixed_array that can be a multi-dimension array.
588 const char *tname = leaf->GetTitle();
589 char *leaf_dim = (char*)strstr( tname, "[" );
590
591 const char *bname = leaf->GetBranch()->GetName();
592 char *branch_dim = (char*)strstr(bname,"[");
593 if (branch_dim) branch_dim++; // skip the '['
594
595 bool isString = false;
596 if (leaf->IsA() == TLeafElement::Class()) {
597 Int_t type =((TBranchElement*)leaf->GetBranch())->GetStreamerType();
600 } else {
601 isString = (leaf->IsA() == TLeafC::Class());
602 }
603 if (leaf_dim) {
604 leaf_dim++; // skip the '['
606 // then both are NOT the same so do the leaf title first:
610 && (leaf_dim+strlen(branch_dim))[0]=='[') {
611 // we have extra info in the leaf title
613 }
614 }
615 if (branch_dim) {
616 // then both are NOT same so do the branch name next:
617 if (isString) {
619 } else {
621 }
622 }
623 if (leaf->IsA() == TLeafElement::Class()) {
624 TBranchElement* branch = (TBranchElement*) leaf->GetBranch();
625 if (branch->GetBranchCount2()) {
626
627 if (!branch->GetBranchCount()) {
628 Warning("DefinedVariable",
629 "Noticed an incorrect in-memory TBranchElement object (%s).\nIt has a BranchCount2 but no BranchCount!\nThe result might be incorrect!",
630 branch->GetName());
631 return numberOfVarDim;
632 }
633
634 // Switch from old direct style to using a TLeafInfo
635 if (fLookupType[code] == kDataMember)
636 Warning("DefinedVariable",
637 "Already in kDataMember mode when handling multiple variable dimensions");
638 fLookupType[code] = kDataMember;
639
640 // Feed the information into the Dimensions system
642
643 }
644 }
645 return numberOfVarDim;
646}
647
648////////////////////////////////////////////////////////////////////////////////
649/// This method check for treat the case where expression contains $Atl and load up
650/// both fAliases and fExpr.
651/// We return:
652/// - -1 in case of failure
653/// - 0 in case we did not find $Alt
654/// - the action number in case of success.
655
657{
658 static const char *altfunc = "Alt$(";
659 static const char *minfunc = "MinIf$(";
660 static const char *maxfunc = "MaxIf$(";
661 Int_t action = 0;
662 Int_t start = 0;
663
664 if ( strncmp(expression,altfunc,strlen(altfunc))==0
665 && expression[strlen(expression)-1]==')' ) {
667 start = strlen(altfunc);
668 }
669 if ( strncmp(expression,maxfunc,strlen(maxfunc))==0
670 && expression[strlen(expression)-1]==')' ) {
671 action = kMaxIf;
672 start = strlen(maxfunc);
673 }
674 if ( strncmp(expression,minfunc,strlen(minfunc))==0
675 && expression[strlen(expression)-1]==')' ) {
676 action = kMinIf;
677 start = strlen(minfunc);
678 }
679
680 if (action) {
681 TString full = expression;
684 int paran = 0;
685 int instr = 0;
686 int brack = 0;
687 for(unsigned int i=start;i<strlen(expression);++i) {
688 switch (expression[i]) {
689 case '(': paran++; break;
690 case ')': paran--; break;
691 case '"': instr = instr ? 0 : 1; break;
692 case '[': brack++; break;
693 case ']': brack--; break;
694 };
695 if (expression[i]==',' && paran==0 && instr==0 && brack==0) {
696 part1 = full( start, i-start );
697 part2 = full( i+1, full.Length() -1 - (i+1) );
698 break; // out of the for loop
699 }
700 }
701 if (part1.Length() && part2.Length()) {
702 TTreeFormula *primary = new TTreeFormula("primary",part1,fTree);
703 TTreeFormula *alternate = new TTreeFormula("alternate",part2,fTree);
704
705 short isstring = 0;
706
707 if (action == kAlternate) {
708 if (alternate->GetManager()->GetMultiplicity() != 0 ) {
709 Error("DefinedVariable","The 2nd arguments in %s can not be an array (%s,%d)!",
710 expression,alternate->GetTitle(),
711 alternate->GetManager()->GetMultiplicity());
712 return -1;
713 }
714
715 // Should check whether we have strings.
716 if (primary->IsString()) {
717 if (!alternate->IsString()) {
718 Error("DefinedVariable",
719 "The 2nd arguments in %s has to return the same type as the 1st argument (string)!",
720 expression);
721 return -1;
722 }
723 isstring = 1;
724 } else if (alternate->IsString()) {
725 Error("DefinedVariable",
726 "The 2nd arguments in %s has to return the same type as the 1st argument (numerical type)!",
727 expression);
728 return -1;
729 }
730 } else {
731 primary->GetManager()->Add( alternate );
732 primary->GetManager()->Sync();
733 if (primary->IsString() || alternate->IsString()) {
734 if (!alternate->IsString()) {
735 Error("DefinedVariable",
736 "The arguments of %s can not be strings!",
737 expression);
738 return -1;
739 }
740 }
741 }
742
744 fExpr[fNoper] = "";
746 ++fNoper;
747
749 return (Int_t)kAlias + isstring;
750 }
751 }
752 return 0;
753}
754
755////////////////////////////////////////////////////////////////////////////////
756/// Decompose 'expression' as pointing to something inside the leaf
757/// Returns:
758/// - -2 Error: some information is missing (message already printed)
759/// - -1 Error: Syntax is incorrect (message already printed)
760/// - 0
761/// - >0 the value returns is the action code.
762
764{
765 Int_t action = 0;
766
768 char *current;
769
770 char scratch[kMaxLen]; scratch[0] = '\0';
771 char work[kMaxLen]; work[0] = '\0';
772
773 const char *right = subExpression;
775
776 TBranch *branch = leaf ? leaf->GetBranch() : nullptr;
777 Long64_t readentry = fTree->GetTree()->GetReadEntry();
778 if (readentry < 0) readentry=0;
779
780 bool useLeafReferenceObject = false;
781 Int_t code = fNcodes-1;
782
783 // Make a check to prevent problem with some corrupted files (missing TStreamerInfo).
784 if (leaf && leaf->IsA()==TLeafElement::Class()) {
785 TBranchElement *br = nullptr;
786 if( branch->IsA() == TBranchElement::Class() )
787 {
789
790 if ( br->GetInfo() == nullptr ) {
791 Error("DefinedVariable","Missing StreamerInfo for %s. We will be unable to read!",
792 name.Data());
793 return -2;
794 }
795 }
796
797 TBranch *bmom = branch->GetMother();
798 if( bmom->IsA() == TBranchElement::Class() )
799 {
800 TBranchElement *mom = (TBranchElement*)br->GetMother();
801 if (mom!=br) {
802 if (mom->GetInfo()==nullptr) {
803 Error("DefinedVariable","Missing StreamerInfo for %s."
804 " We will be unable to read!",
805 mom->GetName());
806 return -2;
807 }
808 if ((mom->GetType()) < -1 && !mom->GetAddress()) {
809 Error("DefinedVariable", "Address not set when the type of the branch is negative for for %s. We will be unable to read!", mom->GetName());
810 return -2;
811 }
812 }
813 }
814 }
815
816 // We need to record the location in the list of leaves because
817 // the tree might actually be a chain and in that case the leaf will
818 // change from tree to tree!.
819
820 // Let's reconstruct the name of the leaf, including the possible friend alias
822 const char* alias = nullptr;
823 if (leaf) {
824 if (realtree) alias = realtree->GetFriendAlias(leaf->GetBranch()->GetTree());
825 if (!alias && realtree!=fTree) {
826 // Let's try on the chain
827 alias = fTree->GetFriendAlias(leaf->GetBranch()->GetTree());
828 }
829 }
831 if (alias) {
832 leafname_len = strlen(alias) + strlen(leaf->GetName()) + 1;
833 snprintf(scratch,kMaxLen-1,"%s.%s",alias,leaf->GetName()); // does not null-terminate if truncation happens
834 }
835 else if (leaf) {
836 leafname_len = strlen(leaf->GetName());
837 strlcpy(scratch,leaf->GetName(),kMaxLen); // null-terminates if truncation happens
838 }
839 if (leafname_len > kMaxLen - 1) {
840 Error("TTreeFormula",
841 "Length of leafname (%d) exceeds maximum allowed by the buffer (%d), formula will be truncated.",
842 leafname_len, kMaxLen - 1);
843 return -1;
844 }
845
846
848 if (leaf) {
849 tleaf = leaf->GetBranch()->GetTree();
850 fCodes[code] = tleaf->GetListOfLeaves()->IndexOf(leaf);
851 const char *mother_name = leaf->GetBranch()->GetMother()->GetName();
852 TString br_extended_name; // Could do ( strlen(mother_name)+strlen( leaf->GetBranch()->GetName() ) + 2 )
853 if (leaf->GetBranch()!=leaf->GetBranch()->GetMother()) {
854 if (mother_name[strlen(mother_name)-1]!='.') {
856 br_extended_name.Append('.');
857 }
858 }
859 br_extended_name.Append( leaf->GetBranch()->GetName() );
860 Ssiz_t dim = br_extended_name.First('[');
861 if (dim >= 0) br_extended_name.Remove(dim);
862
866 }
867
868 // If the leaf belongs to a friend tree which has an index, we might
869 // be in the case where some entry do not exist.
870 if (tleaf != realtree && tleaf->GetTreeIndex()) {
871 // reset the multiplicity
872 if (fMultiplicity >= 0) fMultiplicity = 1;
873 }
874
875 // Analyze the content of 'right'
876
877 // Try to find out the class (if any) of the object in the leaf.
878 TClass * cl = nullptr;
879 TFormLeafInfo *maininfo = nullptr;
880 TFormLeafInfo *previnfo = nullptr;
881 bool unwindCollection = false;
882 const static TClassRef stdStringClass = TClass::GetClass("string");
883
884 if (leaf==nullptr) {
885 TNamed *names = (TNamed*)fLeafNames.UncheckedAt(code);
886 fLeafNames.AddAt(nullptr,code);
888 fLeaves.AddAt(nullptr,code);
889
890 cl = what ? what->IsA() : TTree::Class();
893
894 delete names;
895 } else if (leaf->InheritsFrom(TLeafObject::Class()) ) {
896 TBranchObject *bobj = (TBranchObject*)leaf->GetBranch();
897 cl = TClass::GetClass(bobj->GetClassName());
898 } else if (leaf->InheritsFrom(TLeafElement::Class())) {
899 TBranchElement *branchEl = (TBranchElement *)leaf->GetBranch();
900 branchEl->SetupAddresses();
901 TStreamerInfo *info = branchEl->GetInfo();
902 TStreamerElement *element = nullptr;
903 Int_t type = branchEl->GetStreamerType();
904 switch(type) {
917 element = info->GetElement(branchEl->GetID());
918 if (element) cl = element->GetClassPointer();
919 }
920 break;
929 element = info->GetElement(branchEl->GetID());
930 if (element){
931 cl = element->GetClassPointer();
932 }
933 }
934 break;
935 case -1: {
936 cl = info->GetClass();
937 }
938 break;
939 }
940
941 // If we got a class object, we need to verify whether it is on a
942 // split TClonesArray sub branch.
943 if (cl && branchEl->GetBranchCount()) {
944 if (branchEl->GetType()==31) {
945 // This is inside a TClonesArray.
946
947 if (!element) {
948 Warning("DefinedVariable",
949 "Missing TStreamerElement in object in TClonesArray section");
950 return -2;
951 }
953
954 // The following code was commented out because in THIS case
955 // the dimension are actually handled by parsing the title and name of the leaf
956 // and branch (see a little further)
957 // The dimension needs to be handled!
958 // numberOfVarDim += RegisterDimensions(code,clonesinfo);
959
961
962 // We skip some cases because we can assume we have an object.
963 Int_t offset=0;
964 info->GetStreamerElement(element->GetName(),offset);
975 previnfo = new TFormLeafInfoPointer(cl,offset+branchEl->GetOffset(),element);
976 } else {
977 previnfo = new TFormLeafInfo(cl,offset+branchEl->GetOffset(),element);
978 }
979 maininfo->fNext = previnfo;
980 unwindCollection = true;
981
982 } else if (branchEl->GetType()==41) {
983
984 // This is inside a Collection
985
986 if (!element) {
987 Warning("DefinedVariable","Missing TStreamerElement in object in Collection section");
988 return -2;
989 }
990 // First we need to recover the collection.
991 TBranchElement *count = branchEl->GetBranchCount();
993 if ( count->GetID() >= 0 ) {
995 count->GetInfo()->GetElement(count->GetID());
996 TClass *collectionCl = collectionElement->GetClassPointer();
997
1000 } else {
1004 }
1005
1006 // The following code was commented out because in THIS case
1007 // the dimension are actually handled by parsing the title and name of the leaf
1008 // and branch (see a little further)
1009 // The dimension needs to be handled!
1010 // numberOfVarDim += RegisterDimensions(code,clonesinfo);
1011
1013
1014 // We skip some cases because we can assume we have an object.
1015 Int_t offset=0;
1016 info->GetStreamerElement(element->GetName(),offset);
1027 previnfo = new TFormLeafInfoPointer(cl,offset+branchEl->GetOffset(),element);
1028 } else {
1029 previnfo = new TFormLeafInfo(cl,offset+branchEl->GetOffset(),element);
1030 }
1031 maininfo->fNext = previnfo;
1032 unwindCollection = true;
1033 }
1034 } else if ( branchEl->GetType()==3) {
1038 } else {
1039 clonesinfo = new TFormLeafInfoClones(cl, 0, true);
1040 // The dimension needs to be handled!
1042
1043 }
1046
1047 } else if (!useLeafCollectionObject && branchEl->GetType()==4) {
1048
1052 } else {
1053 collectioninfo = new TFormLeafInfoCollection(cl, 0, cl, true);
1054 // The dimension needs to be handled!
1056 }
1057
1060
1061 } else if (branchEl->GetStreamerType()==-1 && cl && cl->GetCollectionProxy()) {
1062
1064
1068
1069 } else {
1071 // The dimension needs to be handled!
1073
1076
1077 if (cl->GetCollectionProxy()->GetValueClass()!=nullptr &&
1078 cl->GetCollectionProxy()->GetValueClass()->GetCollectionProxy()!=nullptr) {
1079
1082
1083 fHasMultipleVarDim[code] = true;
1085 previnfo->fNext = multi;
1086 cl = cl->GetCollectionProxy()->GetValueClass();
1087 multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false);
1088 previnfo = multi->fNext;
1089
1090 }
1091 if (cl->GetCollectionProxy()->GetValueClass()==nullptr &&
1092 cl->GetCollectionProxy()->GetType()>0) {
1093
1094 previnfo->fNext =
1096 previnfo = previnfo->fNext;
1097 } else {
1098 // nothing to do
1099 }
1100 }
1101
1102 } else if (strlen(right)==0 && cl && element && final) {
1103
1104 TClass *elemCl = element->GetClassPointer();
1106 && elemCl && elemCl->GetCollectionProxy()
1107 && elemCl->GetCollectionProxy()->GetValueClass()
1108 && elemCl->GetCollectionProxy()->GetValueClass()->GetCollectionProxy()) {
1109
1111 new TFormLeafInfoCollection(cl, 0, elemCl);
1112
1113 // The dimension needs to be handled!
1115
1118
1121 elemCl->GetCollectionProxy()->GetValueClass(),
1123
1124 fHasMultipleVarDim[code] = true;
1126 previnfo->fNext = multi;
1127 cl = elemCl->GetCollectionProxy()->GetValueClass();
1128 multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false);
1129 previnfo = multi->fNext;
1130
1131 if (cl->GetCollectionProxy()->GetValueClass()==nullptr &&
1132 cl->GetCollectionProxy()->GetType()>0) {
1133
1134 previnfo->fNext =
1136 previnfo = previnfo->fNext;
1137 }
1138
1139 } else if (!useLeafCollectionObject
1140 && elemCl && elemCl->GetCollectionProxy()
1141 && elemCl->GetCollectionProxy()->GetValueClass()==nullptr
1142 && elemCl->GetCollectionProxy()->GetType()>0) {
1143
1144 // At this point we have an element which is inside a class (which is not
1145 // a collection) and this element of a collection of numerical type.
1146 // (Note: it is not possible to have more than one variable dimension
1147 // unless we were supporting variable size C-style array of collection).
1148
1150 new TFormLeafInfoCollection(cl, 0, elemCl);
1151
1152 // The dimension needs to be handled!
1154
1155 collectioninfo->fNext =
1156 new TFormLeafInfoNumerical(elemCl->GetCollectionProxy());
1157
1159 previnfo = maininfo->fNext;
1160
1161 } else if (!useLeafCollectionObject
1162 && elemCl && elemCl->GetCollectionProxy()) {
1163 if (elemCl->GetCollectionProxy()->GetValueClass()==TString::Class()) {
1164 right = "Data()";
1165 } else if (elemCl->GetCollectionProxy()->GetValueClass()==stdStringClass) {
1166 right = "c_str()";
1167 }
1168
1169 } else if (!element->IsaPointer()) {
1170
1173
1174 }
1175 }
1176 else if ( cl && cl->GetReferenceProxy() ) {
1177 if ( useLeafCollectionObject || fullExpression[0] == '@' || fullExpression[strlen(scratch)] == '@' ) {
1179 }
1180 else {
1181 if ( !maininfo ) {
1184 }
1186 for(Long64_t i=0; i<leaf->GetBranch()->GetEntries()-readentry; ++i) {
1187 R__LoadBranch(leaf->GetBranch(), readentry+i, fQuickLoad);
1188 void *refobj = maininfo->GetValuePointer(leaf,0);
1189 if (refobj) {
1190 cl = refproxy->GetValueClass(refobj);
1191 }
1192 if ( cl ) break;
1193 }
1194 if ( !cl ) {
1195 Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
1196 return -1;
1197 }
1198 }
1199 }
1200 } else {
1201 // Regular/old TLeaf, there should not be anything afterward ...
1202 if (subExpression && subExpression[0]) {
1203 Error("ParseWithLeaf", "Found a numerical leaf but the name has trailing characters: \"%s\"", subExpression);
1204 return -1;
1205 }
1206 }
1207
1208 // Treat the dimension information in the leaf name, title and 2nd branch count
1210
1211 if (cl) {
1212 if (unwindCollection) {
1213 // So far we should get here only if we encounter a split collection of a class that contains
1214 // directly a collection.
1216
1217 if (!useLeafCollectionObject && cl && cl->GetCollectionProxy()) {
1220 fHasMultipleVarDim[code] = true;
1222 previnfo->fNext = multi;
1223
1224 multi->fNext = new TFormLeafInfoCollection(cl, 0, cl, false);
1225 previnfo = multi->fNext;
1226
1227 if (cl->GetCollectionProxy()->GetValueClass()==nullptr &&
1228 cl->GetCollectionProxy()->GetType()>0) {
1229
1230 previnfo->fNext =
1232 previnfo = previnfo->fNext;
1233 }
1234 } else if (!useLeafCollectionObject && cl == TClonesArray::Class()) {
1235
1238 fHasMultipleVarDim[code] = true;
1240 previnfo->fNext = multi;
1241
1242 multi->fNext = new TFormLeafInfoClones(cl, 0, false);
1243 previnfo = multi->fNext;
1244 }
1245 }
1246 Int_t offset=0;
1247 if (cl == TString::Class() && strcmp(right,"fData")==0) {
1248 // For backward compatibility replace TString::fData which no longer exist
1249 // by a call to TString::Data()
1250 right = "Data()";
1251 }
1252 Int_t nchname = strlen(right);
1253 TFormLeafInfo *leafinfo = nullptr;
1254 TStreamerElement* element = nullptr;
1255
1256 // Let see if the leaf was attempted to be casted.
1257 // Since there would have been something like
1258 // ((cast_class*)leafname)->.... we need to use
1259 // paran_level+1
1260 // Also we disable this functionality in case of TClonesArray
1261 // because it is not yet allowed to have 'inheritance' (or virtuality)
1262 // in play in a TClonesArray.
1263 {
1265 if (casted && cl != TClonesArray::Class()) {
1266 if ( ! casted->InheritsFrom(cl) ) {
1267 Error("DefinedVariable","%s does not inherit from %s. Casting not possible!",
1268 casted->GetName(),cl->GetName());
1269 return -2;
1270 }
1272 fHasCast = true;
1273 if (maininfo==nullptr) {
1275 }
1276 if (previnfo==nullptr) {
1278 } else {
1279 previnfo->fNext = leafinfo;
1281 }
1282 leafinfo = nullptr;
1283
1284 cl = casted;
1285 castqueue.AddAt(nullptr,paran_level);
1286 }
1287 }
1288 Int_t i;
1293 for (i=0, current = &(work[0]); i<=nchname;i++ ) {
1294 // We will treated the terminator as a token.
1295 if (right[i] == '(') {
1296 // Right now we do not allow nested parenthesis
1297 do {
1298 *current++ = right[i++];
1299 } while(right[i]!=')' && right[i]);
1300 *current++ = right[i];
1301 *current='\0';
1302 char *params = strchr(work,'(');
1303 if (params) {
1304 *params = 0; params++;
1305 } else params = (char *) ")";
1306 if (cl==nullptr) {
1307 Error("DefinedVariable","Can not call '%s' with a class",work);
1308 return -1;
1309 }
1310 if (!cl->HasDataMemberInfo() && !cl->GetCollectionProxy()) {
1311 Error("DefinedVariable","Class probably unavailable:%s",cl->GetName());
1312 return -2;
1313 }
1314 if (!useCollectionObject && cl == TClonesArray::Class()) {
1315 // We are not interested in the ClonesArray object but only
1316 // in its contents.
1317 // We need to retrieve the class of its content.
1318
1319 TBranch *clbranch = leaf->GetBranch();
1322 if (previnfo) clones = (TClonesArray*)previnfo->GetLocalValuePointer(leaf,0);
1323 else {
1324 bool top = (clbranch==((TBranchElement*)clbranch)->GetMother()
1325 || !leaf->IsOnTerminalBranch());
1327 if (leaf->IsA()==TLeafObject::Class()) {
1328 // in this case mother_cl is not really used
1329 mother_cl = cl;
1330 } else {
1331 mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
1332 }
1334
1335 // The dimension needs to be handled!
1337
1340
1341 clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
1342 }
1343 TClass * inside_cl = clones ? clones->GetClass() : nullptr;
1344 cl = inside_cl;
1345
1346 }
1347 else if (!useCollectionObject && cl && cl->GetCollectionProxy() ) {
1348
1349 // We are NEVER (for now!) interested in the ClonesArray object but only
1350 // in its contents.
1351 // We need to retrieve the class of its content.
1352
1353 if (previnfo==nullptr) {
1354
1355 bool top = (branch==((TBranchElement*)branch)->GetMother()
1356 || !leaf->IsOnTerminalBranch());
1357
1359 if (leaf->IsA()==TLeafObject::Class()) {
1360 // in this case mother_cl is not really used
1361 mother_cl = cl;
1362 } else {
1363 mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
1364 }
1365
1367 new TFormLeafInfoCollection(mother_cl, 0,cl,top);
1368 // The dimension needs to be handled!
1370
1373
1374 }
1375
1377 if (inside_cl) cl = inside_cl;
1378 else if (cl->GetCollectionProxy()->GetType()>0) {
1379 Warning("DefinedVariable","Can not call method on content of %s in %s\n",
1380 cl->GetName(),name.Data());
1381 return -2;
1382 }
1383 }
1384 TMethodCall *method = nullptr;
1385 if (cl==nullptr) {
1386 Error("DefinedVariable",
1387 "Could not discover the TClass corresponding to (%s)!",
1388 right);
1389 return -2;
1390 } else if (cl==TClonesArray::Class() && strcmp(work,"size")==0) {
1391 method = new TMethodCall(cl, "GetEntriesFast", "");
1392 } else if (cl->GetCollectionProxy() && strcmp(work,"size")==0) {
1393 if (maininfo==nullptr) {
1396
1397 bool top = (branch==((TBranchElement*)branch)->GetMother()
1398 || !leaf->IsOnTerminalBranch());
1400 }
1402 }
1404 cl = nullptr;
1405 } else {
1406 if (!cl->HasDataMemberInfo()) {
1407 Error("DefinedVariable",
1408 "Can not call method %s on class without dictionary (%s)!",
1409 right,cl->GetName());
1410 return -2;
1411 }
1412 method = new TMethodCall(cl, work, params);
1413 }
1414 if (method) {
1415 if (!method->GetMethod()) {
1416 Error("DefinedVariable","Unknown method:%s in %s",right,cl->GetName());
1417 return -1;
1418 }
1419 switch(method->ReturnType()) {
1420 case TMethodCall::kLong:
1422 cl = nullptr;
1423 break;
1426 cl = nullptr;
1427 break;
1430 // 1 will be replaced by -1 when we know how to use strlen
1431 numberOfVarDim += RegisterDimensions(code,1); //NOTE: changed from 0
1432 cl = nullptr;
1433 break;
1435 {
1438 }
1439 break;
1440 default:
1441 Error("DefineVariable","Method %s from %s has an impossible return type %d",
1442 work,cl->GetName(), (Int_t)method->ReturnType());
1443 return -2;
1444 }
1445 }
1446 if (maininfo==nullptr) {
1448 }
1449 if (previnfo==nullptr) {
1451 } else {
1452 previnfo->fNext = leafinfo;
1454 }
1455 leafinfo = nullptr;
1456 current = &(work[0]);
1457 *current = 0;
1459 prevUseReferenceObject = false;
1460 useCollectionObject = false;
1461
1462 if (cl && cl->GetCollectionProxy()) {
1463 if (numberOfVarDim>1) {
1464 Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections. Assuming '@' notation for the collection %s.",
1465 cl->GetName());
1466 leafinfo = new TFormLeafInfo(cl,0,nullptr);
1467 useCollectionObject = true;
1468 } else if (numberOfVarDim==0) {
1470 leafinfo = new TFormLeafInfoCollection(cl,0,cl);
1472 } else if (numberOfVarDim==1) {
1474 leafinfo =
1476 (TStreamerElement*)nullptr,maininfo);
1477 previnfo->fNext = leafinfo;
1479 leafinfo = new TFormLeafInfoCollection(cl,0,cl);
1480
1481 fHasMultipleVarDim[code] = true;
1483 }
1484 previnfo->fNext = leafinfo;
1486 leafinfo = nullptr;
1487 }
1488 continue;
1489 } else if (right[i] == ')') {
1490 // We should have the end of a cast operator. Let's introduce a TFormLeafCast
1491 // in the chain.
1492 TClass * casted = (TClass*) ((int(--paran_level)>=0) ? castqueue.At(paran_level) : nullptr);
1493 if (casted) {
1495 fHasCast = true;
1496
1497 if (maininfo==nullptr) {
1499 }
1500 if (previnfo==nullptr) {
1502 } else {
1503 previnfo->fNext = leafinfo;
1505 }
1506 leafinfo = nullptr;
1507 current = &(work[0]);
1508 *current = 0;
1509
1510 cl = casted;
1511 continue;
1512
1513 }
1514 } else if (i > 0 && (right[i] == '.' || right[i] == '[' || right[i] == '\0') ) {
1515 // A delimiter happened let's see if what we have seen
1516 // so far does point to a data member.
1517 bool needClass = true;
1518 *current = '\0';
1519
1520 // skip it all if there is nothing to look at
1521 if (strlen(work)==0) continue;
1522
1525 if (work[0]=='@') {
1526 useReferenceObject = true;
1527 useCollectionObject = true;
1528 Int_t l = 0;
1529 for(l=0;work[l+1]!=0;++l) work[l] = work[l+1];
1530 work[l] = '\0';
1531 } else if (work[strlen(work)-1]=='@') {
1532 useReferenceObject = true;
1533 useCollectionObject = true;
1534 work[strlen(work)-1] = '\0';
1535 } else {
1536 useReferenceObject = false;
1537 useCollectionObject = false;
1538 }
1539
1540 bool mustderef = false;
1541 if ( !prevUseReferenceObject && cl && cl->GetReferenceProxy() ) {
1542 R__LoadBranch(leaf->GetBranch(), readentry, fQuickLoad);
1543 if ( !maininfo ) {
1545 if ( cl->GetReferenceProxy()->HasCounter() ) {
1547 }
1548 prevUseReferenceObject = false;
1549 } else {
1550 previnfo->fNext = new TFormLeafInfoReference(cl, element, offset);
1551 previnfo = previnfo->fNext;
1552 }
1554 cl = nullptr;
1555 for(Long64_t entry=0; entry<leaf->GetBranch()->GetEntries()-readentry; ++entry) {
1556 R__LoadBranch(leaf->GetBranch(), readentry+i, fQuickLoad);
1557 void *refobj = maininfo->GetValuePointer(leaf,0);
1558 if (refobj) {
1559 cl = refproxy->GetValueClass(refobj);
1560 }
1561 if ( cl ) break;
1562 }
1563 needClass = false;
1564 mustderef = true;
1565 }
1566 else if (!prevUseCollectionObject && cl == TClonesArray::Class()) {
1567 // We are not interested in the ClonesArray object but only
1568 // in its contents.
1569 // We need to retrieve the class of its content.
1570
1571 TBranch *clbranch = leaf->GetBranch();
1574 if (maininfo) {
1575 clones = (TClonesArray*)maininfo->GetValuePointer(leaf,0);
1576 } else {
1577 // we have a unsplit TClonesArray leaves
1578 // or we did not yet match any of the sub-branches!
1579
1581 if (leaf->IsA()==TLeafObject::Class()) {
1582 // in this case mother_cl is not really used
1583 mother_cl = cl;
1584 } else {
1585 mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
1586 }
1587
1589 // The dimension needs to be handled!
1591
1592 mustderef = true;
1595
1596 if (clbranch->GetListOfBranches()->GetLast()>=0) {
1597 if (clbranch->IsA() != TBranchElement::Class()) {
1598 Error("DefinedVariable","Unimplemented usage of ClonesArray");
1599 return -2;
1600 }
1601 //clbranch = ((TBranchElement*)clbranch)->GetMother();
1602 clones = (TClonesArray*)((TBranchElement*)clbranch)->GetObject();
1603 } else
1604 clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
1605 }
1606 // NOTE clones can be zero!
1607 if (clones==nullptr) {
1608 Warning("DefinedVariable",
1609 "TClonesArray object was not retrievable for %s!",
1610 name.Data());
1611 return -1;
1612 }
1613 TClass * inside_cl = clones->GetClass();
1614#if 1
1615 cl = inside_cl;
1616#else
1617/* Maybe we should make those test lead to warning messages */
1618 if (1 || inside_cl) cl = inside_cl;
1619 // if inside_cl is nul ... we have a problem of inconsistency :(
1620 if (0 && strlen(work)==0) {
1621 // However in this case we have NO content :(
1622 // so let get the number of objects
1623 //strcpy(work,"fLast");
1624 }
1625#endif
1626 } else if (!prevUseCollectionObject && cl && cl->GetCollectionProxy() ) {
1627
1628 // We are NEVER interested in the Collection object but only
1629 // in its contents.
1630 // We need to retrieve the class of its content.
1631
1632 TBranch *clbranch = leaf->GetBranch();
1634
1635 if (maininfo==nullptr) {
1636
1637 // we have a unsplit Collection leaf
1638 // or we did not yet match any of the sub-branches!
1639
1641 if (leaf->IsA()==TLeafObject::Class()) {
1642 // in this case mother_cl is not really used
1643 mother_cl = cl;
1644 } else {
1645 mother_cl = ((TBranchElement*)clbranch)->GetInfo()->GetClass();
1646 }
1647
1650 // The dimension needs to be handled!
1652
1653 mustderef = true;
1656
1657 } //else if (clbranch->GetStreamerType()==0) {
1658
1659 //}
1660
1662
1663 if (!inside_cl) {
1664 Error("DefinedVariable","Could you not find the inner class for %s with coll type = %d",
1665 cl->GetName(),cl->GetCollectionProxy()->GetType());
1666 }
1667 if (!inside_cl && cl->GetCollectionProxy()->GetType() > 0) {
1668 Warning("DefinedVariable","No data member in content of %s in %s\n",
1669 cl->GetName(),name.Data());
1670 }
1671 cl = inside_cl;
1672 // if inside_cl is nul ... we have a problem of inconsistency.
1673 }
1674
1675 if (!cl) {
1676 if (leaf) leaf->GetBranch()->Print();
1677 Warning("DefinedVariable","Missing class for %s!",name.Data());
1678 } else {
1679 element = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1680 }
1681
1683 // We allow for looking for a data member inside a class inside
1684 // a TClonesArray without mentioning the TClonesArrays variable name
1685 TIter next( cl->GetStreamerInfo()->GetElements() );
1687 while ((curelem = (TStreamerElement*)next())) {
1688 if (curelem->GetClassPointer() == TClonesArray::Class()) {
1689 Int_t clones_offset = 0;
1690 ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),clones_offset);
1694 R__LoadBranch(leaf->GetBranch(),readentry,fQuickLoad);
1695
1696 if (previnfo) {
1697 previnfo->fNext = clonesinfo;
1698 clones = (TClonesArray*)maininfo->GetValuePointer(leaf,0);
1699 previnfo->fNext = nullptr;
1700 } else {
1701 clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leaf,0);
1702 }
1703
1704 TClass *sub_cl = clones->GetClass();
1705 if (sub_cl) element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1706 delete clonesinfo;
1707
1708 if (element) {
1711 if (maininfo==nullptr) maininfo = leafinfo;
1712 if (previnfo==nullptr) previnfo = leafinfo;
1713 else {
1714 previnfo->fNext = leafinfo;
1716 }
1717 leafinfo = nullptr;
1718 cl = sub_cl;
1719 break;
1720 }
1721 } else if (curelem->GetClassPointer() && curelem->GetClassPointer()->GetCollectionProxy()) {
1722
1723 Int_t coll_offset = 0;
1724 ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),coll_offset);
1725
1726 TClass *sub_cl =
1727 curelem->GetClassPointer()->GetCollectionProxy()->GetValueClass();
1728 if (sub_cl) {
1729 element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1730 }
1731 if (element) {
1732 if (numberOfVarDim>1) {
1733 Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections. Assuming '@' notation for the collection %s.",
1734 curelem->GetName());
1736 useCollectionObject = true;
1737 } else if (numberOfVarDim==1) {
1739 leafinfo =
1742 fHasMultipleVarDim[code] = true;
1745 } else {
1748 }
1749 if (maininfo==nullptr) maininfo = leafinfo;
1750 if (previnfo==nullptr) previnfo = leafinfo;
1751 else {
1752 previnfo->fNext = leafinfo;
1754 }
1755 if (leafinfo->fNext) {
1756 previnfo = leafinfo->fNext;
1757 }
1758 leafinfo = nullptr;
1759 cl = sub_cl;
1760 break;
1761 }
1762 }
1763 }
1764
1765 }
1766
1767 if (element) {
1768 Int_t type = element->GetNewType();
1769 if (type<60 && type!=0) {
1770 // This is a basic type ...
1771 if (numberOfVarDim>=1 && type>40) {
1772 // We have a variable array within a variable array!
1774 fHasMultipleVarDim[code] = true;
1775 } else {
1776 if (leafinfo && type<=40 ) {
1777 leafinfo->AddOffset(offset,element);
1778 } else {
1780 }
1781 }
1782 } else {
1783 bool object = false;
1784 bool pointer = false;
1785 bool objarr = false;
1786 switch(type) {
1797 pointer = true;
1798 break;
1800 case TStreamerInfo::kAny :
1806 object = true;
1807 break;
1811 objarr = true;
1812 break;
1815 // Unsupported case.
1816 Error("DefinedVariable",
1817 "%s is a datamember of %s BUT is not yet of a supported type (%d)",
1818 right,cl ? cl->GetName() : "unknown class",type);
1819 return -2;
1820 default:
1821 // Unknown and Unsupported case.
1822 Error("DefinedVariable",
1823 "%s is a datamember of %s BUT is not of a unknown type (%d)",
1824 right,cl ? cl->GetName() : "unknown class",type);
1825 return -2;
1826 }
1827
1828 if (object && !useCollectionObject &&
1829 ( element->GetClassPointer() == TClonesArray::Class()
1830 || element->GetClassPointer()->GetCollectionProxy() ) )
1831 {
1832 object = false;
1833 }
1834 if (object && leafinfo) {
1835 leafinfo->AddOffset(offset,element);
1836 } else if (objarr) {
1837 // This is an embedded array of objects. We can not increase the offset.
1839 mustderef = true;
1840 } else {
1841
1842 if (!useCollectionObject && element->GetClassPointer() == TClonesArray::Class()) {
1843
1845 mustderef = true;
1846
1847 } else if (!useCollectionObject && element->GetClassPointer()
1848 && element->GetClassPointer()->GetCollectionProxy()) {
1849
1850 mustderef = true;
1851 if (numberOfVarDim>1) {
1852 Warning("DefinedVariable","TTreeFormula support only 2 level of variables size collections. Assuming '@' notation for the collection %s.",
1853 element->GetName());
1855 useCollectionObject = true;
1856 } else if (numberOfVarDim==1) {
1858 leafinfo =
1860
1861 fHasMultipleVarDim[code] = true;
1862 //numberOfVarDim += RegisterDimensions(code,leafinfo);
1863 //cl = cl->GetCollectionProxy()->GetValueClass();
1864
1865 //if (maininfo==0) maininfo = leafinfo;
1866 //if (previnfo==0) previnfo = leafinfo;
1867 //else {
1868 // previnfo->fNext = leafinfo;
1869 // previnfo = leafinfo;
1870 //}
1872 if (element->GetClassPointer()->GetCollectionProxy()->GetValueClass()==nullptr) {
1874 element->GetClassPointer()->GetCollectionProxy());
1875 if (leafinfo->fNext) leafinfo->fNext->fNext = info;
1876 else leafinfo->fNext = info;
1877 }
1878 } else {
1880
1881 TClass *elemCl = element->GetClassPointer();
1882 TClass *valueCl = elemCl->GetCollectionProxy()->GetValueClass();
1883 if (!maininfo) maininfo = leafinfo;
1884
1885 if (valueCl!=nullptr && valueCl->GetCollectionProxy()!=nullptr) {
1886
1888 if (previnfo==nullptr) previnfo = leafinfo;
1889 else {
1890 previnfo->fNext = leafinfo;
1892 }
1894 elemCl->GetCollectionProxy()->GetValueClass(),maininfo);
1895 //numberOfVarDim += RegisterDimensions(code,previnfo->fNext);
1896 fHasMultipleVarDim[code] = true;
1897 //previnfo = previnfo->fNext;
1899 valueCl);
1900 elemCl = valueCl;
1901 }
1902 if (elemCl->GetCollectionProxy() &&
1903 elemCl->GetCollectionProxy()->GetValueClass()==nullptr) {
1904 TFormLeafInfo *info = new TFormLeafInfoNumerical(elemCl->GetCollectionProxy());
1905 if (leafinfo->fNext) leafinfo->fNext->fNext = info;
1906 else leafinfo->fNext = info;
1907 }
1908 }
1909 } else if ( (object || pointer) && !useReferenceObject && element->GetClassPointer()->GetReferenceProxy() ) {
1910 TClass* c = element->GetClassPointer();
1911 R__LoadBranch(leaf->GetBranch(),readentry,fQuickLoad);
1912 if ( object ) {
1914 }
1915 else {
1917 leafinfo->fNext = new TFormLeafInfoReference(c, element, 0);
1918 }
1919 //if ( c->GetReferenceProxy()->HasCounter() ) {
1920 // numberOfVarDim += RegisterDimensions(code,-1);
1921 //}
1922 prevUseReferenceObject = false;
1923 needClass = false;
1924 mustderef = true;
1925 } else if (pointer) {
1926 // this is a pointer to be followed.
1928 mustderef = true;
1929 } else {
1930 // this is an embedded object.
1931 R__ASSERT(object);
1933 }
1934 }
1935 }
1936 } else {
1937 if (cl) Error("DefinedVariable","%s is not a datamember of %s",work,cl->GetName());
1938 // no else, we warned earlier that the class was missing.
1939 return -1;
1940 }
1941
1942 numberOfVarDim += RegisterDimensions(code,leafinfo,maininfo,useCollectionObject); // Note or useCollectionObject||prevUseColectionObject
1943 if (maininfo==nullptr) {
1945 }
1946 if (previnfo==nullptr) {
1948 } else if (previnfo!=leafinfo) {
1949 previnfo->fNext = leafinfo;
1951 }
1952 while (previnfo->fNext) previnfo = previnfo->fNext;
1953
1954 if ( right[i] != '\0' ) {
1955 if ( !needClass && mustderef ) {
1956 maininfo->SetBranch(leaf->GetBranch());
1957 char *ptr = (char*)maininfo->GetValuePointer(leaf,0);
1959 if ( !maininfo->IsReference() ) {
1960 for( TFormLeafInfo* inf = maininfo->fNext; inf; inf = inf->fNext ) {
1961 if ( inf->IsReference() ) {
1963 }
1964 }
1965 }
1966 else {
1968 }
1969 if ( refInfo ) {
1970 cl = refInfo->GetValueClass(ptr);
1971 if ( !cl ) {
1972 Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
1973 return -1;
1974 }
1975 element = ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(work,offset);
1976 }
1977 else {
1978 Error("DefinedVariable","Failed to access class type of reference target (%s)",element->GetName());
1979 return -1;
1980 }
1981 }
1982 else if ( needClass ) {
1983 cl = element->GetClassPointer();
1984 }
1985 }
1986 if (mustderef) leafinfo = nullptr;
1987 current = &(work[0]);
1988 *current = 0;
1989 R__ASSERT(right[i] != '['); // We are supposed to have removed all dimensions already!
1990
1991 if (cl == TString::Class() && strcmp(right+i+1,"fData") == 0) {
1992 // For backward compatibility replace TString::fData which no longer exist
1993 // by a call to TString::Data()
1994 right = ".Data()";
1995 i = 0;
1996 nchname = strlen(right);
1997 }
1998
1999 } else
2000 *current++ = right[i];
2001 }
2002 if (maininfo) {
2004 if (leaf) fLookupType[code] = kDataMember;
2005 else fLookupType[code] = kTreeMember;
2006 }
2007 }
2008
2009 if (strlen(work)!=0) {
2010 // We have something left to analyze. Let's make this an error case!
2011 return -1;
2012 }
2013
2014 TClass *objClass = EvalClass(code);
2015 if (objClass && !useLeafCollectionObject && objClass->GetCollectionProxy() && objClass->GetCollectionProxy()->GetValueClass()) {
2016 TFormLeafInfo *last = nullptr;
2017 if ( SwitchToFormLeafInfo(code) ) {
2018
2019 last = (TFormLeafInfo*)fDataMembers.At(code);
2020
2021 if (!last) return action;
2022 while (last->fNext) { last = last->fNext; }
2023
2024 }
2025 if (last && last->GetClass() != objClass) {
2027 if (leaf->IsA()==TLeafObject::Class()) {
2028 // in this case mother_cl is not really used
2029 mother_cl = cl;
2030 } else {
2031 mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
2032 }
2033
2035 // The dimension needs to be handled!
2037 last->fNext = collectioninfo;
2038 }
2039 numberOfVarDim += RegisterDimensions(code,1); //NOTE: changed from 0
2040 objClass = objClass->GetCollectionProxy()->GetValueClass();
2041 }
2043
2044 TFormLeafInfo *last = nullptr;
2045 if ( SwitchToFormLeafInfo(code) ) {
2046
2047 last = (TFormLeafInfo*)fDataMembers.At(code);
2048
2049 if (!last) return action;
2050 while (last->fNext) { last = last->fNext; }
2051
2052 }
2053 const char *funcname = nullptr;
2054 if (objClass == TString::Class()) {
2055 funcname = "Data";
2056 //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
2057 } else if (objClass == stdStringClass) {
2058 funcname = "c_str";
2059 //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
2060 }
2061 if (funcname) {
2063 if (last) {
2065 } else {
2067 if (leaf) fLookupType[code] = kDataMember;
2068 else fLookupType[code] = kTreeMember;
2069 }
2070 }
2071 return kDefinedString;
2072 }
2073
2074 if (objClass) {
2075 TMethodCall *method = new TMethodCall(objClass, "AsDouble", "");
2076 if (method->IsValid()
2077 && (method->ReturnType() == TMethodCall::kLong || method->ReturnType() == TMethodCall::kDouble)) {
2078
2079 TFormLeafInfo *last = nullptr;
2080 if (SwitchToFormLeafInfo(code)) {
2081 last = (TFormLeafInfo*)fDataMembers.At(code);
2082 // Improbable case
2083 if (!last) {
2084 delete method;
2085 return action;
2086 }
2087 while (last->fNext) { last = last->fNext; }
2088 }
2089 if (last) {
2091 } else {
2093 if (leaf) fLookupType[code] = kDataMember;
2094 else fLookupType[code] = kTreeMember;
2095 }
2096
2097 return kDefinedVariable;
2098 }
2099 delete method;
2100 method = new TMethodCall(objClass, "AsString", "");
2101 if (method->IsValid()
2102 && method->ReturnType() == TMethodCall::kString) {
2103
2104 TFormLeafInfo *last = nullptr;
2105 if (SwitchToFormLeafInfo(code)) {
2106 last = (TFormLeafInfo*)fDataMembers.At(code);
2107 // Improbable case
2108 if (!last) {
2109 delete method;
2110 return action;
2111 }
2112 while (last->fNext) { last = last->fNext; }
2113 }
2114 if (last) {
2116 } else {
2118 if (leaf) fLookupType[code] = kDataMember;
2119 else fLookupType[code] = kTreeMember;
2120 }
2121
2122 //tobetested: numberOfVarDim += RegisterDimensions(code,1,0); // Register the dim of the implied char*
2123 return kDefinedString;
2124 }
2125 if (method->IsValid()
2126 && method->ReturnType() == TMethodCall::kOther) {
2127
2129 if ((rcl == TString::Class() || rcl == stdStringClass) ) {
2130
2131 TFormLeafInfo *last = nullptr;
2132 if (SwitchToFormLeafInfo(code)) {
2133 last = (TFormLeafInfo*)fDataMembers.At(code);
2134 // Improbable case
2135 if (!last) {
2136 delete method;
2137 return action;
2138 }
2139 while (last->fNext) { last = last->fNext; }
2140 }
2141 if (last) {
2143 last = last->fNext;
2144 } else {
2146 fDataMembers.AddAtAndExpand(last,code);
2147 if (leaf) fLookupType[code] = kDataMember;
2148 else fLookupType[code] = kTreeMember;
2149 }
2150
2151 objClass = rcl;
2152
2153 const char *funcname = nullptr;
2154 if (objClass == TString::Class()) {
2155 funcname = "Data";
2156 } else if (objClass == stdStringClass) {
2157 funcname = "c_str";
2158 }
2159 if (funcname) {
2160 method = new TMethodCall(objClass, funcname, "");
2162 }
2163 return kDefinedString;
2164 }
2165 }
2166 delete method;
2167 }
2168
2169 return action;
2170}
2171
2172////////////////////////////////////////////////////////////////////////////////
2173/// Look for the leaf corresponding to the start of expression.
2174/// It returns the corresponding leaf if any.
2175/// It also modify the following arguments:
2176///
2177/// - leftover: contain from expression that was not used to determine the leaf
2178/// - final:
2179/// * paran_level: number of un-matched open parenthesis
2180/// * cast_queue: list of cast to be done
2181/// * aliases: list of aliases used
2182/// - Return <0 in case of failure
2183///
2184/// - Return 0 if a leaf has been found
2185/// - Return 2 if info about the TTree itself has been requested.
2186
2187Int_t TTreeFormula::FindLeafForExpression(const char* expression, TLeaf*& leaf, TString& leftover, bool& final, UInt_t& paran_level, TObjArray& castqueue, std::vector<std::string>& aliasUsed, bool& useLeafCollectionObject, const char* fullExpression)
2188{
2189 // Later on we will need to read one entry, let's make sure
2190 // it is a real entry.
2191 if (fTree->GetTree()==nullptr) {
2192 fTree->LoadTree(0);
2193 if (fTree->GetTree()==nullptr) return -1;
2194 }
2195 Long64_t readentry = fTree->GetTree()->GetReadEntry();
2196 if (readentry < 0) readentry=0;
2197 const char *cname = expression;
2198 char first[kMaxLen]; first[0] = '\0';
2199 char second[kMaxLen*2]; second[0] = '\0';
2200 char right[kMaxLen*2]; right[0] = '\0';
2201 char work[kMaxLen]; work[0] = '\0';
2202 char left[kMaxLen]; left[0] = '\0';
2203 char scratch[kMaxLen*5];
2204 char scratch2[kMaxLen*5];
2205 std::string currentname;
2206 Int_t previousdot = 0;
2207 char *current;
2208 TLeaf *tmp_leaf=nullptr;
2209 TBranch *branch=nullptr, *tmp_branch=nullptr;
2211 Int_t i;
2212 bool foundAtSign = false;
2213 bool startWithParan = false;
2214
2215 for (i=0, current = &(work[0]); i<=nchname && !final;i++ ) {
2216 // We will treated the terminator as a token.
2217 *current++ = cname[i];
2218
2219 if (cname[i] == '(') {
2220 ++paran_level;
2221
2222 if (current==work+1) {
2223 // If the expression starts with a parenthesis, we are likely
2224 // to have a cast operator inside.
2225 startWithParan = true;
2226 current--;
2227 }
2228 continue;
2229 //i++;
2230 //while( cname[i]!=')' && cname[i] ) {
2231 // *current++ = cname[i++];
2232 //}
2233 //*current++ = cname[i];
2234 ////*current = 0;
2235 //continue;
2236 }
2237 if (cname[i] == ')') {
2238 if (paran_level==0) {
2239 Error("DefinedVariable","Unmatched parenthesis in %s",fullExpression);
2240 return -1;
2241 }
2242 paran_level--;
2243
2244 if (startWithParan) {
2245 startWithParan = false; // the next match wont be against the starting parenthesis.
2246
2247 // Let's see if work is a classname and thus we have a cast.
2248 *(--current) = 0;
2249 TString cast_name = gInterpreter->TypeName(work);
2251 if (cast_cl) {
2252 // We must have a cast
2253 castqueue.AddAtAndExpand(cast_cl,paran_level);
2254 current = &(work[0]);
2255 *current = 0;
2256 // Warning("DefinedVariable","Found cast to %s",cast_fullExpression);
2257 continue;
2258 } else if (gROOT->GetType(cast_name)) {
2259 // We reset work
2260 current = &(work[0]);
2261 *current = 0;
2262 Warning("DefinedVariable",
2263 "Casting to primary types like \"%s\" is not supported yet",cast_name.Data());
2264 continue;
2265 }
2266 *(current++)=')';
2267 }
2268
2269 *current='\0';
2270 char *params = strchr(work,'(');
2271 if (params) {
2272 *params = 0; params++;
2273
2274 if (branch && !leaf) {
2275 // We have a branch but not a leaf. We are likely to have found
2276 // the top of split branch.
2277 if (BranchHasMethod(nullptr, branch, work, params, readentry)) {
2278 //fprintf(stderr, "Does have a method %s for %s.\n", work, branch->GetName());
2279 }
2280 }
2281
2282 // What we have so far might be a member function of one of the
2283 // leaves that are not split (for example "GetNtrack" for the Event class).
2285 TLeaf* leafcur = nullptr;
2286 while (!leaf && (leafcur = (TLeaf*) next())) {
2287 TBranch* br = leafcur->GetBranch();
2288 bool yes = BranchHasMethod(leafcur, br, work, params, readentry);
2289 if (yes) {
2290 leaf = leafcur;
2291 //fprintf(stderr, "Does have a method %s for %s found in leafcur %s.\n", work, leafcur->GetBranch()->GetName(), leafcur->GetName());
2292 }
2293 }
2294 if (!leaf) {
2295 // Check for an alias.
2296 if (strlen(left) && left[strlen(left)-1]=='.') left[strlen(left)-1]=0;
2297 const char *aliasValue = fTree->GetAlias(left);
2298 if (aliasValue && strcspn(aliasValue,"+*/-%&!=<>|")==strlen(aliasValue)) {
2299 // First check whether we are using this alias recursively (this would
2300 // lead to an infinite recursion.
2301 if (find(aliasUsed.begin(),
2302 aliasUsed.end(),
2303 left) != aliasUsed.end()) {
2304 Error("DefinedVariable",
2305 "The substitution of the branch alias \"%s\" by \"%s\" in \"%s\" failed\n"\
2306 "\tbecause \"%s\" is used [recursively] in its own definition!",
2307 left,aliasValue,fullExpression,left);
2308 return -3;
2309 }
2310 aliasUsed.push_back(left);
2312 newExpression += (cname+strlen(left));
2315 if (res<0) {
2316 Error("DefinedVariable",
2317 "The substitution of the alias \"%s\" by \"%s\" failed.",left,aliasValue);
2318 return -3;
2319 }
2320 return res;
2321 }
2322
2323 // This is actually not really any error, we probably received something
2324 // like "abs(some_val)", let ROOT::v5::TFormula decompose it first.
2325 return -1;
2326 }
2327 // if (!leaf->InheritsFrom(TLeafObject::Class()) ) {
2328 // If the leaf that we found so far is not a TLeafObject then there is
2329 // nothing we would be able to do.
2330 // Error("DefinedVariable","Need a TLeafObject to call a function!");
2331 // return -1;
2332 //}
2333 // We need to recover the info not used.
2334 strlcpy(right,work,2*kMaxLen);
2335 strncat(right,"(",2*kMaxLen-1-strlen(right));
2336 strncat(right,params,2*kMaxLen-1-strlen(right));
2337 final = true;
2338
2339 // Record in 'i' what we consumed
2340 i += strlen(params);
2341
2342 // we reset work
2343 current = &(work[0]);
2344 *current = 0;
2345 break;
2346 }
2347 }
2348 if (cname[i] == '.' || cname[i] == '\0' || cname[i] == ')') {
2349 // A delimiter happened let's see if what we have seen
2350 // so far does point to a leaf.
2351 *current = '\0';
2352
2353 Int_t len = strlen(work);
2354 if (work[0]=='@') {
2355 foundAtSign = true;
2356 Int_t l = 0;
2357 for(l=0;work[l+1]!=0;++l) work[l] = work[l+1];
2358 work[l] = '\0';
2359 --current;
2360 } else if (len>=2 && work[len-2]=='@') {
2361 foundAtSign = true;
2362 work[len-2] = cname[i];
2363 work[len-1] = '\0';
2364 --current;
2365 } else {
2366 foundAtSign = false;
2367 }
2368
2369 if (left[0]==0) strlcpy(left,work,kMaxLen);
2370 if (!leaf && !branch) {
2371 // So far, we have not found a matching leaf or branch.
2372 strlcpy(first,work,kMaxLen);
2373
2374 std::string treename(first);
2375 if (!treename.empty() && treename[treename.size()-1]=='.') {
2376 treename.erase(treename.size()-1);
2377 }
2378 if (treename== "This" /* || treename == fTree->GetName() */ ) {
2379 // Request info about the TTree object itself,
2383 if (cname[i]) leftover = &(cname[i+1]);
2384 return 2;
2385 }
2386 // The following would allow to access the friend by name
2387 // however, it would also prevent the access of the leaves
2388 // within the friend. We could use the '@' notation here
2389 // however this would not be aesthetically pleasing :(
2390 // What we need to do, is add the ability to look ahead to
2391 // the next 'token' to decide whether we to access the tree
2392 // or its leaf.
2393 //} else {
2394 // TTree *tfriend = fTree->GetFriend(treename.c_str());
2395 // TTree *realtree = fTree->GetTree();
2396 // if (!tfriend && realtree != fTree){
2397 // // If it is a chain and we did not find a friend,
2398 // // let's try with the internal tree.
2399 // tfriend = realtree->GetFriend(treename.c_str());
2400 // }
2401 // if (tfriend) {
2402 // TNamed *named = new TNamed(treename.c_str(),tfriend->GetName());
2403 // fLeafNames.AddAtAndExpand(named,fNcodes);
2404 // fLeaves.AddAtAndExpand(tfriend,fNcodes);
2405 // if (cname[i]) leftover = &(cname[i+1]);
2406 // return 2;
2407 // }
2408 //}
2409
2410 branch = fTree->FindBranch(first);
2411 leaf = fTree->FindLeaf(first);
2412
2413 // Now look with the delimiter removed (we looked with it first
2414 // because a dot is allowed at the end of some branches).
2415 if (cname[i]) first[strlen(first)-1]='\0';
2416 if (!branch) branch = fTree->FindBranch(first);
2417 if (!leaf) leaf = fTree->FindLeaf(first);
2418 TClass* cl = nullptr;
2419 if ( branch && branch->InheritsFrom(TBranchElement::Class()) ) {
2420 int offset=0;
2422 TStreamerInfo* info = bElt->GetInfo();
2423 TStreamerElement* element = info ? info->GetStreamerElement(first,offset) : nullptr;
2424 if (element) cl = element->GetClassPointer();
2425 if ( cl && !cl->GetReferenceProxy() ) cl = nullptr;
2426 }
2427 if ( cl ) { // We have a reference class here....
2428 final = true;
2430 // we reset work
2431 current = &(work[0]);
2432 *current = 0;
2433 }
2434 else if (branch && (foundAtSign || cname[i] != 0) ) {
2435 // Since we found a branch and there is more information in the name,
2436 // we do NOT look at the 'IsOnTerminalBranch' status of the leaf
2437 // we found ... yet!
2438
2439 if (leaf==nullptr) {
2440 // Note we do not know (yet?) what (if anything) to do
2441 // for a TBranchObject branch.
2442 if (branch->InheritsFrom(TBranchElement::Class()) ) {
2443 Int_t type = ((TBranchElement*)branch)->GetType();
2444 if ( type == 3 || type ==4) {
2445 // We have a Collection branch.
2446 leaf = (TLeaf*)branch->GetListOfLeaves()->At(0);
2447 if (foundAtSign) {
2449 foundAtSign = false;
2450 current = &(work[0]);
2451 *current = 0;
2452 ++i;
2453 break;
2454 }
2455 }
2456 }
2457 }
2458
2459 // we reset work
2461 foundAtSign = false;
2462 current = &(work[0]);
2463 *current = 0;
2464 } else if (leaf || branch) {
2465 if (leaf && branch) {
2466 // We found both a leaf and branch matching the request name
2467 // let's see which one is the proper one to use! (On annoying case
2468 // is that where the same name is repeated ( varname.varname )
2469
2470 // We always give priority to the branch
2471 // leaf = 0;
2472 }
2473 if (leaf && leaf->IsOnTerminalBranch()) {
2474 // This is a non-object leaf, it should NOT be specified more except for
2475 // dimensions.
2476 final = true;
2477 }
2478 // we reset work
2479 current = &(work[0]);
2480 *current = 0;
2481 } else {
2482 // What we have so far might be a data member of one of the
2483 // leaves that are not split (for example "fNtrack" for the Event class.
2485 if (leafcur) {
2486 leaf = leafcur;
2487 branch = leaf->GetBranch();
2488 if (leaf->IsOnTerminalBranch()) {
2489 final = true;
2490 strlcpy(right,first,kMaxLen);
2491 //We need to put the delimiter back!
2492 if (foundAtSign) strncat(right,"@",2*kMaxLen-1-strlen(right));
2493 if (cname[i]=='.') strncat(right,".",2*kMaxLen-1-strlen(right));
2494
2495 // We reset work
2496 current = &(work[0]);
2497 *current = 0;
2498 };
2499 } else if (cname[i] == '.') {
2500 // If we have a branch that match a name preceded by a dot
2501 // then we assume we are trying to drill down the branch
2502 // Let look if one of the top level branch has a branch with the name
2503 // we are looking for.
2505 TIter next( fTree->GetListOfBranches() );
2506 while(!branch && (branchcur=(TBranch*)next()) ) {
2507 branch = branchcur->FindBranch(first);
2508 }
2509 if (branch) {
2510 // We reset work
2511 current = &(work[0]);
2512 *current = 0;
2513 }
2514 }
2515 }
2516 } else { // correspond to if (leaf || branch)
2517 if (final) {
2518 Error("DefinedVariable", "Unexpected control flow!");
2519 return -1;
2520 }
2521
2522 // No dot is allowed in subbranches and leaves, so
2523 // we always remove it in the present case.
2524 if (cname[i]) work[strlen(work)-1] = '\0';
2525 snprintf(scratch,sizeof(scratch),"%s.%s",first,work);
2526 snprintf(scratch2,sizeof(scratch2),"%s.%s.%s",first,second,work);
2527
2528 if (previousdot) {
2530 }
2531
2532 // First look for the current 'word' in the list of
2533 // leaf of the
2534 if (branch) {
2535 tmp_leaf = branch->FindLeaf(work);
2536 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch);
2537 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch2);
2538 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(currentname.c_str());
2539 }
2540 if (tmp_leaf && tmp_leaf->IsOnTerminalBranch() ) {
2541 // This is a non-object leaf, it should NOT be specified more except for
2542 // dimensions.
2543 final = true;
2544 }
2545
2546 if (branch) {
2547 tmp_branch = branch->FindBranch(work);
2548 if (!tmp_branch) tmp_branch = branch->FindBranch(scratch);
2549 if (!tmp_branch) tmp_branch = branch->FindBranch(scratch2);
2550 if (!tmp_branch) tmp_branch = branch->FindBranch(currentname.c_str());
2551 }
2552 if (tmp_branch) {
2554
2555 // NOTE: Should we look for a leaf within here?
2556 if (!final) {
2557 tmp_leaf = branch->FindLeaf(work);
2558 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch);
2559 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(scratch2);
2560 if (!tmp_leaf) tmp_leaf = branch->FindLeaf(currentname.c_str());
2561 if (tmp_leaf && tmp_leaf->IsOnTerminalBranch() ) {
2562 // This is a non-object leaf, it should NOT be specified
2563 // more except for dimensions.
2564 final = true;
2565 leaf = tmp_leaf;
2566 }
2567 }
2568 }
2569 if (tmp_leaf) {
2570 // Something was found.
2571 if (second[0]) strncat(second,".",2*kMaxLen-1-strlen(second));
2572 strncat(second,work,2*kMaxLen-1-strlen(second));
2573 leaf = tmp_leaf;
2575 foundAtSign = false;
2576
2577 // we reset work
2578 current = &(work[0]);
2579 *current = 0;
2580 } else {
2581 //We need to put the delimiter back!
2582 if (strlen(work)) {
2583 if (foundAtSign) {
2585 work[where] = '@';
2586 work[where+1] = cname[i];
2587 ++current;
2588 previousdot = where+1;
2589 } else {
2591 work[strlen(work)] = cname[i];
2592 }
2593 } else --current;
2594 }
2595 }
2596 }
2597 }
2598
2599 // Copy the left over for later use.
2600 if (strlen(work)) {
2601 strncat(right,work,2*kMaxLen-1-strlen(right));
2602 }
2603
2604 if (i<nchname) {
2605 if (strlen(right) && right[strlen(right)-1]!='.' && cname[i]!='.') {
2606 // In some cases we remove a little to fast the period, we add
2607 // it back if we need. It is assumed that 'right' and the rest of
2608 // the name was cut by a delimiter, so this should be safe.
2609 strncat(right,".",2*kMaxLen-1-strlen(right));
2610 }
2611 strncat(right,&cname[i],2*kMaxLen-1-strlen(right));
2612 }
2613
2614 if (!final && branch) {
2615 if (!leaf) {
2616 leaf = (TLeaf*)branch->GetListOfLeaves()->UncheckedAt(0);
2617 if (!leaf) return -1;
2618 }
2619 final = leaf->IsOnTerminalBranch();
2620 }
2621
2622 if (leaf && leaf->InheritsFrom(TLeafObject::Class()) ) {
2623 if (strlen(right)==0) strlcpy(right,work,2*kMaxLen);
2624 }
2625
2626 if (leaf==nullptr && left[0]!=0) {
2627 if (left[strlen(left)-1]=='.') left[strlen(left)-1]=0;
2628
2629 // Check for an alias.
2630 const char *aliasValue = fTree->GetAlias(left);
2631 if (aliasValue && strcspn(aliasValue,"()[]+*/-%&!=<>|")==strlen(aliasValue)) {
2632 // First check whether we are using this alias recursively (this would
2633 // lead to an infinite recursion).
2634 if (find(aliasUsed.begin(),
2635 aliasUsed.end(),
2636 left) != aliasUsed.end()) {
2637 Error("DefinedVariable",
2638 "The substitution of the branch alias \"%s\" by \"%s\" in \"%s\" failed\n"\
2639 "\tbecause \"%s\" is used [recursively] in its own definition!",
2640 left,aliasValue,fullExpression,left);
2641 return -3;
2642 }
2643 aliasUsed.push_back(left);
2645 newExpression += (cname+strlen(left));
2648 if (res<0) {
2649 Error("DefinedVariable",
2650 "The substitution of the alias \"%s\" by \"%s\" failed.",left,aliasValue);
2651 return -3;
2652 }
2653 return res;
2654 }
2655 }
2656 leftover = right;
2657
2658 return 0;
2659}
2660
2661////////////////////////////////////////////////////////////////////////////////
2662/// Check if name is in the list of Tree/Branch leaves.
2663///
2664/// This member function redefines the function in ROOT::v5::TFormula
2665/// If a leaf has a name corresponding to the argument name, then
2666/// returns a new code.
2667///
2668/// A TTreeFormula may contain more than one variable.
2669/// For each variable referenced, the pointers to the corresponding
2670/// branch and leaf is stored in the object arrays fBranches and fLeaves.
2671///
2672/// name can be :
2673/// - Leaf_Name (simple variable or data member of a ClonesArray)
2674/// - Branch_Name.Leaf_Name
2675/// - Branch_Name.Method_Name
2676/// - Leaf_Name[index]
2677/// - Branch_Name.Leaf_Name[index]
2678/// - Branch_Name.Leaf_Name[index1]
2679/// - Branch_Name.Leaf_Name[][index2]
2680/// - Branch_Name.Leaf_Name[index1][index2]
2681///
2682/// New additions:
2683/// - Branch_Name.Leaf_Name[OtherLeaf_Name]
2684/// - Branch_Name.Datamember_Name
2685/// - '.' can be replaced by '->'
2686///
2687/// and
2688/// - Branch_Name[index1].Leaf_Name[index2]
2689/// - Leaf_name[index].Action().OtherAction(param)
2690/// - Leaf_name[index].Action()[val].OtherAction(param)
2691///
2692/// The expected returned values are
2693/// - -2 : the name has been recognized but won't be usable
2694/// - -1 : the name has not been recognized, or is too long, or tree does not exist.
2695/// - >=0 : the name has been recognized, return the internal code for this name.
2696
2698{
2699
2701 if (!fTree) return -1;
2702
2703 fNpar = 0;
2704 if (name.Length() > kMaxLen) {
2705 Error("TTreeFormula", "The length of the variable name (%d) exceeds the maximum allowed (%d)", name.Length(), kMaxLen);
2706 return -1;
2707 }
2708 Int_t i,k;
2709
2710 if (name == "Entry$") {
2711 Int_t code = fNcodes++;
2712 fCodes[code] = 0;
2713 fLookupType[code] = kIndexOfEntry;
2714 return code;
2715 }
2716 if (name == "LocalEntry$") {
2717 Int_t code = fNcodes++;
2718 fCodes[code] = 0;
2720 return code;
2721 }
2722 if (name == "Entries$") {
2723 Int_t code = fNcodes++;
2724 fCodes[code] = 0;
2725 fLookupType[code] = kEntries;
2728 return code;
2729 }
2730 if (name == "LocalEntries$") {
2731 Int_t code = fNcodes++;
2732 fCodes[code] = 0;
2733 fLookupType[code] = kLocalEntries;
2734 SetBit(kNeedEntries); // FIXME: necessary?
2735 fManager->SetBit(kNeedEntries); // FIXME: necessary?
2736 return code;
2737 }
2738 if (name == "Iteration$") {
2739 Int_t code = fNcodes++;
2740 fCodes[code] = 0;
2741 fLookupType[code] = kIteration;
2742 return code;
2743 }
2744 if (name == "Length$") {
2745 Int_t code = fNcodes++;
2746 fCodes[code] = 0;
2747 fLookupType[code] = kLength;
2748 return code;
2749 }
2750 static const char *lenfunc = "Length$(";
2751 if (strncmp(name.Data(),"Length$(",strlen(lenfunc))==0
2752 && name[name.Length()-1]==')') {
2753
2754 TString subform = name.Data()+strlen(lenfunc);
2755 subform.Remove( subform.Length() - 1 );
2756 TTreeFormula *lengthForm = new TTreeFormula("lengthForm",subform,fTree);
2758 Int_t code = fNcodes++;
2759 fCodes[code] = 0;
2760 fLookupType[code] = kLengthFunc;
2761 return code;
2762 }
2763 static const char *minfunc = "Min$(";
2764 if (strncmp(name.Data(),"Min$(",strlen(minfunc))==0
2765 && name[name.Length()-1]==')') {
2766
2767 TString subform = name.Data()+strlen(minfunc);
2768 subform.Remove( subform.Length() - 1 );
2769 TTreeFormula *minForm = new TTreeFormula("minForm",subform,fTree);
2771 Int_t code = fNcodes++;
2772 fCodes[code] = 0;
2773 fLookupType[code] = kMin;
2774 return code;
2775 }
2776 static const char *maxfunc = "Max$(";
2777 if (strncmp(name.Data(),"Max$(",strlen(maxfunc))==0
2778 && name[name.Length()-1]==')') {
2779
2780 TString subform = name.Data()+strlen(maxfunc);
2781 subform.Remove( subform.Length() - 1 );
2782 TTreeFormula *maxForm = new TTreeFormula("maxForm",subform,fTree);
2784 Int_t code = fNcodes++;
2785 fCodes[code] = 0;
2786 fLookupType[code] = kMax;
2787 return code;
2788 }
2789 static const char *sumfunc = "Sum$(";
2790 if (strncmp(name.Data(),"Sum$(",strlen(sumfunc))==0
2791 && name[name.Length()-1]==')') {
2792
2793 TString subform = name.Data()+strlen(sumfunc);
2794 subform.Remove( subform.Length() - 1 );
2795 TTreeFormula *sumForm = new TTreeFormula("sumForm",subform,fTree);
2797 Int_t code = fNcodes++;
2798 fCodes[code] = 0;
2799 fLookupType[code] = kSum;
2800 return code;
2801 }
2802
2803
2804
2805 // Check for $Alt(expression1,expression2)
2806 Int_t res = DefineAlternate(name.Data());
2807 if (res!=0) {
2808 // There was either a syntax error or we found $Alt
2809 if (res<0) return res;
2810 action = res;
2811 return 0;
2812 }
2813
2814 // Find the top level leaf and deal with dimensions
2815
2816 char cname[kMaxLen]; strlcpy(cname,name.Data(),kMaxLen);
2817 char dims[kMaxLen]; dims[0] = '\0';
2818
2819 bool final = false;
2820
2821 UInt_t paran_level = 0;
2823
2824 // First, it is easier to remove all dimensions information from 'cname'
2826 for(i=0,k=0; i<cnamelen; ++i, ++k) {
2827 if (cname[i] == '[') {
2828 int bracket = i;
2829 int bracket_level = 1;
2830 int j;
2831 for (j=++i; j<cnamelen && (bracket_level>0 || cname[j]=='['); j++, i++) {
2832 if (cname[j]=='[') bracket_level++;
2833 else if (cname[j]==']') bracket_level--;
2834 }
2835 if (bracket_level != 0) {
2836 //Error("DefinedVariable","Bracket unbalanced");
2837 return -1;
2838 }
2840 //k += j-bracket;
2841 }
2842 if (i!=k) cname[k] = cname[i];
2843 }
2844 cname[k]='\0';
2845
2846 bool useLeafCollectionObject = false;
2848 TLeaf *leaf = nullptr;
2849 {
2850 std::vector<std::string> aliasSofar = fAliasesUsed;
2852 }
2853 if (res<0) return res;
2854
2855 if (!leaf && res!=2) {
2856 // Check for an alias.
2857 const char *aliasValue = fTree->GetAlias(cname);
2858 if (aliasValue) {
2859 // First check whether we are using this alias recursively (this would
2860 // lead to an infinite recursion.
2861 if (find(fAliasesUsed.begin(),
2862 fAliasesUsed.end(),
2863 cname) != fAliasesUsed.end()) {
2864 Error("DefinedVariable",
2865 "The substitution of the alias \"%s\" by \"%s\" failed\n"\
2866 "\tbecause \"%s\" is recursively used in its own definition!",
2868 return -3;
2869 }
2870
2871
2872 if (strcspn(aliasValue,"()+*/-%&!=<>|")!=strlen(aliasValue)) {
2873 // If the alias contains an operator, we need to use a nested formula
2874 // (since DefinedVariable must only add one entry to the operation's list).
2875
2876 // Need to check the aliases used so far
2877 std::vector<std::string> aliasSofar = fAliasesUsed;
2878 aliasSofar.push_back( cname );
2879
2881 if (dims[0]) {
2882 subValue += dims;
2883 }
2884
2885 TTreeFormula *subform = new TTreeFormula(cname,subValue,fTree,aliasSofar); // Need to pass the aliases used so far.
2886
2887 if (subform->GetNdim()==0) {
2888 delete subform;
2889 Error("DefinedVariable",
2890 "The substitution of the alias \"%s\" by \"%s\" failed.",cname,aliasValue);
2891 return -3;
2892 }
2893
2896
2897 if (subform->IsString()) {
2899 return 0;
2900 } else {
2901 action = kAlias;
2902 return 0;
2903 }
2904 } else { /* assumes strcspn(aliasValue,"[]")!=strlen(aliasValue) */
2906 thisAlias += dims;
2908 if (aliasRes<0) {
2909 // We failed but DefinedVariable has not printed why yet.
2910 // and because we want those to be printed _before_ the notice
2911 // of the failure of the substitution, we need to print them here.
2912 if (aliasRes==-1) {
2913 Error("Compile", " Bad numerical expression : \"%s\"",thisAlias.Data());
2914 } else if (aliasRes==-2) {
2915 Error("Compile", " Part of the Variable \"%s\" exists but some of it is not accessible or useable",thisAlias.Data());
2916
2917 }
2918 Error("DefinedVariable",
2919 "The substitution of the alias \"%s\" by \"%s\" failed.",cname,aliasValue);
2920 return -3;
2921 }
2922 return aliasRes;
2923 }
2924 }
2925 }
2926
2927
2928 if (leaf || res==2) {
2929
2930 if (leaf && leaf->GetBranch() && leaf->GetBranch()->TestBit(kDoNotProcess)) {
2931 Error("DefinedVariable","the branch \"%s\" has to be enabled to be used",leaf->GetBranch()->GetName());
2932 return -2;
2933 }
2934
2935 Int_t code = fNcodes++;
2936
2937 // If needed will now parse the indexes specified for
2938 // arrays.
2939 if (dims[0]) {
2940 char *current = &( dims[0] );
2941 Int_t dim = 0;
2943 Int_t index;
2945 while (current) {
2946 current++;
2947 if (current[0] == ']') {
2948 fIndexes[code][dim] = -1; // Loop over all elements;
2949 } else {
2950 scanindex = sscanf(current,"%d",&index);
2951 if (scanindex) {
2952 fIndexes[code][dim] = index;
2953 } else {
2954 fIndexes[code][dim] = -2; // Index is calculated via a variable.
2955 varindex = current;
2956 char *end = (char*)(varindex.Data());
2957 for(char bracket_level = 0;*end!=0;end++) {
2958 if (*end=='[') bracket_level++;
2959 if (bracket_level==0 && *end==']') break;
2960 if (*end==']') bracket_level--;
2961 }
2962 *end = '\0';
2963 fVarIndexes[code][dim] = new TTreeFormula("index_var",
2964 varindex,
2965 fTree);
2966 if (fVarIndexes[code][dim]->GetNdim() == 0) {
2967 // Parsing failed for the index, let's stop here ....
2968 return -1;
2969 }
2970 current += strlen(varindex)+1; // move to the end of the index array
2971 }
2972 }
2973 dim ++;
2974 if (dim >= kMAXFORMDIM) {
2975 // NOTE: test that dim this is NOT too big!!
2976 break;
2977 }
2978 current = (char*)strstr( current, "[" );
2979 }
2980 }
2981
2982 // Now that we have cleaned-up the expression, let's compare it to the content
2983 // of the leaf!
2984
2986 if (res<0) return res;
2987 if (res>0) action = res;
2988 return code;
2989 }
2990
2991//*-*- May be a graphical cut ?
2992 TCutG *gcut = (TCutG*)gROOT->GetListOfSpecials()->FindObject(name.Data());
2993 if (gcut) {
2994 if (gcut->GetObjectX()) {
2995 if(!gcut->GetObjectX()->InheritsFrom(TTreeFormula::Class()))
2996 gcut->SetObjectX(nullptr);
2997 }
2998 if (gcut->GetObjectY()) {
2999 if(!gcut->GetObjectY()->InheritsFrom(TTreeFormula::Class()))
3000 gcut->SetObjectY(nullptr);
3001 }
3002
3003 Int_t code = fNcodes;
3004
3005 if (strlen(gcut->GetVarX()) && strlen(gcut->GetVarY()) ) {
3006
3007 TTreeFormula *fx = new TTreeFormula("f_x",gcut->GetVarX(),fTree);
3008 gcut->SetObjectX(fx);
3009
3010 TTreeFormula *fy = new TTreeFormula("f_y",gcut->GetVarY(),fTree);
3011 gcut->SetObjectY(fy);
3012
3013 fCodes[code] = -2;
3014
3015 } else if (strlen(gcut->GetVarX())) {
3016
3017 // Let's build the equivalent formula:
3018 // min(gcut->X) <= VarX <= max(gcut->Y)
3019 Double_t min = 0;
3020 Double_t max = 0;
3021 Int_t n = gcut->GetN();
3022 Double_t *x = gcut->GetX();
3023 min = max = x[0];
3024 for(Int_t i2 = 1; i2<n; i2++) {
3025 if (x[i2] < min) min = x[i2];
3026 if (x[i2] > max) max = x[i2];
3027 }
3028 TString formula = "(";
3029 formula += min;
3030 formula += "<=";
3031 formula += gcut->GetVarX();
3032 formula += " && ";
3033 formula += gcut->GetVarX();
3034 formula += "<=";
3035 formula += max;
3036 formula += ")";
3037
3038 TTreeFormula *fx = new TTreeFormula("f_x",formula.Data(),fTree);
3039 gcut->SetObjectX(fx);
3040
3041 fCodes[code] = -1;
3042
3043 } else {
3044
3045 Error("DefinedVariable","Found a TCutG without leaf information (%s)",
3046 gcut->GetName());
3047 return -1;
3048
3049 }
3050
3052 fNcodes++;
3053 fLookupType[code] = -1;
3054 return code;
3055 }
3056
3057 //may be an entrylist
3058 TEntryList *elist = dynamic_cast<TEntryList*> (gDirectory->Get(name.Data()));
3059 if (elist) {
3060 Int_t code = fNcodes;
3061 fCodes[code] = 0;
3062 fExternalCuts.AddAtAndExpand(elist, code);
3063 fNcodes++;
3064 fLookupType[code] = kEntryList;
3065 return code;
3066
3067 }
3068
3069 return -1;
3070}
3071
3072////////////////////////////////////////////////////////////////////////////////
3073/// Return the leaf (if any) which contains an object containing
3074/// a data member which has the name provided in the arguments.
3075
3077{
3078 TClass * cl = nullptr;
3080 TFormLeafInfo* clonesinfo = nullptr;
3081 TLeaf *leafcur;
3082 while ((leafcur = (TLeaf*)nextleaf())) {
3083 // The following code is used somewhere else, we need to factor it out.
3084
3085 // Here since we are interested in data member, we want to consider only
3086 // 'terminal' branch and leaf.
3087 cl = nullptr;
3088 if (leafcur->InheritsFrom(TLeafObject::Class()) &&
3089 leafcur->GetBranch()->GetListOfBranches()->Last()==nullptr) {
3091 cl = lobj->GetClass();
3092 } else if (leafcur->InheritsFrom(TLeafElement::Class()) && leafcur->IsOnTerminalBranch()) {
3094 if (lElem->IsOnTerminalBranch()) {
3095 TBranchElement *branchEl = (TBranchElement *)leafcur->GetBranch();
3096 Int_t type = branchEl->GetStreamerType();
3097 if (type==-1) {
3098 cl = branchEl->GetInfo() ? branchEl->GetInfo()->GetClass() : nullptr;
3099 } else if (type>60 || type==0) {
3100 // Case of an object data member. Here we allow for the
3101 // variable name to be omitted. Eg, for Event.root with split
3102 // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
3103 TStreamerElement* element = branchEl->GetInfo()->GetElement(branchEl->GetID());
3104 if (element) cl = element->GetClassPointer();
3105 else cl = nullptr;
3106 }
3107 }
3108
3109 }
3110 if (clonesinfo) { delete clonesinfo; clonesinfo = nullptr; }
3111 if (cl == TClonesArray::Class()) {
3112 // We have a unsplit TClonesArray leaves
3113 // In this case we assume that cl is the class in which the TClonesArray
3114 // belongs.
3117
3118 TBranch *branch = leafcur->GetBranch();
3119 if ( branch->IsA()==TBranchElement::Class()
3120 && ((TBranchElement*)branch)->GetType()==31) {
3121
3122 // We have an unsplit TClonesArray as part of a split TClonesArray!
3123
3124 // Let's not dig any further. If the user really wants a data member
3125 // inside the nested TClonesArray, it has to specify it explicitly.
3126
3127 continue;
3128
3129 } else {
3130 bool toplevel = (branch == branch->GetMother());
3132 clones = (TClonesArray*)clonesinfo->GetLocalValuePointer(leafcur,0);
3133 }
3134 if (clones) cl = clones->GetClass();
3135 } else if (cl && cl->GetCollectionProxy()) {
3136
3137 // We have a unsplit Collection leaves
3138 // In this case we assume that cl is the class in which the TClonesArray
3139 // belongs.
3140
3141 TBranch *branch = leafcur->GetBranch();
3142 if ( branch->IsA()==TBranchElement::Class()
3143 && ((TBranchElement*)branch)->GetType()==41) {
3144
3145 // We have an unsplit Collection as part of a split Collection!
3146
3147 // Let's not dig any further. If the user really wants a data member
3148 // inside the nested Collection, it has to specify it explicitly.
3149
3150 continue;
3151
3152 } else {
3154 }
3155 cl = cl->GetCollectionProxy()->GetValueClass();
3156 }
3157 if (cl) {
3158 // Now that we have the class, let's check if the topchoice is of its datamember
3159 // or if the nextchoice is a datamember of one of its datamember.
3160 Int_t offset;
3162 TStreamerElement* element = info?info->GetStreamerElement(topchoice,offset):nullptr;
3163 if (!element) {
3166 while ((curelem = (TStreamerElement*)nextel())) {
3167
3168 if (curelem->GetClassPointer() == TClonesArray::Class()) {
3169 // In case of a TClonesArray we need to load the data and read the
3170 // clonesArray object before being able to look into the class inside.
3171 // We need to do that because we are never interested in the TClonesArray
3172 // itself but only in the object inside.
3173 TBranch *branch = leafcur->GetBranch();
3174 TFormLeafInfo *leafinfo = nullptr;
3175 if (clonesinfo) {
3177 } else if (branch->IsA()==TBranchElement::Class()
3178 && ((TBranchElement*)branch)->GetType()==31) {
3179 // Case of a sub branch of a TClonesArray
3181 TStreamerInfo *bel_info = branchEl->GetInfo();
3182 TClass * mother_cl = ((TBranchElement*)branch)->GetInfo()->GetClass();
3184 bel_info->GetElement(branchEl->GetID());
3186 }
3187
3188 Int_t clones_offset = 0;
3189 ((TStreamerInfo*)cl->GetStreamerInfo())->GetStreamerElement(curelem->GetName(),clones_offset);
3191 if (leafinfo)
3192 if (leafinfo->fNext) leafinfo->fNext->fNext = sub_clonesinfo;
3193 else leafinfo->fNext = sub_clonesinfo;
3194 else leafinfo = sub_clonesinfo;
3195
3197
3198 TClonesArray * clones = (TClonesArray*)leafinfo->GetValuePointer(leafcur,0);
3199
3200 delete leafinfo; clonesinfo = nullptr;
3201 // If TClonesArray object does not exist we have no information, so let go
3202 // on. This is a weakish test since the TClonesArray object might exist in
3203 // the next entry ... In other word, we ONLY rely on the information available
3204 // in entry #0.
3205 if (!clones) continue;
3206 TClass *sub_cl = clones->GetClass();
3207
3208 // Now that we finally have the inside class, let's query it.
3209 element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(nextchoice,offset);
3210 if (element) break;
3211 } // if clones array
3212 else if (curelem->GetClassPointer() && curelem->GetClassPointer()->GetCollectionProxy()) {
3213
3214 TClass *sub_cl = curelem->GetClassPointer()->GetCollectionProxy()->GetValueClass();
3215
3216 while(sub_cl && sub_cl->GetCollectionProxy())
3217 sub_cl = sub_cl->GetCollectionProxy()->GetValueClass();
3218
3219 // Now that we finally have the inside class, let's query it.
3220 if (sub_cl) element = ((TStreamerInfo*)sub_cl->GetStreamerInfo())->GetStreamerElement(nextchoice,offset);
3221 if (element) break;
3222
3223 }
3224 } // loop on elements
3225 }
3226 if (element) break;
3227 else cl = nullptr;
3228 }
3229 }
3230 delete clonesinfo;
3231 if (cl) {
3232 return leafcur;
3233 } else {
3234 return nullptr;
3235 }
3236}
3237
3238////////////////////////////////////////////////////////////////////////////////
3239/// Return the leaf (if any) of the tree with contains an object of a class
3240/// having a method which has the name provided in the argument.
3241
3242bool TTreeFormula::BranchHasMethod(TLeaf* leafcur, TBranch* branch, const char* method, const char* params, Long64_t readentry) const
3243{
3244 TClass *cl = nullptr;
3245 TLeafObject* lobj = nullptr;
3246
3247 // Since the user does not want this branch to be loaded anyway, we just
3248 // skip it. This prevents us from warning the user that the method might
3249 // be on a disabled branch. However, and more usefully, this allows the
3250 // user to avoid error messages from branches that cannot be currently
3251 // read without warnings/errors.
3252
3253 if (branch->TestBit(kDoNotProcess)) {
3254 return false;
3255 }
3256
3257 // FIXME: The following code is used somewhere else, we need to factor it out.
3258 if (branch->InheritsFrom(TBranchObject::Class())) {
3259 lobj = (TLeafObject*) branch->GetListOfLeaves()->At(0);
3260 cl = lobj->GetClass();
3261 } else if (branch->InheritsFrom(TBranchElement::Class())) {
3263 Int_t type = branchEl->GetStreamerType();
3264 if (type == -1) {
3265 cl = branchEl->GetInfo() ? branchEl->GetInfo()->GetClass() : nullptr;
3266 } else if (type > 60) {
3267 // Case of an object data member. Here we allow for the
3268 // variable name to be omitted. Eg, for Event.root with split
3269 // level 1 or above Draw("GetXaxis") is the same as Draw("fH.GetXaxis()")
3270 TStreamerElement* element = branchEl->GetInfo()->GetElement(branchEl->GetID());
3271 if (element) {
3272 cl = element->GetClassPointer();
3273 } else {
3274 cl = nullptr;
3275 }
3276 if ((cl == TClonesArray::Class()) && (branchEl->GetType() == 31)) {
3277 // we have a TClonesArray inside a split TClonesArray,
3278 // Let's not dig any further. If the user really wants a data member
3279 // inside the nested TClonesArray, it has to specify it explicitly.
3280 cl = nullptr;
3281 }
3282 // NOTE do we need code for Collection here?
3283 }
3284 }
3285
3286 if (cl == TClonesArray::Class()) {
3287 // We might be try to call a method of the top class inside a
3288 // TClonesArray.
3289 // Since the leaf was not terminal, we might have a split or
3290 // unsplit and/or top leaf/branch.
3291 TClonesArray* clones = nullptr;
3293 if (branch->InheritsFrom(TBranchObject::Class())) {
3294 clones = (TClonesArray*) lobj->GetObject();
3295 } else if (branch->InheritsFrom(TBranchElement::Class())) {
3296 // We do not know exactly where the leaf of the TClonesArray is
3297 // in the hierarchy but we still need to get the correct class
3298 // holder.
3300 if (bc == bc->GetMother()) {
3301 // Top level branch
3302 //clones = *((TClonesArray**) bc->GetAddress());
3303 clones = (TClonesArray*) bc->GetObject();
3304 } else if (!leafcur || !leafcur->IsOnTerminalBranch()) {
3305 TStreamerElement* element = bc->GetInfo()->GetElement(bc->GetID());
3306 if (element->IsaPointer()) {
3307 clones = *((TClonesArray**) bc->GetAddress());
3308 //clones = *((TClonesArray**) bc->GetObject());
3309 } else {
3310 //clones = (TClonesArray*) bc->GetAddress();
3311 clones = (TClonesArray*) bc->GetObject();
3312 }
3313 }
3314 if (!clones) {
3317 mother_cl = bc->GetInfo()->GetClass();
3319 // if (!leafcur) { leafcur = (TLeaf*) branch->GetListOfLeaves()->At(0); }
3320 clones = (TClonesArray*) clonesinfo->GetLocalValuePointer(leafcur, 0);
3321 // cl = clones->GetClass();
3322 delete clonesinfo;
3323 }
3324 } else {
3325 Error("BranchHasMethod","A TClonesArray was stored in a branch type no yet support (i.e. neither TBranchObject nor TBranchElement): %s",branch->IsA()->GetName());
3326 return false;
3327 }
3328 cl = clones ? clones->GetClass() : nullptr;
3329 } else if (cl && cl->GetCollectionProxy()) {
3330 cl = cl->GetCollectionProxy()->GetValueClass();
3331 }
3332
3333 if (cl) {
3334 if (cl->GetClassInfo()) {
3335 if (cl->GetMethodAllAny(method)) {
3336 // Let's try to see if the function we found belongs to the current
3337 // class. Note that this implementation currently can not work if
3338 // one the argument is another leaf or data member of the object.
3339 // (Anyway we do NOT support this case).
3340 TMethodCall methodcall(cl, method, params);
3341 if (methodcall.GetMethod()) {
3342 // We have a method that works.
3343 // We will use it.
3344 return true;
3345 }
3346 }
3347 }
3348 }
3349
3350 return false;
3351}
3352
3353////////////////////////////////////////////////////////////////////////////////
3354/// Now let calculate what physical instance we really need.
3355/// Some redundant code is used to speed up the cases where
3356/// they are no dimensions.
3357///
3358/// We know that instance is less that fCumulUsedSize[0] so
3359/// we can skip the modulo when virt_dim is 0.
3360
3362 Int_t real_instance = 0;
3364
3365 bool check = false;
3366 if (codeindex<0) {
3367 codeindex = 0;
3368 check = true;
3369 }
3370
3371 TFormLeafInfo * info = nullptr;
3372 Int_t max_dim = fNdimensions[codeindex];
3373 if ( max_dim ) {
3374 virt_dim = 0;
3375 max_dim--;
3376
3377 if (!fManager->fMultiVarDim) {
3378 if (fIndexes[codeindex][0]>=0) {
3380 } else {
3383 if (fIndexes[codeindex][0]==-2) {
3384 // NOTE: Should we check that this is a valid index?
3385 if (check) {
3388 // out of bounds
3389 return fNdata[0]+1;
3390 }
3391 }
3393 // Force the loading of the index.
3395 }
3397 if (local_index<0) {
3398 Error("EvalInstance","Index %s is out of bound (%d) in formula %s",
3401 GetTitle());
3402 return fNdata[0]+1;
3403 }
3404 }
3406 virt_dim ++;
3407 }
3408 } else {
3409 // NOTE: We assume that ONLY the first dimension of a leaf can have a variable
3410 // size AND contain the index for the size of yet another sub-dimension.
3411 // I.e. a variable size array inside a variable size array can only have its
3412 // size vary with the VERY FIRST physical dimension of the leaf.
3413 // Thus once the index of the first dimension is found, all other dimensions
3414 // are fixed!
3415
3416 // NOTE: We could unroll some of this loops to avoid a few tests.
3419 // if (info && info->GetVarDim()==-1) info = 0;
3420 }
3422
3423 switch (fIndexes[codeindex][0]) {
3424 case -2:
3426 // Force the loading of the index.
3428 }
3430 if (local_index<0) {
3431 Error("EvalInstance","Index %s is out of bound (%d) in formula %s",
3434 GetTitle());
3435 local_index = 0;
3436 }
3437 break;
3438 case -1: {
3442 }
3446
3448 if (maxloop == 0) {
3449 local_index--;
3450 instance = fNdata[0]+1; // out of bounds.
3451 if (check) return fNdata[0]+1;
3452 } else {
3453 do {
3455 local_index++;
3456 } while( instance >= virt_accum && local_index<maxloop);
3457 local_index--;
3458 // update the cache
3461
3462 if (local_index==(maxloop-1) && (instance >= virt_accum)) {
3463 instance = fNdata[0]+1; // out of bounds.
3464 if (check) return fNdata[0]+1;
3465 } else {
3468 } else {
3469 instance = fNdata[0]+1; // out of bounds.
3470 if (check) return fNdata[0]+1;
3471 }
3472 }
3473 }
3474 virt_dim ++;
3475 }
3476 break;
3477 default:
3479 }
3480
3481 // Inform the (appropriate) MultiVarLeafInfo that the clones array index is
3482 // local_index.
3483
3486 } else {
3488 }
3489 for(Int_t d = kMAXFORMDIM-1; d>0; d--) {
3490 if (fManager->fVarDims[d]) {
3492 } else {
3494 }
3495 }
3496 if (info) {
3497 // When we have multiple variable dimensions, the LeafInfo only expect
3498 // the instance after the primary index has been set.
3499 info->SetPrimaryIndex(local_index);
3500 real_instance = 0;
3501
3502 // Let's update fCumulSizes for the rest of the code.
3503 Int_t vdim = info->GetVarDim();
3504 Int_t isize = info->GetSize(local_index);
3505 if (fIndexes[codeindex][vdim]>=0) {
3506 info->SetSecondaryIndex(fIndexes[codeindex][vdim]);
3507 }
3508 if (isize!=1 && fIndexes[codeindex][vdim]>isize) {
3509 // We are out of bounds!
3510 return fNdata[0]+1;
3511 }
3513 for(Int_t k=vdim -1; k>0; --k) {
3515 }
3516 } else {
3518 }
3519 }
3520 if (max_dim>0) {
3521 for (Int_t dim = 1; dim < max_dim; dim++) {
3522 if (fIndexes[codeindex][dim]>=0) {
3524 } else {
3529 } else {
3531 }
3532 if (fIndexes[codeindex][dim]==-2) {
3533 // NOTE: Should we check that this is a valid index?
3535 // Force the loading of the index.
3537 }
3539 if (local_index<0 ||
3541 Error("EvalInstance","Index %s is out of bound (%d/%d) in formula %s",
3545 GetTitle());
3547 }
3548 }
3550 virt_dim ++;
3551 }
3552 }
3553 if (fIndexes[codeindex][max_dim]>=0) {
3554 if (!info) real_instance += fIndexes[codeindex][max_dim];
3555 } else {
3559 } else {
3561 }
3562 if (info && local_index>=fCumulSizes[codeindex][max_dim]) {
3563 // We are out of bounds! [Multiple var dims, See same message a few line above]
3564 return fNdata[0]+1;
3565 }
3566 if (fIndexes[codeindex][max_dim]==-2) {
3568 // Force the loading of the index.
3569 fVarIndexes[codeindex][max_dim]->LoadBranches();
3570 }
3572 if (local_index<0 ||
3573 local_index>=fCumulSizes[codeindex][max_dim]) {
3574 Error("EvalInstance","Index %s is of out bound (%d/%d) in formula %s",
3575 fVarIndexes[codeindex][max_dim]->GetTitle(),
3577 fCumulSizes[codeindex][max_dim],
3578 GetTitle());
3579 local_index = fCumulSizes[codeindex][max_dim]-1;
3580 }
3581 }
3583 }
3584 } // if (max_dim-1>0)
3585 } // if (max_dim)
3586
3587 return real_instance;
3588}
3589
3590////////////////////////////////////////////////////////////////////////////////
3591/// Evaluate the class of this treeformula.
3592///
3593/// If the 'value' of this formula is a simple pointer to an object,
3594/// this function returns the TClass corresponding to its type.
3595
3597{
3598 if (fNoper != 1 || fNcodes <=0 ) return nullptr;
3599
3600 return EvalClass(0);
3601}
3602
3603////////////////////////////////////////////////////////////////////////////////
3604/// Evaluate the class of the operation oper.
3605///
3606/// If the 'value' in the requested operation is a simple pointer to an object,
3607/// this function returns the TClass corresponding to its type.
3608
3610{
3612 switch(fLookupType[oper]) {
3613 case kDirect: {
3614 if (leaf->IsA()==TLeafObject::Class()) {
3615 return ((TLeafObject*)leaf)->GetClass();
3616 } else if ( leaf->IsA()==TLeafElement::Class()) {
3617 TBranchElement * branch = (TBranchElement*)((TLeafElement*)leaf)->GetBranch();
3618 TStreamerInfo * info = branch->GetInfo();
3619 Int_t id = branch->GetID();
3620 if (id>=0) {
3621 if (info==nullptr || !info->IsCompiled()) {
3622 // we probably do not have a way to know the class of the object.
3623 return nullptr;
3624 }
3625 TStreamerElement* elem = (TStreamerElement*)info->GetElement(id);
3626 if (elem==nullptr) {
3627 // we probably do not have a way to know the class of the object.
3628 return nullptr;
3629 } else {
3630 return elem->GetClass();
3631 }
3632 } else return TClass::GetClass( branch->GetClassName() );
3633 } else {
3634 return nullptr;
3635 }
3636 }
3637 case kMethod: return nullptr; // kMethod is deprecated so let's no waste time implementing this.
3638 case kTreeMember:
3639 case kDataMember: {
3641 if (!obj) return nullptr;
3642 return ((TFormLeafInfo*)obj)->GetClass();
3643 }
3644
3645 default: return nullptr;
3646 }
3647
3648
3649}
3650
3651////////////////////////////////////////////////////////////////////////////////
3652/// Evaluate this treeformula.
3653///
3654/// Return the address of the object pointed to by the formula.
3655/// Return 0 if the formula is not a single object
3656/// The object type can be retrieved using by call EvalClass();
3657
3659{
3660 if (fNoper != 1 || fNcodes <=0 ) return nullptr;
3661
3662
3663 switch (fLookupType[0]) {
3664 case kIndexOfEntry:
3665 case kIndexOfLocalEntry:
3666 case kEntries:
3667 case kLocalEntries:
3668 case kLength:
3669 case kLengthFunc:
3670 case kIteration:
3671 case kEntryList:
3672 return nullptr;
3673 }
3674
3676
3678
3679 if (instance==0 || fNeedLoading) {
3680 fNeedLoading = false;
3681 R__LoadBranch(leaf->GetBranch(),
3682 leaf->GetBranch()->GetTree()->GetReadEntry(),
3683 fQuickLoad);
3684 }
3685 else if (real_instance>=fNdata[0]) return nullptr;
3686 if (fAxis) {
3687 return nullptr;
3688 }
3689 switch(fLookupType[0]) {
3690 case kDirect: {
3691 if (real_instance) {
3692 Warning("EvalObject","Not yet implement for kDirect and arrays (for %s).\nPlease contact the developers",GetName());
3693 }
3694 return leaf->GetValuePointer();
3695 }
3696 case kMethod: return GetValuePointerFromMethod(0,leaf);
3697 case kTreeMember:
3698 case kDataMember: return ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->GetValuePointer(leaf,real_instance);
3699 default: return nullptr;
3700 }
3701
3702
3703}
3704
3705
3706////////////////////////////////////////////////////////////////////////////////
3707/// Eval the instance as a string.
3708
3710{
3711 const Int_t kMAXSTRINGFOUND = 10;
3712 const char *stringStack[kMAXSTRINGFOUND];
3713
3714 if (fNoper==1 && fNcodes>0 && IsString()) {
3716
3718
3719 if (instance==0 || fNeedLoading) {
3720 fNeedLoading = false;
3721 TBranch *branch = leaf->GetBranch();
3722 R__LoadBranch(branch,branch->GetTree()->GetReadEntry(),fQuickLoad);
3723 } else if (real_instance>=fNdata[0]) {
3724 return nullptr;
3725 }
3726
3727 if (fLookupType[0]==kDirect) {
3728 return (char*)leaf->GetValuePointer();
3729 } else {
3730 return (char*)GetLeafInfo(0)->GetValuePointer(leaf,real_instance);
3731 }
3732 }
3733
3735
3736 return stringStack[0];
3737}
3738
3739#define TT_EVAL_INIT \
3740 TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(0); \
3741 \
3742 const Int_t real_instance = GetRealInstance(instance,0); \
3743 \
3744 if (instance==0) fNeedLoading = true; \
3745 if (real_instance>=fNdata[0]) return 0; \
3746 \
3747 /* Since the only operation in this formula is reading this branch, \
3748 we are guaranteed that this function is first called with instance==0 and \
3749 hence we are guaranteed that the branch is always properly read */ \
3750 \
3751 if (fNeedLoading) { \
3752 fNeedLoading = false; \
3753 TBranch *br = leaf->GetBranch(); \
3754 if (br && br->GetTree()) { \
3755 Long64_t tentry = br->GetTree()->GetReadEntry(); \
3756 R__LoadBranch(br,tentry,fQuickLoad); \
3757 } else { \
3758 Error("TTreeFormula::TT_EVAL_INIT", \
3759 "Could not init branch associated to this leaf (%s).", leaf->GetName()); \
3760 } \
3761 } \
3762 \
3763 if (fAxis) { \
3764 char * label; \
3765 /* This portion is a duplicate (for speed reason) of the code \
3766 located in the main for loop at "a tree string" (and in EvalStringInstance) */ \
3767 if (fLookupType[0]==kDirect) { \
3768 label = (char*)leaf->GetValuePointer(); \
3769 } else { \
3770 label = (char*)GetLeafInfo(0)->GetValuePointer(leaf,instance); \
3771 } \
3772 Int_t bin = fAxis->FindBin(label); \
3773 return bin-0.5; \
3774 }
3775
3776#define TREE_EVAL_INIT \
3777 const Int_t real_instance = GetRealInstance(instance,0); \
3778 \
3779 if (real_instance>=fNdata[0]) return 0; \
3780 \
3781 if (fAxis) { \
3782 char * label; \
3783 /* This portion is a duplicate (for speed reason) of the code \
3784 located in the main for loop at "a tree string" (and in EvalStringInstance) */ \
3785 label = (char*)GetLeafInfo(0)->GetValuePointer((TLeaf*)0x0,instance); \
3786 Int_t bin = fAxis->FindBin(label); \
3787 return bin-0.5; \
3788 }
3789
3790#define TT_EVAL_INIT_LOOP \
3791 TLeaf *leaf = (TLeaf*)fLeaves.UncheckedAt(code); \
3792 \
3793 /* Now let calculate what physical instance we really need. */ \
3794 const Int_t real_instance = GetRealInstance(instance,code); \
3795 \
3796 if (willLoad) { \
3797 TBranch *branch = (TBranch*)fBranches.UncheckedAt(code); \
3798 if (branch) { \
3799 if (branch->GetTree()) { \
3800 Long64_t treeEntry = branch->GetTree()->GetReadEntry(); \
3801 R__LoadBranch(branch,treeEntry,fQuickLoad); \
3802 } else { \
3803 Error("TTreeFormula::TT_EVAL_INIT_LOOP", \
3804 "Could not init branch associated to this leaf (%s).", leaf->GetName()); \
3805 } \
3806 } else if (fDidBooleanOptimization) { \
3807 branch = leaf->GetBranch(); \
3808 if (branch->GetTree()) { \
3809 Long64_t treeEntry = branch->GetTree()->GetReadEntry(); \
3810 if (branch->GetReadEntry() != treeEntry) branch->GetEntry( treeEntry ); \
3811 } else { \
3812 Error("TTreeFormula::TT_EVAL_INIT_LOOP", \
3813 "Could not init branch associated to this leaf (%s).", leaf->GetName()); \
3814 } \
3815 } \
3816 } else { \
3817 /* In the cases where we are behind (i.e. right of) a potential boolean optimization \
3818 this tree variable reading may have not been executed with instance==0 which would \
3819 result in the branch being potentially not read in. */ \
3820 if (fDidBooleanOptimization) { \
3821 TBranch *br = leaf->GetBranch(); \
3822 if (br->GetTree()) { \
3823 Long64_t treeEntry = br->GetTree()->GetReadEntry(); \
3824 if (br->GetReadEntry() != treeEntry) br->GetEntry( treeEntry ); \
3825 } else { \
3826 Error("TTreeFormula::TT_EVAL_INIT_LOOP", \
3827 "Could not init branch associated to this leaf (%s).", leaf->GetName()); \
3828 } \
3829 } \
3830 } \
3831 if (real_instance>=fNdata[code]) return 0;
3832
3833#define TREE_EVAL_INIT_LOOP \
3834 /* Now let calculate what physical instance we really need. */ \
3835 const Int_t real_instance = GetRealInstance(instance,code); \
3836 \
3837 if (real_instance>=fNdata[code]) return 0;
3838
3839
3840template<typename T> T Summing(TTreeFormula *sum) {
3841 Int_t len = sum->GetNdata();
3842 T res = 0;
3843 for (int i=0; i<len; ++i) res += sum->EvalInstance<T>(i);
3844 return res;
3845}
3846
3847template<typename T> T FindMin(TTreeFormula *arr) {
3848 Int_t len = arr->GetNdata();
3849 T res = 0;
3850 if (len) {
3851 res = arr->EvalInstance<T>(0);
3852 for (int i=1; i<len; ++i) {
3853 T val = arr->EvalInstance<T>(i);
3854 if (val < res) {
3855 res = val;
3857 }
3858 }
3859 return res;
3860}
3861
3862template<typename T> T FindMax(TTreeFormula *arr) {
3863 Int_t len = arr->GetNdata();
3864 T res = 0;
3865 if (len) {
3866 res = arr->EvalInstance<T>(0);
3867 for (int i=1; i<len; ++i) {
3868 T val = arr->EvalInstance(i);
3869 if (val > res) {
3870 res = val;
3872 }
3873 }
3874 return res;
3875}
3876
3877template<typename T> T FindMin(TTreeFormula *arr, TTreeFormula *condition) {
3878 Int_t len = arr->GetNdata();
3879 T res = 0;
3880 if (len) {
3881 int i = 0;
3882 T condval;
3883 do {
3884 condval = condition->EvalInstance<T>(i);
3885 ++i;
3886 } while (!condval && i<len);
3887 if (!condval && i==len) {
3888 return 0;
3889 }
3890 if (i!=1) {
3891 // Insure the loading of the branch.
3892 arr->EvalInstance<T>(0);
3893 }
3894 // Now we know that i>0 && i<len and cond==true
3895 res = arr->EvalInstance<T>(i-1);
3896 for (; i<len; ++i) {
3897 condval = condition->EvalInstance<T>(i);
3898 if (condval) {
3899 T val = arr->EvalInstance<T>(i);
3900 if (val < res) {
3901 res = val;
3902 }
3904 }
3905 }
3906 return res;
3907}
3908
3909template<typename T> T FindMax(TTreeFormula *arr, TTreeFormula *condition) {
3910 Int_t len = arr->GetNdata();
3911 T res = 0;
3912 if (len) {
3913 int i = 0;
3914 T condval;
3915 do {
3916 condval = condition->EvalInstance<T>(i);
3917 ++i;
3918 } while (!condval && i<len);
3919 if (!condval && i==len) {
3920 return 0;
3921 }
3922 if (i!=1) {
3923 // Insure the loading of the branch.
3924 arr->EvalInstance<T>(0);
3925 }
3926 // Now we know that i>0 && i<len and cond==true
3927 res = arr->EvalInstance<T>(i-1);
3928 for (; i<len; ++i) {
3929 condval = condition->EvalInstance<T>(i);
3930 if (condval) {
3931 T val = arr->EvalInstance<T>(i);
3932 if (val > res) {
3933 res = val;
3934 }
3935 }
3936 }
3937 }
3938 return res;
3939}
3940
3941namespace {
3942
3943template <typename T> T fmod_local(T x, T y) { return fmod(x,y); }
3944template <> Long64_t fmod_local(Long64_t x, Long64_t y) { return fmod((LongDouble_t)x,(LongDouble_t)y); }
3946template<typename T> inline void SetMethodParam(TMethodCall *method, T p) { method->SetParam(p); }
3947template<> void SetMethodParam(TMethodCall *method, LongDouble_t p) { method->SetParam((Double_t)p); }
3948
3949}
3950
3951template<typename T> inline T TTreeFormula::GetConstant(Int_t k) { return fConst[k]; }
3952template<> inline LongDouble_t TTreeFormula::GetConstant(Int_t k) {
3953 if( !fConstLD ) {
3954 // create LD version of the constants list by rescanning all literals used in the expression
3956 for (Int_t op=0; op<fNoper ; ++op) {
3957 const Int_t oper = GetOper()[op];
3958 if( (oper >> kTFOperShift) == kConstant ) {
3959 int i = (oper & kTFOperMask);
3960 if( !strncmp(fExpr[op], "0x", 2) || !strncmp(fExpr[op], "0X", 2) ) {
3961 ULong64_t val;
3962 sscanf( fExpr[op], "%llx", &val );
3963 fConstLD[i] = (LongDouble_t)val;
3964 } else {
3965 sscanf( fExpr[op], "%Lg", &fConstLD[i] );
3967 }
3968 }
3969 }
3970 return fConstLD[k];
3971}
3973
3974////////////////////////////////////////////////////////////////////////////
3975/// \brief Evaluate this treeformula
3976/// \tparam T The type used to interpret the numbers then used for the operations
3977/// \param instance iteration instance
3978/// \param stringStackArg formula as string
3979/// \return the result of the evaluation
3980
3981template<typename T>
3983{
3984// Note that the redundancy and structure in this code is tailored to improve
3985// efficiencies.
3986 if (TestBit(kMissingLeaf)) return 0;
3987 if (fNoper == 1 && fNcodes > 0) {
3988
3989 switch (fLookupType[0]) {
3990 case kDirect: {
3992 return leaf->GetTypedValue<T>(real_instance);
3993 }
3994 case kMethod: {
3996 ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->SetBranch(leaf->GetBranch());
3997 return GetValueFromMethod(0,leaf);
3998 }
3999 case kDataMember: {
4001 ((TFormLeafInfo*)fDataMembers.UncheckedAt(0))->SetBranch(leaf->GetBranch());
4003 }
4004 case kTreeMember: {
4007 }
4008 case kIndexOfEntry: return (T)fTree->GetReadEntry();
4009 case kIndexOfLocalEntry: return (T)fTree->GetTree()->GetReadEntry();
4010 case kEntries: return (T)fTree->GetEntries();
4011 case kLocalEntries: return (T)fTree->GetTree()->GetEntries();
4012 case kLength: return fManager->fNdata;
4013 case kLengthFunc: return ((TTreeFormula*)fAliases.UncheckedAt(0))->GetNdata();
4014 case kIteration: return instance;
4015 case kSum: return Summing<T>((TTreeFormula*)fAliases.UncheckedAt(0));
4016 case kMin: return FindMin<T>((TTreeFormula*)fAliases.UncheckedAt(0));
4017 case kMax: return FindMax<T>((TTreeFormula*)fAliases.UncheckedAt(0));
4018 case kEntryList: {
4019 TEntryList *elist = (TEntryList*)fExternalCuts.At(0);
4020 return elist->Contains(fTree->GetTree()->GetReadEntry());
4021 }
4022 case -1: break;
4023 }
4024 switch (fCodes[0]) {
4025 case -2: {
4027 TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
4028 TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
4030 fx->ResetLoading();
4031 fy->ResetLoading();
4032 }
4033 T xcut = fx->EvalInstance<T>(instance);
4034 T ycut = fy->EvalInstance<T>(instance);
4035 return gcut->IsInside(xcut,ycut);
4036 }
4037 case -1: {
4039 TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
4041 fx->ResetLoading();
4042 }
4043 return fx->EvalInstance<T>(instance);
4044 }
4045 default: return 0;
4046 }
4047 }
4048
4049 T tab[kMAXFOUND];
4050 const Int_t kMAXSTRINGFOUND = 10;
4051 const char *stringStackLocal[kMAXSTRINGFOUND];
4053
4054 const bool willLoad = (instance==0 || fNeedLoading); fNeedLoading = false;
4055 if (willLoad) fDidBooleanOptimization = false;
4056
4057 Int_t pos = 0;
4058 Int_t pos2 = 0;
4059 for (Int_t i=0; i<fNoper ; ++i) {
4060
4061 const Int_t oper = GetOper()[i];
4062 const Int_t newaction = oper >> kTFOperShift;
4063
4065 // ROOT::v5::TFormula operands.
4066
4067 // one of the most used cases
4068 if (newaction==kConstant) { pos++; tab[pos-1] = GetConstant<T>(oper & kTFOperMask); continue; }
4069
4070 switch(newaction) {
4071
4072 case kEnd : return tab[0];
4073 case kAdd : pos--; tab[pos-1] += tab[pos]; continue;
4074 case kSubstract : pos--; tab[pos-1] -= tab[pos]; continue;
4075 case kMultiply : pos--; tab[pos-1] *= tab[pos]; continue;
4076 case kDivide : pos--; if (tab[pos] == 0) tab[pos-1] = 0; // division by 0
4077 else tab[pos-1] /= tab[pos];
4078 continue;
4079 case kModulo : {pos--;
4080 Long64_t int1((Long64_t)tab[pos-1]);
4081 Long64_t int2((Long64_t)tab[pos]);
4082 tab[pos-1] = T(int1 % int2);
4083 continue;}
4084
4085 case kcos : tab[pos-1] = TMath::Cos(tab[pos-1]); continue;
4086 case ksin : tab[pos-1] = TMath::Sin(tab[pos-1]); continue;
4087 case ktan : if (TMath::Cos(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
4088 else tab[pos-1] = TMath::Tan(tab[pos-1]);
4089 continue;
4090 case kacos : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
4091 else tab[pos-1] = TMath::ACos(tab[pos-1]);
4092 continue;
4093 case kasin : if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
4094 else tab[pos-1] = TMath::ASin(tab[pos-1]);
4095 continue;
4096 case katan : tab[pos-1] = TMath::ATan(tab[pos-1]); continue;
4097 case kcosh : tab[pos-1] = TMath::CosH(tab[pos-1]); continue;
4098 case ksinh : tab[pos-1] = TMath::SinH(tab[pos-1]); continue;
4099 case ktanh : if (TMath::CosH(tab[pos-1]) == 0) {tab[pos-1] = 0;} // { tangente indeterminee }
4100 else tab[pos-1] = TMath::TanH(tab[pos-1]);
4101 continue;
4102 case kacosh: if (tab[pos-1] < 1) {tab[pos-1] = 0;} // indetermination
4103 else tab[pos-1] = TMath::ACosH(tab[pos-1]);
4104 continue;
4105 case kasinh: tab[pos-1] = TMath::ASinH(tab[pos-1]); continue;
4106 case katanh: if (TMath::Abs(tab[pos-1]) > 1) {tab[pos-1] = 0;} // indetermination
4107 else tab[pos-1] = TMath::ATanH(tab[pos-1]);
4108 continue;
4109 case katan2: pos--; tab[pos-1] = TMath::ATan2(tab[pos-1],tab[pos]); continue;
4110
4111 case kfmod : pos--; tab[pos-1] = fmod_local(tab[pos-1],tab[pos]); continue;
4112 case kpow : pos--; tab[pos-1] = TMath::Power(tab[pos-1],tab[pos]); continue;
4113 case ksq : tab[pos-1] = tab[pos-1]*tab[pos-1]; continue;
4114 case ksqrt : tab[pos-1] = TMath::Sqrt(TMath::Abs(tab[pos-1])); continue;
4115
4116 case kstrstr : pos2 -= 2; pos++;if (strstr(stringStack[pos2],stringStack[pos2+1])) tab[pos-1]=1;
4117 else tab[pos-1]=0;
4118 continue;
4119
4120 case kmin : pos--; tab[pos-1] = std::min(tab[pos-1],tab[pos]); continue;
4121 case kmax : pos--; tab[pos-1] = std::max(tab[pos-1],tab[pos]); continue;
4122
4123 case klog : if (tab[pos-1] > 0) tab[pos-1] = TMath::Log(tab[pos-1]);
4124 else {tab[pos-1] = 0;} //{indetermination }
4125 continue;
4126 case kexp : { Double_t dexp = tab[pos-1];
4127 if (dexp < -700) {tab[pos-1] = 0; continue;}
4128 if (dexp > 700) {tab[pos-1] = TMath::Exp(700); continue;}
4129 tab[pos-1] = TMath::Exp(dexp); continue;
4130 }
4131 case klog10: if (tab[pos-1] > 0) tab[pos-1] = TMath::Log10(tab[pos-1]);
4132 else {tab[pos-1] = 0;} //{indetermination }
4133 continue;
4134
4135 case kpi : pos++; tab[pos-1] = TMath::Pi(); continue;
4136
4137 case kabs : tab[pos-1] = TMath::Abs(tab[pos-1]); continue;
4138 case ksign : if (tab[pos-1] < 0) tab[pos-1] = -1; else tab[pos-1] = 1;
4139 continue;
4140 case kint : tab[pos-1] = T(Long64_t(tab[pos-1])); continue;
4141 case kSignInv: tab[pos-1] = -1 * tab[pos-1]; continue;
4142 case krndm : pos++; tab[pos-1] = gRandom->Rndm(); continue;
4143
4144 case kAnd : pos--; if (tab[pos-1]!=0 && tab[pos]!=0) tab[pos-1]=1;
4145 else tab[pos-1]=0;
4146 continue;
4147 case kOr : pos--; if (tab[pos-1]!=0 || tab[pos]!=0) tab[pos-1]=1;
4148 else tab[pos-1]=0;
4149 continue;
4150
4151 case kEqual : pos--; tab[pos-1] = (tab[pos-1] == tab[pos]) ? 1 : 0; continue;
4152 case kNotEqual : pos--; tab[pos-1] = (tab[pos-1] != tab[pos]) ? 1 : 0; continue;
4153 case kLess : pos--; tab[pos-1] = (tab[pos-1] < tab[pos]) ? 1 : 0; continue;
4154 case kGreater : pos--; tab[pos-1] = (tab[pos-1] > tab[pos]) ? 1 : 0; continue;
4155 case kLessThan : pos--; tab[pos-1] = (tab[pos-1] <= tab[pos]) ? 1 : 0; continue;
4156 case kGreaterThan: pos--; tab[pos-1] = (tab[pos-1] >= tab[pos]) ? 1 : 0; continue;
4157 case kNot : tab[pos-1] = (tab[pos-1] != 0) ? 0 : 1; continue;
4158
4159 case kStringEqual : pos2 -= 2; pos++; if (!strcmp(stringStack[pos2+1],stringStack[pos2])) tab[pos-1]=1;
4160 else tab[pos-1]=0;
4161 continue;
4162 case kStringNotEqual: pos2 -= 2; pos++;if (strcmp(stringStack[pos2+1],stringStack[pos2])) tab[pos-1]=1;
4163 else tab[pos-1]=0;
4164 continue;
4165
4166 case kBitAnd : pos--; tab[pos-1]= ((ULong64_t) tab[pos-1]) & ((ULong64_t) tab[pos]); continue;
4167 case kBitOr : pos--; tab[pos-1]= ((ULong64_t) tab[pos-1]) | ((ULong64_t) tab[pos]); continue;
4168 case kLeftShift : pos--; tab[pos-1]= ((ULong64_t) tab[pos-1]) <<((ULong64_t) tab[pos]); continue;
4169 case kRightShift: pos--; tab[pos-1]= ((ULong64_t) tab[pos-1]) >>((ULong64_t) tab[pos]); continue;
4170
4171 case kJump : i = (oper & kTFOperMask); continue;
4172 case kJumpIf : {
4173 pos--;
4174 if (!tab[pos]) {
4175 i = (oper & kTFOperMask);
4176 // If we skip the left (true) side of the if statement we may,
4177 // skip some of the branch loading (since we remove duplicate branch
4178 // request (in TTreeFormula constructor) and so we need to force the
4179 // loading here.
4181 }
4182 continue;
4183 }
4184
4185 case kStringConst: {
4186 // String
4187 pos2++; stringStack[pos2-1] = (char*)fExpr[i].Data();
4188 if (fAxis) {
4189 // See TT_EVAL_INIT
4190 Int_t bin = fAxis->FindBin(stringStack[pos2-1]);
4191 return bin;
4192 }
4193 continue;
4194 }
4195
4196 case kBoolOptimize: {
4197 // boolean operation optimizer
4198
4199 int param = (oper & kTFOperMask);
4200 bool skip = false;
4201 int op = param % 10; // 1 is && , 2 is ||
4202
4203 if (op == 1 && (!tab[pos-1]) ) {
4204 // &&: skip the right part if the left part is already false
4205
4206 skip = true;
4207
4208 // Preserve the existing behavior (i.e. the result of a&&b is
4209 // either 0 or 1)
4210 tab[pos-1] = 0;
4211
4212 } else if (op == 2 && tab[pos-1] ) {
4213 // ||: skip the right part if the left part is already true
4214
4215 skip = true;
4216
4217 // Preserve the existing behavior (i.e. the result of a||b is
4218 // either 0 or 1)
4219 tab[pos-1] = 1;
4220 }
4221
4222 if (skip) {
4223 int toskip = param / 10;
4224 i += toskip;
4226 }
4227 continue;
4228 }
4229
4230 case kFunctionCall: {
4231 // an external function call
4232
4233 int param = (oper & kTFOperMask);
4234 int fno = param / 1000;
4235 int nargs = param % 1000;
4236
4237 // Retrieve the function
4239
4240 // Set the arguments
4241 method->ResetParam();
4242 if (nargs) {
4243 UInt_t argloc = pos-nargs;
4244 for(Int_t j=0;j<nargs;j++,argloc++,pos--) {
4246 }
4247 }
4248 pos++;
4249 Double_t ret = 0;
4250 method->Execute(ret);
4251 tab[pos-1] = ret; // check for the correct conversion!
4252
4253 continue;
4254 }
4255
4256// case kParameter: { pos++; tab[pos-1] = fParams[(oper & kTFOperMask)]; continue; }
4257 }
4258
4259 } else {
4260 // TTreeFormula operands.
4261
4262 // a tree variable (the most used case).
4263
4264 if (newaction == kDefinedVariable) {
4265
4266 const Int_t code = (oper & kTFOperMask);
4267 const Int_t lookupType = fLookupType[code];
4268 switch (lookupType) {
4269 case kIndexOfEntry: tab[pos++] = (T)fTree->GetReadEntry(); continue;
4270 case kIndexOfLocalEntry: tab[pos++] = (T)fTree->GetTree()->GetReadEntry(); continue;
4271 case kEntries: tab[pos++] = (T)fTree->GetEntries(); continue;
4272 case kLocalEntries: tab[pos++] = (T)fTree->GetTree()->GetEntries(); continue;
4273 case kLength: tab[pos++] = fManager->fNdata; continue;
4274 case kLengthFunc: tab[pos++] = ((TTreeFormula*)fAliases.UncheckedAt(i))->GetNdata(); continue;
4275 case kIteration: tab[pos++] = instance; continue;
4276 case kSum: tab[pos++] = Summing<T>((TTreeFormula*)fAliases.UncheckedAt(i)); continue;
4277 case kMin: tab[pos++] = FindMin<T>((TTreeFormula*)fAliases.UncheckedAt(i)); continue;
4278 case kMax: tab[pos++] = FindMax<T>((TTreeFormula*)fAliases.UncheckedAt(i)); continue;
4279
4280 case kDirect: { TT_EVAL_INIT_LOOP; tab[pos++] = leaf->GetTypedValue<T>(real_instance); continue; }
4281 case kMethod: { TT_EVAL_INIT_LOOP; tab[pos++] = GetValueFromMethod(code,leaf); continue; }
4283 GetTypedValue<T>(leaf,real_instance); continue; }
4285 GetTypedValue<T>((TLeaf*)nullptr,real_instance); continue; }
4286 case kEntryList: { TEntryList *elist = (TEntryList*)fExternalCuts.At(code);
4287 tab[pos++] = elist->Contains(fTree->GetReadEntry());
4288 continue;}
4289 case -1: break;
4290 default: tab[pos++] = 0; continue;
4291 }
4292 switch (fCodes[code]) {
4293 case -2: {
4294 TCutG *gcut = (TCutG*)fExternalCuts.At(code);
4295 TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
4296 TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
4298 fx->ResetLoading();
4299 fy->ResetLoading();
4300 }
4301 T xcut = fx->EvalInstance<T>(instance);
4302 T ycut = fy->EvalInstance<T>(instance);
4303 tab[pos++] = gcut->IsInside(xcut,ycut);
4304 continue;
4305 }
4306 case -1: {
4307 TCutG *gcut = (TCutG*)fExternalCuts.At(code);
4308 TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
4310 fx->ResetLoading();
4311 }
4312 tab[pos++] = fx->EvalInstance<T>(instance);
4313 continue;
4314 }
4315 default: {
4316 tab[pos++] = 0;
4317 continue;
4318 }
4319 }
4320 }
4321 switch(newaction) {
4322
4323 // a TTree Variable Alias (i.e. a sub-TTreeFormula)
4324 case kAlias: {
4325 int aliasN = i;
4328
4329 subform->fDidBooleanOptimization = fDidBooleanOptimization;
4330 T param = subform->EvalInstance<T>(instance);
4331
4332 tab[pos] = param; pos++;
4333 continue;
4334 }
4335 // a TTree Variable Alias String (i.e. a sub-TTreeFormula)
4336 case kAliasString: {
4337 int aliasN = i;
4340
4341 pos2++;
4342 subform->fDidBooleanOptimization = fDidBooleanOptimization;
4343 stringStack[pos2-1] = subform->EvalStringInstance(instance);
4344 continue;
4345 }
4346 case kMinIf: {
4347 int alternateN = i;
4350 T param = FindMin<T>(primary,condition);
4351 ++i; // skip the place holder for the condition
4352 tab[pos] = param; pos++;
4353 continue;
4354 }
4355 case kMaxIf: {
4356 int alternateN = i;
4359 T param = FindMax<T>(primary,condition);
4360 ++i; // skip the place holder for the condition
4361 tab[pos] = param; pos++;
4362 continue;
4363 }
4364
4365 // a TTree Variable Alternate (i.e. a sub-TTreeFormula)
4366 case kAlternate: {
4367 int alternateN = i;
4369
4370 // First check whether we are in range for the primary formula
4372
4373 T param = primary->EvalInstance<T>(instance);
4374
4375 ++i; // skip the alternate value.
4376
4377 tab[pos] = param; pos++;
4378 } else {
4379 // The primary is not in range, we will calculate the alternate value
4380 // via the next operation (which will be a intentional).
4381
4382 // kAlias no operations
4383 }
4384 continue;
4385 }
4386 case kAlternateString: {
4387 int alternateN = i;
4389
4390 // First check whether we are in range for the primary formula
4392
4393 pos2++;
4394 stringStack[pos2-1] = primary->EvalStringInstance(instance);
4395
4396 ++i; // skip the alternate value.
4397
4398 } else {
4399 // The primary is not in range, we will calculate the alternate value
4400 // via the next operation (which will be a kAlias).
4401
4402 // intentional no operations
4403 }
4404 continue;
4405 }
4406
4407 // a tree string
4408 case kDefinedString: {
4411
4412 // Now let calculate what physical instance we really need.
4414
4415 if (instance==0 || fNeedLoading) {
4416 fNeedLoading = false;
4417 TBranch *branch = leafc->GetBranch();
4418 Long64_t readentry = branch->GetTree()->GetReadEntry();
4420 } else {
4421 // In the cases where we are behind (i.e. right of) a potential boolean optimization
4422 // this tree variable reading may have not been executed with instance==0 which would
4423 // result in the branch being potentially not read in.
4425 TBranch *br = leafc->GetBranch();
4426 Long64_t treeEntry = br->GetTree()->GetReadEntry();
4428 }
4429 if (real_instance>=fNdata[string_code]) return 0;
4430 }
4431 pos2++;
4433 stringStack[pos2-1] = (char*)leafc->GetValuePointer();
4434 } else {
4436 }
4437 continue;
4438 }
4439
4440 }
4441 }
4442
4443 R__ASSERT(i<fNoper);
4444 }
4445
4446 //std::cout << __PRETTY_FUNCTION__ << " returning " << tab[0] << std::endl;
4447 return tab[0];
4448}
4449
4450// Template instantiations
4451template double TTreeFormula::EvalInstance<double> (int, char const**);
4452template long double TTreeFormula::EvalInstance<long double> (int, char const**);
4453template long long TTreeFormula::EvalInstance<long long> (int, char const**);
4454
4455////////////////////////////////////////////////////////////////////////////////
4456/// Return DataMember corresponding to code.
4457///
4458/// function called by TLeafObject::GetValue
4459/// with the value of fLookupType computed in TTreeFormula::DefinedVariable
4460
4462{
4463 return (TFormLeafInfo *)fDataMembers.UncheckedAt(code);
4465}
4466
4467////////////////////////////////////////////////////////////////////////////////
4468/// Return leaf corresponding to serial number n.
4469
4471{
4472 return (TLeaf*)fLeaves.UncheckedAt(n);
4473}
4474
4475////////////////////////////////////////////////////////////////////////////////
4476/// Return methodcall corresponding to code.
4477///
4478/// function called by TLeafObject::GetValue
4479/// with the value of fLookupType computed in TTreeFormula::DefinedVariable
4480
4482{
4483 return (TMethodCall *)fMethods.UncheckedAt(code);
4485}
4486
4487////////////////////////////////////////////////////////////////////////////////
4488/// Return number of available instances in the formula.
4489
4491{
4493}
4494
4495////////////////////////////////////////////////////////////////////////////////
4496/// Return result of a leafobject method.
4497
4499{
4501
4502 if (!m) {
4503 return 0.0;
4504 }
4505
4506 void* thisobj = nullptr;
4507 if (leaf->InheritsFrom(TLeafObject::Class())) {
4508 thisobj = ((TLeafObject*) leaf)->GetObject();
4509 } else {
4510 TBranchElement* branch = (TBranchElement*) ((TLeafElement*) leaf)->GetBranch();
4511 Int_t id = branch->GetID();
4512 // FIXME: This is wrong for a top-level branch.
4513 Int_t offset = 0;
4514 if (id > -1) {
4515 TStreamerInfo* info = branch->GetInfo();
4516 if (info) {
4517 offset = info->GetElementOffset(id);
4518 } else {
4519 Warning("GetValueFromMethod", "No streamer info for branch %s.", branch->GetName());
4520 }
4521 }
4522 if (id < 0) {
4523 char* address = branch->GetObject();
4524 thisobj = address;
4525 } else {
4526 //char* address = branch->GetAddress();
4527 char* address = branch->GetObject();
4528 if (address) {
4529 thisobj = *((char**) (address + offset));
4530 } else {
4531 // FIXME: If the address is not set, the object won't be either!
4532 thisobj = branch->GetObject();
4533 }
4534 }
4535 }
4536
4537 TMethodCall::EReturnType r = m->ReturnType();
4538
4539 if (r == TMethodCall::kLong) {
4540 Longptr_t l = 0;
4541 m->Execute(thisobj, l);
4542 return (Double_t) l;
4543 }
4544
4545 if (r == TMethodCall::kDouble) {
4546 Double_t d = 0.0;
4547 m->Execute(thisobj, d);
4548 return d;
4549 }
4550
4551 m->Execute(thisobj);
4552
4553 return 0;
4554}
4555
4556////////////////////////////////////////////////////////////////////////////////
4557/// Return result of a leafobject method.
4558
4560{
4562
4563 if (!m) {
4564 return nullptr;
4565 }
4566
4567 void* thisobj;
4568 if (leaf->InheritsFrom(TLeafObject::Class())) {
4569 thisobj = ((TLeafObject*) leaf)->GetObject();
4570 } else {
4571 TBranchElement* branch = (TBranchElement*) ((TLeafElement*) leaf)->GetBranch();
4572 Int_t id = branch->GetID();
4573 Int_t offset = 0;
4574 if (id > -1) {
4575 TStreamerInfo* info = branch->GetInfo();
4576 if (info) {
4577 offset = info->GetElementOffset(id);
4578 } else {
4579 Warning("GetValuePointerFromMethod", "No streamer info for branch %s.", branch->GetName());
4580 }
4581 }
4582 if (id < 0) {
4583 char* address = branch->GetObject();
4584 thisobj = address;
4585 } else {
4586 //char* address = branch->GetAddress();
4587 char* address = branch->GetObject();
4588 if (address) {
4589 thisobj = *((char**) (address + offset));
4590 } else {
4591 // FIXME: If the address is not set, the object won't be either!
4592 thisobj = branch->GetObject();
4593 }
4594 }
4595 }
4596
4597 TMethodCall::EReturnType r = m->ReturnType();
4598
4599 if (r == TMethodCall::kLong) {
4600 Longptr_t l = 0;
4601 m->Execute(thisobj, l);
4602 return nullptr;
4603 }
4604
4605 if (r == TMethodCall::kDouble) {
4606 Double_t d = 0.0;
4607 m->Execute(thisobj, d);
4608 return nullptr;
4609 }
4610
4611 if (r == TMethodCall::kOther) {
4612 char* c = nullptr;
4613 m->Execute(thisobj, &c);
4614 return c;
4615 }
4616
4617 m->Execute(thisobj);
4618
4619 return nullptr;
4620}
4621
4622////////////////////////////////////////////////////////////////////////////////
4623/// Return TRUE if the formula corresponds to one single Tree leaf
4624/// and this leaf is short, int or unsigned short, int
4625/// When a leaf is of type integer or string, the generated histogram is forced
4626/// to have an integer bin width
4627
4628bool TTreeFormula::IsInteger(bool fast) const
4629{
4630 if (fast) {
4631 if (TestBit(kIsInteger)) return true;
4632 else return false;
4633 }
4634
4635 if (fNoper==2 && GetAction(0)==kAlternate) {
4638 return subform->IsInteger(false);
4639 }
4640
4641 if (GetAction(0)==kMinIf || GetAction(0)==kMaxIf) {
4642 return false;
4643 }
4644
4645 if (fNoper > 1) return false;
4646
4647 if (GetAction(0)==kAlias) {
4650 return subform->IsInteger(false);
4651 }
4652
4653 if (fLeaves.GetEntries() != 1) {
4654 switch (fLookupType[0]) {
4655 case kIndexOfEntry:
4656 case kIndexOfLocalEntry:
4657 case kEntries:
4658 case kLocalEntries:
4659 case kLength:
4660 case kLengthFunc:
4661 case kIteration:
4662 return true;
4663 case kSum:
4664 case kMin:
4665 case kMax:
4666 case kEntryList:
4667 default:
4668 return false;
4669 }
4670 }
4671
4672 if (EvalClass()==TBits::Class()) return true;
4673
4674 if (IsLeafInteger(0) || IsLeafString(0)) return true;
4675 return false;
4676}
4678////////////////////////////////////////////////////////////////////////////////
4679/// Return TRUE if the leaf corresponding to code is short, int or unsigned
4680/// short, int When a leaf is of type integer, the generated histogram is
4681/// forced to have an integer bin width
4682
4683bool TTreeFormula::IsLeafInteger(Int_t code) const
4684{
4685 TLeaf *leaf = (TLeaf*)fLeaves.At(code);
4686 if (!leaf) {
4687 switch (fLookupType[code]) {
4688 case kIndexOfEntry:
4689 case kIndexOfLocalEntry:
4690 case kEntries:
4691 case kLocalEntries:
4692 case kLength:
4693 case kLengthFunc:
4694 case kIteration:
4695 return true;
4696 case kSum:
4697 case kMin:
4698 case kMax:
4699 case kEntryList:
4700 default:
4701 return false;
4702 }
4703 }
4704 if (fAxis) return true;
4706 switch (fLookupType[code]) {
4707 case kMethod:
4708 case kTreeMember:
4709 case kDataMember:
4710 info = GetLeafInfo(code);
4711 return info->IsInteger();
4712 case kDirect:
4713 break;
4714 }
4715 if (!strcmp(leaf->GetTypeName(),"Int_t")) return true;
4716 if (!strcmp(leaf->GetTypeName(),"Short_t")) return true;
4717 if (!strcmp(leaf->GetTypeName(),"UInt_t")) return true;
4718 if (!strcmp(leaf->GetTypeName(),"UShort_t")) return true;
4719 if (!strcmp(leaf->GetTypeName(),"Bool_t")) return true;
4720 if (!strcmp(leaf->GetTypeName(),"Char_t")) return true;
4721 if (!strcmp(leaf->GetTypeName(),"UChar_t")) return true;
4722 if (!strcmp(leaf->GetTypeName(),"Long64_t")) return true;
4723 if (!strcmp(leaf->GetTypeName(),"ULong64_t")) return true;
4724 if (!strcmp(leaf->GetTypeName(),"string")) return true;
4725 return false;
4726}
4727
4728////////////////////////////////////////////////////////////////////////////////
4729/// Return TRUE if the formula is a string
4730
4731bool TTreeFormula::IsString() const
4732{
4733 // See TTreeFormula::Init for the setting of kIsCharacter.
4734 return TestBit(kIsCharacter);
4736
4737////////////////////////////////////////////////////////////////////////////////
4738/// Return true if the expression at the index 'oper' is to be treated as
4739/// as string.
4740
4742{
4743 if (ROOT::v5::TFormula::IsString(oper)) return true;
4744 if (GetAction(oper)==kDefinedString) return true;
4745 if (GetAction(oper)==kAliasString) return true;
4746 if (GetAction(oper)==kAlternateString) return true;
4747 return false;
4748}
4749
4750////////////////////////////////////////////////////////////////////////////////
4751/// Return TRUE if the leaf or data member corresponding to code is a string
4752
4753bool TTreeFormula::IsLeafString(Int_t code) const
4754{
4755 TLeaf *leaf = (TLeaf*)fLeaves.At(code);
4757 if (fLookupType[code]==kTreeMember) {
4758 info = GetLeafInfo(code);
4759 return info->IsString();
4760 }
4761
4762 switch(fLookupType[code]) {
4763 case kDirect:
4764 if ( !leaf->IsUnsigned() && (leaf->InheritsFrom(TLeafC::Class()) || leaf->InheritsFrom(TLeafB::Class()) ) ) {
4765 // Need to find out if it is an 'array' or a pointer.
4766 if (leaf->GetLenStatic() > 1) return true;
4767
4768 // Now we need to differentiate between a variable length array and
4769 // a TClonesArray.
4770 if (leaf->GetLeafCount()) {
4771 const char* indexname = leaf->GetLeafCount()->GetName();
4772 if (indexname[strlen(indexname)-1] == '_' ) {
4773 // This in a clones array
4774 return false;
4775 } else {
4776 // this is a variable length char array
4777 return true;
4778 }
4779 }
4780 return false;
4781 } else if (leaf->InheritsFrom(TLeafElement::Class())) {
4782 TBranchElement * br = (TBranchElement*)leaf->GetBranch();
4783 Int_t bid = br->GetID();
4784 if (bid < 0) return false;
4785 if (br->GetInfo()==nullptr || !br->GetInfo()->IsCompiled()) {
4786 // Case where the file is corrupted is some ways.
4787 // We can not get to the actual type of the data
4788 // let's assume it is NOT a string.
4789 return false;
4790 }
4791 TStreamerElement * elem = (TStreamerElement*) br->GetInfo()->GetElement(bid);
4792 if (!elem) {
4793 // Case where the file is corrupted is some ways.
4794 // We can not get to the actual type of the data
4795 // let's assume it is NOT a string.
4796 return false;
4797 }
4798 if (elem->GetNewType() == TStreamerInfo::kOffsetL + TStreamerInfo::kChar) {
4799 // Check whether a specific element of the string is specified!
4800 if (fIndexes[code][fNdimensions[code]-1] != -1) return false;
4801 return true;
4802 }
4803 if ( elem->GetNewType() == TStreamerInfo::kCharStar) {
4804 // Check whether a specific element of the string is specified!
4805 if (fNdimensions[code] && fIndexes[code][fNdimensions[code]-1] != -1) return false;
4806 return true;
4807 }
4808 return false;
4809 } else {
4810 return false;
4811 }
4812 case kMethod:
4813 //TMethodCall *m = GetMethodCall(code);
4814 //TMethodCall::EReturnType r = m->ReturnType();
4815 return false;
4816 case kDataMember:
4817 info = GetLeafInfo(code);
4818 return info->IsString();
4819 default:
4820 return false;
4821 }
4822}
4823
4824////////////////////////////////////////////////////////////////////////////////
4825/// Return value of variable as a string
4826///
4827/// - mode = -2 : Print line with ***
4828/// - mode = -1 : Print column names
4829/// - mode = 0 : Print column values
4830
4832{
4833 return PrintValue(mode,0);
4834}
4835
4836////////////////////////////////////////////////////////////////////////////////
4837/// Return value of variable as a string
4838///
4839/// - mode = -2 : Print line with ***
4840/// - mode = -1 : Print column names
4841/// - mode = 0 : Print column values
4842///
4843/// decform contains the requested format (with the same convention as printf).
4844
4845char *TTreeFormula::PrintValue(Int_t mode, Int_t instance, const char *decform) const
4846{
4847 const int kMAXLENGTH = kMaxLen;
4848 static char value[kMAXLENGTH];
4849
4850 if (mode == -2) {
4851 for (int i = 0; i < kMAXLENGTH-1; i++)
4852 value[i] = '*';
4853 value[kMAXLENGTH-1] = 0;
4854 } else if (mode == -1) {
4855 snprintf(value, kMAXLENGTH-1, "%s", GetTitle());
4856 } else if (mode == 0) {
4857 if ( (fNstring && fNval==0 && fNoper==1) || IsString() )
4858 {
4859 const char * val = nullptr;
4860 if (GetAction(0)==kStringConst) {
4861 val = fExpr[0].Data();
4862 } else if (instance<fNdata[0]) {
4863 if (fNoper == 1) {
4864 if (fLookupType[0]==kTreeMember) {
4865 val = (char*)GetLeafInfo(0)->GetValuePointer((TLeaf*)nullptr,instance);
4866 } else {
4868 TBranch *branch = leaf->GetBranch();
4869 Long64_t readentry = branch->GetTree()->GetReadEntry();
4871 if (fLookupType[0]==kDirect && fNoper==1) {
4872 val = (const char*)leaf->GetValuePointer();
4873 } else {
4874 val = ((TTreeFormula*)this)->EvalStringInstance(instance);
4875 }
4876 }
4877 } else {
4878 val = ((TTreeFormula*)this)->EvalStringInstance(instance);
4879 }
4880 }
4881 if (val) {
4882 strlcpy(value, val, kMAXLENGTH);
4883 } else {
4884 value[0] = '\0';
4885 }
4886 value[kMAXLENGTH-1] = 0;
4887 } else {
4888 //NOTE: This is terrible form ... but is forced upon us by the fact that we can not
4889 //use the mutable keyword AND we should keep PrintValue const.
4890 Int_t real_instance = ((TTreeFormula*)this)->GetRealInstance(instance,-1);
4891 if (real_instance<fNdata[0]) {
4894 char *expo = nullptr;
4895 if (len>2) {
4896 switch (decform[len-2]) {
4897 case 'l':
4898 case 'L': {
4899 outputSizeLevel = 2;
4900 if (len>3 && tolower(decform[len-3])=='l') {
4901 outputSizeLevel = 3;
4902 }
4903 break;
4904 }
4905 case 'h': outputSizeLevel = 0; break;
4906 }
4907 }
4908 switch(decform[len-1]) {
4909 case 'c':
4910 case 'd':
4911 case 'i':
4912 {
4913 switch (outputSizeLevel) {
4914 case 0: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Short_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4915 case 2: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Long_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4917 case 1:
4918 default: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(Int_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4919 }
4920 break;
4921 }
4922 case 'o':
4923 case 'x':
4924 case 'X':
4925 case 'u':
4926 {
4927 switch (outputSizeLevel) {
4928 case 0: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(UShort_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4929 case 2: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(ULong_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4931 case 1:
4932 default: snprintf(value,kMAXLENGTH,Form("%%%s",decform),(UInt_t)((TTreeFormula*)this)->EvalInstance(instance)); break;
4933 }
4934 break;
4935 }
4936 case 'f':
4937 case 'e':
4938 case 'E':
4939 case 'g':
4940 case 'G':
4941 {
4942 switch (outputSizeLevel) {
4944 case 1:
4945 default: snprintf(value,kMAXLENGTH,Form("%%%s",decform),((TTreeFormula*)this)->EvalInstance(instance)); break;
4946 }
4947 expo = strchr(value,'e');
4948 break;
4949 }
4950 default:
4952 expo = strchr(value,'e');
4953 }
4954 if (expo) {
4955 // If there is an exponent we may be longer than planned.
4956 // so let's trim off the excess precision!
4957 UInt_t declen = atoi(decform);
4958 if (strlen(value)>declen) {
4959 UInt_t off = strlen(value)-declen;
4960 char *start = expo - off;
4962 for(UInt_t z=0;z<=vlen;++z) {
4963 start[z] = expo[z];
4964 }
4965 //strcpy(expo-off,expo);
4966 }
4967 }
4968 } else {
4969 if (isalpha(decform[strlen(decform)-1])) {
4971 short_decform.Remove(short_decform.Length()-1);
4972 snprintf(value,kMAXLENGTH,Form(" %%%sc",short_decform.Data()),' ');
4973 } else {
4974 snprintf(value,kMAXLENGTH,Form(" %%%sc",decform),' ');
4975 }
4976
4977 }
4978 }
4979 }
4980 return &value[0];
4981}
4982
4983////////////////////////////////////////////////////////////////////////////////
4984/// Tell the formula that we are going to request a new entry.
4985
4987{
4988 fNeedLoading = true;
4990
4991 for(Int_t i=0; i<fNcodes; ++i) {
4992 UInt_t max_dim = fNdimensions[i];
4993 for(UInt_t dim=0; dim<max_dim ;++dim) {
4994 if (fVarIndexes[i][dim]) {
4995 fVarIndexes[i][dim]->ResetLoading();
4996 }
4997 }
4998 }
4999 Int_t n = fAliases.GetLast();
5000 if ( fNoper < n ) {
5001 n = fNoper;
5002 }
5003 for(Int_t k=0; k <= n; ++k) {
5004 TTreeFormula *f = static_cast<TTreeFormula*>(fAliases.UncheckedAt(k));
5005 if (f) {
5006 f->ResetLoading();
5007 }
5008 }
5009 for (int i=0; i<fExternalCuts.GetSize(); i++) {
5010 auto c = dynamic_cast<TCutG*>(fExternalCuts.At(i));
5011 if (c) {
5012 ((TTreeFormula *)(c->GetObjectX()))->ResetLoading();
5013 ((TTreeFormula *)(c->GetObjectY()))->ResetLoading();
5014 }
5015 }
5019}
5020
5021////////////////////////////////////////////////////////////////////////////////
5022/// Set the axis (in particular get the type).
5023
5024void TTreeFormula::SetAxis(TAxis *axis)
5025{
5026 if (!axis) {fAxis = nullptr; return;}
5027 if (IsString()) {
5028 fAxis = axis;
5029 if (fNoper==1 && GetAction(0)==kAliasString){
5032 subform->SetAxis(axis);
5033 } else if (fNoper==2 && GetAction(0)==kAlternateString){
5036 subform->SetAxis(axis);
5037 }
5038 // Since the bin are corresponding to 'string', we currently must also set
5039 // the axis to align the bins exactly on integer boundaries.
5041 } else if (IsInteger()) {
5044}
5045
5046////////////////////////////////////////////////////////////////////////////////
5047/// Stream an object of class TTreeFormula.
5048
5050{
5051 if (R__b.IsReading()) {
5052 UInt_t R__s, R__c;
5053 Version_t R__v = R__b.ReadVersion(&R__s, &R__c);
5054 if (R__v > 2) {
5055 R__b.ReadClassBuffer(TTreeFormula::Class(), this, R__v, R__s, R__c);
5056 return;
5057 }
5058 //====process old versions before automatic schema evolution
5060 R__b >> fTree;
5061 R__b >> fNcodes;
5062 R__b.ReadFastArray(fCodes, fNcodes);
5065 R__b >> instance; //data member removed
5066 R__b >> fNindex;
5067 if (fNindex) {
5068 fLookupType = new Int_t[fNindex];
5069 R__b.ReadFastArray(fLookupType, fNindex);
5070 }
5072 //====end of old versions
5073
5074 } else {
5075 R__b.WriteClassBuffer(TTreeFormula::Class(),this);
5076 }
5078
5079////////////////////////////////////////////////////////////////////////////////
5080/// Try to 'demote' a string into an array bytes. If this is not possible,
5081/// return false.
5082
5084{
5085 Int_t code = GetActionParam(oper);
5087 if (oper>0 && GetAction(oper-1)==kJump) {
5088 // We are the second hand of a ternary operator, let's not do the fixing.
5089 return false;
5090 }
5091 TLeaf *leaf = (TLeaf*)fLeaves.At(code);
5092 if (leaf && (leaf->InheritsFrom(TLeafC::Class()) || leaf->InheritsFrom(TLeafB::Class()) ) ) {
5094 fNval++;
5095 fNstring--;
5096 return true;
5097 }
5098 }
5099 return false;
5100}
5101
5102
5103////////////////////////////////////////////////////////////////////////////////
5104/// This function is called TTreePlayer::UpdateFormulaLeaves, itself
5105/// called by TChain::LoadTree when a new Tree is loaded.
5106/// Because Trees in a TChain may have a different list of leaves, one
5107/// must update the leaves numbers in the TTreeFormula used by the TreePlayer.
5108///
5109/// A safer alternative would be to recompile the whole thing .... However
5110/// currently compile HAS TO be called from the constructor!
5111
5113{
5116 for (Int_t i=0;i<nleaves;i++) {
5117 if (!fTree) break;
5118 if (!fLeafNames[i]) continue;
5119
5121 fLeaves[i] = leaf;
5122 if (fBranches[i] && leaf) {
5123 fBranches[i] = leaf->GetBranch();
5124 // Since sometimes we might no read all the branches for all the entries, we
5125 // might sometimes only read the branch count and thus reset the collection
5126 // but might not read the data branches, to insure that a subsequent read
5127 // from TTreeFormula will properly load the data branches even if fQuickLoad is true,
5128 // we reset the entry of all branches in the TTree.
5129 ((TBranch*)fBranches[i])->ResetReadEntry();
5130 }
5131 if (leaf==nullptr) SetBit( kMissingLeaf );
5132 }
5133 for (Int_t j=0; j<kMAXCODES; j++) {
5134 for (Int_t k = 0; k<kMAXFORMDIM; k++) {
5135 if (fVarIndexes[j][k]) {
5137 }
5138 }
5140 if (j<fNval && fCodes[j]<0) {
5142 if (gcut) {
5143 TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
5144 TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
5145 if (fx) fx->UpdateFormulaLeaves();
5146 if (fy) fy->UpdateFormulaLeaves();
5147 }
5148 }
5149 }
5150 for(Int_t k=0;k<fNoper;k++) {
5151 const Int_t oper = GetOper()[k];
5152 switch(oper >> kTFOperShift) {
5153 case kAlias:
5154 case kAliasString:
5155 case kAlternate:
5156 case kAlternateString:
5157 case kMinIf:
5158 case kMaxIf:
5159 {
5162 subform->UpdateFormulaLeaves();
5163 break;
5164 }
5165 case kDefinedVariable:
5166 {
5167 Int_t code = GetActionParam(k);
5168 if (fCodes[code]==0) switch(fLookupType[code]) {
5169 case kLengthFunc:
5170 case kSum:
5171 case kMin:
5172 case kMax:
5173 {
5176 subform->UpdateFormulaLeaves();
5177 break;
5178 }
5179 default:
5180 break;
5181 }
5182 }
5183 default:
5184 break;
5185 }
5187}
5188
5189////////////////////////////////////////////////////////////////////////////////
5190/// Populate the TTreeFormulaManager with the dimension information.
5191
5193 Int_t i,k;
5194
5195 // Now that we saw all the expressions and variables AND that
5196 // we know whether arrays of chars are treated as string or
5197 // not, we can properly setup the dimensions.
5198 TIter next(fDimensionSetup);
5199 Int_t last_code = -1;
5200 Int_t virt_dim = 0;
5201 for(TDimensionInfo * info; (info = (TDimensionInfo*)next()); ) {
5202 if (last_code!=info->fCode) {
5203 // We know that the list is ordered by code number then by
5204 // dimension. Thus a different code means that we need to
5205 // restart at the lowest dimensions.
5206 virt_dim = 0;
5207 last_code = info->fCode;
5209 }
5210
5211 if (GetAction(info->fOper)==kDefinedString) {
5212
5213 // We have a string used as a string (and not an array of number)
5214 // We need to determine which is the last dimension and skip it.
5216 while(nextinfo && nextinfo->fCode==info->fCode) {
5217 DefineDimensions(info->fCode,info->fSize, info->fMultiDim, virt_dim);
5218 nextinfo = (TDimensionInfo*)next();
5219 }
5220 if (!nextinfo) break;
5221
5222 info = nextinfo;
5223 virt_dim = 0;
5224 last_code = info->fCode;
5226
5227 info->fSize = 1; // Maybe this should actually do nothing!
5228 }
5229
5230
5231 DefineDimensions(info->fCode,info->fSize, info->fMultiDim, virt_dim);
5232 }
5233
5234 fMultiplicity = 0;
5235 for(i=0;i<fNoper;i++) {
5236 Int_t action = GetAction(i);
5237
5238 if (action==kMinIf || action==kMaxIf) {
5239 // Skip/Ignore the 2nd args
5240 ++i;
5241 continue;
5242 }
5243 if (action==kAlias || action==kAliasString) {
5246 switch(subform->GetMultiplicity()) {
5247 case 0: break;
5248 case 1: fMultiplicity = 1; break;
5249 case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
5250 }
5252 // since we are addint to this manager 'subform->ResetDimensions();'
5253 // will be called a little latter
5254 continue;
5255 }
5256 if (action==kDefinedString) {
5257 //if (fOper[i] >= 105000 && fOper[i]<110000) {
5258 // We have a string used as a string
5259
5260 // This dormant portion of code would be used if (when?) we allow the histogramming
5261 // of the integral content (as opposed to the string content) of strings
5262 // held in a variable size container delimited by a null (as opposed to
5263 // a fixed size container or variable size container whose size is controlled
5264 // by a variable). In GetNdata, we will then use strlen to grab the current length.
5265 //fCumulSizes[i][fNdimensions[i]-1] = 1;
5266 //fUsedSizes[fNdimensions[i]-1] = -TMath::Abs(fUsedSizes[fNdimensions[i]-1]);
5267 //fUsedSizes[0] = - TMath::Abs( fUsedSizes[0]);
5268
5269 //continue;
5270 }
5271 }
5272
5273 for (i=0;i<fNcodes;i++) {
5274 if (fCodes[i] < 0) {
5276 if (!gcut) continue;
5277 TTreeFormula *fx = (TTreeFormula *)gcut->GetObjectX();
5278 TTreeFormula *fy = (TTreeFormula *)gcut->GetObjectY();
5279
5280 if (fx) {
5281 switch(fx->GetMultiplicity()) {
5282 case 0: break;
5283 case 1: fMultiplicity = 1; break;
5284 case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
5285 }
5286 fManager->Add(fx);
5287 }
5288 if (fy) {
5289 switch(fy->GetMultiplicity()) {
5290 case 0: break;
5291 case 1: fMultiplicity = 1; break;
5292 case 2: if (fMultiplicity!=1) fMultiplicity = 2; break;
5293 }
5294 fManager->Add(fy);
5295 }
5296
5297 continue;
5298 }
5299
5300 if (fLookupType[i]==kIteration) {
5301 fMultiplicity = 1;
5302 continue;
5303 }
5304
5305 TLeaf *leaf = i <= fLeaves.GetLast() ? (TLeaf*)fLeaves.UncheckedAt(i) : nullptr;
5306 if (!leaf) continue;
5307
5308 // Reminder of the meaning of fMultiplicity:
5309 // -1: Only one or 0 element per entry but contains variable length
5310 // -array! (Only used for TTreeFormulaManager)
5311 // 0: Only one element per entry, no variable length array
5312 // 1: loop over the elements of a variable length array
5313 // 2: loop over elements of fixed length array (nData is the same for all entry)
5314
5315 if (leaf->GetLeafCount()) {
5316 // We assume only one possible variable length dimension (the left most)
5317 fMultiplicity = 1;
5318 } else if (fLookupType[i]==kDataMember) {
5320 TStreamerElement * elem = leafinfo->fElement;
5321 if (fMultiplicity!=1) {
5322 if (leafinfo->HasCounter() ) fMultiplicity = 1;
5323 else if (elem && elem->GetArrayDim()>0) fMultiplicity = 2;
5324 else if (leaf->GetLenStatic()>1) fMultiplicity = 2;
5325 }
5326 } else {
5327 if (leaf->GetLenStatic()>1 && fMultiplicity!=1) fMultiplicity = 2;
5328 }
5329 if (fMultiplicity!=1) {
5330 // If the leaf belongs to a friend tree which has an index, we might
5331 // be in the case where some entry do not exist.
5332
5333 TTree *realtree = fTree ? fTree->GetTree() : nullptr;
5334 TTree *tleaf = leaf->GetBranch()->GetTree();
5335 if (tleaf && tleaf != realtree && tleaf->GetTreeIndex()) {
5336 // Reset the multiplicity if we have a friend tree with an index.
5337 fMultiplicity = 1;
5338 }
5339 }
5340
5341 Int_t virt_dim2 = 0;
5342 for (k = 0; k < fNdimensions[i]; k++) {
5343 // At this point fCumulSizes[i][k] actually contain the physical
5344 // dimension of the k-th dimensions.
5345 if ( (fCumulSizes[i][k]>=0) && (fIndexes[i][k] >= fCumulSizes[i][k]) ) {
5346 // unreachable element requested:
5347 fManager->CancelDimension(virt_dim2); // fCumulUsedSizes[virt_dim2] = 0;
5348 }
5349 if ( fIndexes[i][k] < 0 ) virt_dim2++;
5350 fFixedSizes[i][k] = fCumulSizes[i][k];
5351 }
5352
5353 // Add up the cumulative size
5354 for (k = fNdimensions[i] - 1; (k > 0); k--) {
5355 // NOTE: When support for inside variable dimension is added this
5356 // will become inaccurate (since one of the value in the middle of the chain
5357 // is unknown until GetNdata is called.
5358 fCumulSizes[i][k-1] *= TMath::Abs(fCumulSizes[i][k]);
5359 }
5360 // NOTE: We assume that the inside variable dimensions are dictated by the
5361 // first index.
5362 if (fCumulSizes[i][0]>0) fNdata[i] = fCumulSizes[i][0];
5363
5364 //for (k = 0; k<kMAXFORMDIM; k++) {
5365 // if (fVarIndexes[i][k]) fManager->Add(fVarIndexes[i][k]);
5366 //}
5367
5369}
5370
5371////////////////////////////////////////////////////////////////////////////////
5372/// Make sure that all the branches have been loaded properly.
5373
5375{
5376 Int_t i;
5377 for (i=0; i<fNoper ; ++i) {
5379 if (leaf==nullptr) continue;
5380
5381 TBranch *br = leaf->GetBranch();
5382 Long64_t treeEntry = br->GetTree()->GetReadEntry();
5384
5386 if (alias) alias->LoadBranches();
5387
5388 Int_t max_dim = fNdimensions[i];
5389 for (Int_t dim = 0; dim < max_dim; ++dim) {
5390 if (fVarIndexes[i][dim]) fVarIndexes[i][dim]->LoadBranches();
5391 }
5393}
5394
5395////////////////////////////////////////////////////////////////////////////////
5396/// Calculate the actual dimension for the current entry.
5397
5399 Int_t size;
5400 bool outofbounds = false;
5401
5402 for (Int_t i=0;i<fNcodes;i++) {
5403 if (fCodes[i] < 0) continue;
5404
5405 // NOTE: Currently only the leafcount can indicate a dimension that
5406 // is physically variable. So only the left-most dimension is variable.
5407 // When an API is introduced to be able to determine a variable inside dimensions
5408 // one would need to add a way to recalculate the values of fCumulSizes for this
5409 // leaf. This would probably require the addition of a new data member
5410 // fSizes[kMAXCODES][kMAXFORMDIM];
5411 // Also note that EvalInstance expect all the values (but the very first one)
5412 // of fCumulSizes to be positive. So indicating that a physical dimension is
5413 // variable (expected for the first one) can NOT be done via negative values of
5414 // fCumulSizes.
5415
5416 TLeaf *leaf = i <= fLeaves.GetLast() ? (TLeaf *)fLeaves.UncheckedAt(i) : nullptr;
5417 if (!leaf) {
5418 switch(fLookupType[i]) {
5419 case kDirect:
5420 case kMethod:
5421 case kTreeMember:
5422 case kDataMember:
5423 fNdata[i] = 0;
5424 outofbounds = true;
5425 }
5426 continue;
5427 }
5428
5430 TTree *tleaf = leaf->GetBranch()->GetTree();
5431 if (tleaf && tleaf != realtree && tleaf->GetTreeIndex()) {
5432 if (tleaf->GetReadEntry() < 0) {
5433 fNdata[i] = 0;
5434 outofbounds = true;
5435 continue;
5436 } else {
5437 fNdata[i] = fCumulSizes[i][0];
5438 }
5439 }
5440 bool hasBranchCount2 = false;
5441 if (leaf->GetLeafCount()) {
5442 TLeaf* leafcount = leaf->GetLeafCount();
5443 TBranch *branchcount = leafcount->GetBranch();
5444 TFormLeafInfo * info = nullptr;
5445 if (leaf->IsA() == TLeafElement::Class()) {
5446 //if branchcount address not yet set, GetEntry will set the address
5447 // read branchcount value
5448 Long64_t readentry = leaf->GetBranch()->GetTree()->GetReadEntry();
5449 if (readentry < 0) readentry=0;
5450 if (!branchcount->GetAddress()) {
5452 } else {
5453 // Since we do not read the full branch let's reset the read entry number
5454 // so that a subsequent read from TTreeFormula will properly load the full
5455 // object even if fQuickLoad is true.
5456 branchcount->TBranch::GetEntry(readentry);
5457 branchcount->ResetReadEntry();
5458 }
5459
5460 size = ((TBranchElement*)branchcount)->GetNdata();
5461 // Reading the size as above is correct only when the branchcount
5462 // is of streamer type kCounter which require the underlying data
5463 // member to be signed integral type.
5464
5465 TBranchElement* branch = (TBranchElement*) leaf->GetBranch();
5466 if (branch->GetAddress() == nullptr) {
5467 // Humm there is no space reserve to write the data,
5468 // the data member is likely 'removed' from the class
5469 // layout, so rather than crashing by accessing
5470 // random memory, make it clear we can't read it.
5471 size = 0;
5472 }
5473
5474 // NOTE: could be sped up
5475 if (fHasMultipleVarDim[i]) {// info && info->GetVarDim()>=0) {
5477 if (branch->GetBranchCount2()) R__LoadBranch(branch->GetBranchCount2(),readentry,fQuickLoad);
5479
5480 // Here we need to add the code to take in consideration the
5481 // double variable length
5482 // We fill up the array of sizes in the TLeafInfo:
5483 info->LoadSizes(branch);
5484 hasBranchCount2 = true;
5485 if (info->GetVirtVarDim()>=0) info->UpdateSizes(fManager->fVarDims[info->GetVirtVarDim()]);
5486
5487 // Refresh the fCumulSizes[i] to have '1' for the
5488 // double variable dimensions
5489 Int_t vdim = info->GetVarDim();
5490 fCumulSizes[i][vdim] = fCumulSizes[i][vdim+1];
5491 for(Int_t k=vdim -1; k>=0; k--) {
5492 fCumulSizes[i][k] = fCumulSizes[i][k+1]*fFixedSizes[i][k];
5493 }
5494 // Update fCumulUsedSizes
5495 // UpdateMultiVarSizes(vdim,info,i)
5496 //Int_t fixed = fCumulSizes[i][vdim+1];
5497 //for(Int_t k=vdim - 1; k>=0; k++) {
5498 // Int_t fixed *= fFixedSizes[i][k];
5499 // for(Int_t l=0;l<size; l++) {
5500 // fCumulSizes[i][k] += info->GetSize(l) * fixed;
5501 //}
5502 }
5503 } else {
5504 Long64_t readentry = leaf->GetBranch()->GetTree()->GetReadEntry();
5505 if (readentry < 0) readentry=0;
5507 size = leaf->GetLen() / leaf->GetLenStatic();
5508 }
5509 if (hasBranchCount2) {
5510 // We assume that fCumulSizes[i][1] contains the product of the fixed sizes
5511 fNdata[i] = fCumulSizes[i][1] * ((TFormLeafInfo *)fDataMembers.At(i))->GetSumOfSizes();
5512 } else {
5513 fNdata[i] = size * fCumulSizes[i][1];
5514 }
5515 if (fIndexes[i][0]==-1) {
5516 // Case where the index is not specified AND the 1st dimension has a variable
5517 // size.
5518 if (fManager->fUsedSizes[0]==1 || (size<fManager->fUsedSizes[0]) ) fManager->fUsedSizes[0] = size;
5519 if (info && fIndexes[i][info->GetVarDim()]>=0) {
5520 for(Int_t j=0; j<size; j++) {
5521 if (fIndexes[i][info->GetVarDim()] >= info->GetSize(j)) {
5522 info->SetSize(j,0);
5525 } else if (fIndexes[i][info->GetVarDim()]>=0) {
5526 // There is an index and it is not too large
5527 info->SetSize(j,1);
5530 }
5531 }
5532 }
5533 } else if (fIndexes[i][0] >= size) {
5534 // unreachable element requested:
5535 fManager->fUsedSizes[0] = 0;
5536 fNdata[i] = 0;
5537 outofbounds = true;
5538 } else if (hasBranchCount2) {
5541 if (fIndexes[i][0]<0
5542 || fIndexes[i][info2->GetVarDim()] >= info2->GetSize(fIndexes[i][0])) {
5543 // unreachable element requested:
5544 fManager->fUsedSizes[0] = 0;
5545 fNdata[i] = 0;
5546 outofbounds = true;
5547 }
5548 }
5549 } else if (fLookupType[i]==kDataMember) {
5551 if (leafinfo->HasCounter()) {
5552 TBranch *branch = leaf->GetBranch();
5553 Long64_t readentry = branch->GetTree()->GetReadEntry();
5554 if (readentry < 0) readentry=0;
5556 size = (Int_t) leafinfo->GetCounterValue(leaf);
5557 if (fIndexes[i][0]==-1) {
5558 // Case where the index is not specified AND the 1st dimension has a variable
5559 // size.
5560 if (fManager->fUsedSizes[0]==1 || (size<fManager->fUsedSizes[0]) ) {
5561 fManager->fUsedSizes[0] = size;
5562 }
5563 } else if (fIndexes[i][0] >= size) {
5564 // unreachable element requested:
5565 fManager->fUsedSizes[0] = 0;
5566 fNdata[i] = 0;
5567 outofbounds = true;
5568 } else {
5569 fNdata[i] = size*fCumulSizes[i][1];
5570 }
5571 Int_t vdim = leafinfo->GetVarDim();
5572 if (vdim>=0) {
5573 // Here we need to add the code to take in consideration the
5574 // double variable length
5575 // We fill up the array of sizes in the TLeafInfo:
5576 // here we can assume that branch is a TBranch element because the other style does NOT support this type
5577 // of complexity.
5578 leafinfo->LoadSizes(branch);
5579 hasBranchCount2 = true;
5580 if (fIndexes[i][0]==-1&&fIndexes[i][vdim] >= 0) {
5581 for(int z=0; z<size; ++z) {
5582 if (fIndexes[i][vdim] >= leafinfo->GetSize(z)) {
5583 leafinfo->SetSize(z,0);
5584 // --fManager->fUsedSizes[0];
5585 } else if (fIndexes[i][vdim] >= 0 ) {
5586 leafinfo->SetSize(z,1);
5587 }
5588 }
5589 }
5590 leafinfo->UpdateSizes(fManager->fVarDims[vdim]);
5591
5592 // Refresh the fCumulSizes[i] to have '1' for the
5593 // double variable dimensions
5594 fCumulSizes[i][vdim] = fCumulSizes[i][vdim+1];
5595 for(Int_t k=vdim -1; k>=0; k--) {
5596 fCumulSizes[i][k] = fCumulSizes[i][k+1]*fFixedSizes[i][k];
5597 }
5598 fNdata[i] = fCumulSizes[i][1] * leafinfo->GetSumOfSizes();
5599 } else {
5600 fNdata[i] = size * fCumulSizes[i][1];
5601 }
5602 } else if (leafinfo->GetMultiplicity()==-1) {
5603 TBranch *branch = leaf->GetBranch();
5604 Long64_t readentry = branch->GetTree()->GetReadEntry();
5605 if (readentry < 0) readentry=0;
5607 if (leafinfo->GetNdata(leaf)==0) {
5608 outofbounds = true;
5609 }
5610 }
5611 }
5612 // However we allow several dimensions that virtually vary via the size of their
5613 // index variables. So we have code to recalculate fCumulUsedSizes.
5614 TFormLeafInfo * info = nullptr;
5615 if (fLookupType[i]!=kDirect) {
5617 }
5618 for(Int_t k=0, virt_dim=0; k < fNdimensions[i]; k++) {
5619 if (fIndexes[i][k]<0) {
5620 if (info && fIndexes[i][k]==-2 && fVarIndexes[i][k]->GetManager()->GetMultiplicity()==0) {
5621 // Index and thus local size provided by a "index variable of size 1"
5622 Int_t index = fVarIndexes[i][k]->EvalInstance(0);
5623 Int_t index_size = info->GetSize(index);
5624 if (fManager->fUsedSizes[virt_dim]==1 || (index_size!=1 && index_size<fManager->fUsedSizes[virt_dim]) )
5626 } else if (fIndexes[i][k]==-2 && fManager->fVirtUsedSizes[virt_dim]<0) {
5627
5628 // if fVirtUsedSize[virt_dim] is positive then VarIndexes[i][k]->GetNdata()
5629 // is always the same and has already been factored in fUsedSize[virt_dim]
5631 if (index_size==1) {
5632 // We could either have a variable size array which is currently of size one
5633 // or a single element that might or not might not be present (and is currently present!)
5634 if (fVarIndexes[i][k]->GetManager()->GetMultiplicity()==1) {
5636 }
5637
5639 index_size<fManager->fUsedSizes[virt_dim]) {
5641 }
5642
5643 } else if (hasBranchCount2 && info && k==info->GetVarDim()) {
5644 // NOTE: We assume the indexing of variable sizes on the first index!
5645 if (fIndexes[i][0]>=0) {
5646 Int_t index_size = info->GetSize(fIndexes[i][0]);
5647 if (fManager->fUsedSizes[virt_dim]==1 || (index_size!=1 && index_size<fManager->fUsedSizes[virt_dim]) )
5649 }
5650 }
5651 virt_dim++;
5652 } else if (hasBranchCount2 && info && k==info->GetVarDim()) {
5653
5654 // nothing to do, at some point I thought this might be useful:
5655 // if (fIndexes[i][k]>=0) {
5656 // index = info->GetSize(fIndexes[i][k]);
5657 // if (fManager->fUsedSizes[virt_dim]==1 || (index!=1 && index<fManager->fUsedSizes[virt_dim]) )
5658 // fManager->fUsedSizes[virt_dim] = index;
5659 // virt_dim++;
5660 // }
5661
5662 }
5663 }
5664 }
5665 return ! outofbounds;
5666
5667
5668
5669}
5670
5672{
5673 // Convert the fOper of a TTTreeFormula version fromVersion to the current in memory version
5674
5675 enum { kOldAlias = /*ROOT::v5::TFormula::kVariable*/ 100000+10000+1,
5679 };
5680
5681 for (int k=0; k<fNoper; k++) {
5682 // First hide from ROOT::v5::TFormula convertion
5683
5684 Int_t action = GetOper()[k];
5685
5686 switch (action) {
5687
5688 case kOldAlias: GetOper()[k] = -kOldAlias; break;
5689 case kOldAliasString: GetOper()[k] = -kOldAliasString; break;
5690 case kOldAlternate: GetOper()[k] = -kOldAlternate; break;
5691 case kOldAlternateString: GetOper()[k] = -kOldAlternateString; break;
5692 }
5693 }
5694
5696
5697 for (int i=0,offset=0; i<fNoper; i++) {
5698 Int_t action = GetOper()[i+offset];
5699
5700 switch (action) {
5701 case -kOldAlias: SetAction(i, kAlias, 0); break;
5702 case -kOldAliasString: SetAction(i, kAliasString, 0); break;
5703 case -kOldAlternate: SetAction(i, kAlternate, 0); break;
5704 case -kOldAlternateString: SetAction(i, kAlternateString, 0); break;
5705 }
5706 }
5707
5708}
5709
5710////////////////////////////////////////////////////////////////////////////////
5711/// Convert the underlying lookup method from the direct technique
5712/// (dereferencing the address held by the branch) to the method using
5713/// TFormLeafInfo. This is in particular useful in the case where we
5714/// need to append an additional TFormLeafInfo (for example to call a
5715/// method).
5716/// Return false if the switch was unsuccessful (basically in the
5717/// case of an old style split tree).
5718
5720{
5721 TFormLeafInfo *last = nullptr;
5722 TLeaf *leaf = (TLeaf*)fLeaves.At(code);
5723 if (!leaf) return false;
5724
5725 if (fLookupType[code]==kDirect) {
5726 if (leaf->InheritsFrom(TLeafElement::Class())) {
5727 TBranchElement * br = (TBranchElement*)leaf->GetBranch();
5728 if (br->GetType()==31) {
5729 // sub branch of a TClonesArray
5730 TStreamerInfo *info = br->GetInfo();
5731 TClass* cl = info->GetClass();
5732 TStreamerElement *element = (TStreamerElement *)info->GetElement(br->GetID());
5734 Int_t offset;
5735 info->GetStreamerElement(element->GetName(),offset);
5736 clonesinfo->fNext = new TFormLeafInfo(cl,offset+br->GetOffset(),element);
5737 last = clonesinfo->fNext;
5740
5741 } else if (br->GetType()==41) {
5742 // sub branch of a Collection
5743
5744 TBranchElement *count = br->GetBranchCount();
5746 if ( count->GetID() >= 0 ) {
5748 (TStreamerElement *)count->GetInfo()->GetElement(count->GetID());
5749 TClass *collectionCl = collectionElement->GetClassPointer();
5750
5753 } else {
5757 }
5758
5759 TStreamerInfo *info = br->GetInfo();
5760 TClass* cl = info->GetClass();
5761 TStreamerElement *element = (TStreamerElement *)info->GetElement(br->GetID());
5762 Int_t offset;
5763 info->GetStreamerElement(element->GetName(),offset);
5764 collectioninfo->fNext = new TFormLeafInfo(cl,offset+br->GetOffset(),element);
5765 last = collectioninfo->fNext;
5768
5769 } else if (br->GetID()<0) {
5770 return false;
5771 } else {
5772 last = new TFormLeafInfoDirect(br);
5773 fDataMembers.AddAtAndExpand(last,code);
5775 }
5776 } else {
5777 //last = new TFormLeafInfoDirect(br);
5778 //fDataMembers.AddAtAndExpand(last,code);
5779 //fLookupType[code]=kDataMember;
5780 return false;
5781 }
5782 }
5783 return true;
5784}
#define lenfunc
Definition CPyCppyy.h:224
#define d(i)
Definition RSha256.hxx:102
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
static Roo_reg_AGKInteg1D instance
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
int Int_t
Definition RtypesCore.h:45
long Longptr_t
Definition RtypesCore.h:75
short Version_t
Definition RtypesCore.h:65
char Char_t
Definition RtypesCore.h:37
unsigned long ULong_t
Definition RtypesCore.h:55
long Long_t
Definition RtypesCore.h:54
unsigned int UInt_t
Definition RtypesCore.h:46
short Short_t
Definition RtypesCore.h:39
double Double_t
Definition RtypesCore.h:59
long double LongDouble_t
Definition RtypesCore.h:61
long long Long64_t
Definition RtypesCore.h:69
unsigned long long ULong64_t
Definition RtypesCore.h:70
#define ClassImp(name)
Definition Rtypes.h:374
const Int_t kDoNotProcess
Definition TBranch.h:56
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
const Int_t kMaxLen
#define gDirectory
Definition TDirectory.h:384
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
winID h TVirtualViewer3D TVirtualGLPainter p
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 offset
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 r
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 value
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 UChar_t len
Option_t Option_t TPoint TPoint const char mode
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
R__EXTERN TRandom * gRandom
Definition TRandom.h:62
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2489
#define TT_EVAL_INIT_LOOP
#define TREE_EVAL_INIT
#define TT_EVAL_INIT
T FindMin(TTreeFormula *arr)
static void R__LoadBranch(TBranch *br, Long64_t entry, bool quickLoad)
T FindMax(TTreeFormula *arr)
const Int_t kMaxLen
#define TREE_EVAL_INIT_LOOP
T Summing(TTreeFormula *sum)
const Int_t kMAXCODES
const Int_t kMAXFORMDIM
#define snprintf
Definition civetweb.c:1540
const_iterator begin() const
const_iterator end() const
Double_t * fConst
Definition TFormula.h:82
TObjArray fFunctions
Definition TFormula.h:85
virtual void Convert(UInt_t fromVersion)
Int_t * GetOper() const
Definition TFormula.h:103
TString * fExpr
Definition TFormula.h:78
virtual Int_t GetNdim() const
Definition TFormula.h:237
Short_t GetAction(Int_t code) const
Definition TFormula.h:104
Int_t GetActionParam(Int_t code) const
Definition TFormula.h:105
virtual Int_t Compile(const char *expression="")
Compile expression already stored in fTitle.
void SetAction(Int_t code, Int_t value, Int_t param=0)
Definition TFormula.h:107
void Streamer(TBuffer &b, const TClass *onfile_class)
Stream a class object.
virtual Bool_t IsString(Int_t oper) const
Return true if the expression at the index 'oper' has to be treated as a string.
void Set(Int_t n) override
Set size of this array to n ints.
Definition TArrayI.cxx:105
const Int_t * GetArray() const
Definition TArrayI.h:43
Int_t At(Int_t i) const
Definition TArrayI.h:79
void AddAt(Int_t c, Int_t i)
Add Int_t c at position i. Check for out of bounds.
Definition TArrayI.cxx:93
Int_t GetSize() const
Definition TArray.h:47
Class to manage histogram axis.
Definition TAxis.h:32
@ kIsInteger
Definition TAxis.h:76
virtual Int_t FindBin(Double_t x)
Find bin number corresponding to abscissa x.
Definition TAxis.cxx:288
static TClass * Class()
A Branch for the case of an object.
static TClass * Class()
Int_t GetID() const
const char * GetClassName() const override
Return the name of the user class whose content is stored in this branch, if any.
TStreamerInfo * GetInfo() const
Get streamer info for the branch class.
A Branch for the case of an object.
static TClass * Class()
A TTree is a list of TBranches.
Definition TBranch.h:93
Buffer base class used for serializing objects.
Definition TBuffer.h:43
TClassRef is used to implement a permanent reference to a TClass object.
Definition TClassRef.h:29
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
Bool_t HasDataMemberInfo() const
Definition TClass.h:413
ClassInfo_t * GetClassInfo() const
Definition TClass.h:440
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:4696
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition TClass.cxx:2998
TMethod * GetMethodAllAny(const char *method)
Return pointer to method without looking at parameters.
Definition TClass.cxx:4481
TVirtualRefProxy * GetReferenceProxy() const
Definition TClass.h:490
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:3069
An array of clone (identical) objects.
static TClass * Class()
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Graphical cut class.
Definition TCutG.h:20
A small helper class to help in keeping track of the array dimensions encountered in the analysis of ...
TDimensionInfo(Int_t code, Int_t oper, Int_t size, TFormLeafInfoMultiVarDim *multiDim)
~TDimensionInfo() override
TFormLeafInfoMultiVarDim * fMultiDim
Describe directory structure in memory.
Definition TDirectory.h:45
A List of entry numbers in a TTree or TChain.
Definition TEntryList.h:26
virtual Int_t Contains(Long64_t entry, TTree *tree=nullptr)
A small helper class to implement casting an object to a different type (equivalent to dynamic_cast)
A small helper class to implement reading a data member on a TClonesArray object stored in a TTree.
A small helper class to implement reading a data member on a TClonesArray object stored in a TTree.
Used to return the size of a collection.
A small helper class to implement reading a data member on a generic collection object stored in a TT...
A small helper class to implement reading a data member on an object stored in a TTree.
Asmall helper class to implement executing a method of an object stored in a TTree.
static TClass * ReturnTClass(TMethodCall *mc)
Return the TClass corresponding to the return type of the function if it is an object type or if the ...
A small helper class to implement reading a data member on a variable size array inside a TClonesArra...
A small helper class to implement reading a data member on a variable size array inside a TClonesArra...
A small helper class to implement reading a data member on a variable size array inside a TClonesArra...
A helper class to implement reading a data member on a variable size array inside a TClonesArray obje...
A small helper class to implement reading a numerical value inside a collection.
A small helper class to implement reading a data member by following a pointer inside a branch of TTr...
A small helper class to implement the following of reference objects stored in a TTree.
A small helper class to implement reading from the containing TTree object itself.
This class is a small helper class to implement reading a data member on an object stored in a TTree.
virtual void * GetValuePointer(TLeaf *leaf, Int_t instance=0)
returns the address of the value pointed to by the serie of TFormLeafInfo.
virtual bool Update()
We reloading all cached information in case the underlying class information has changed (for example...
virtual TClass * GetClass() const
Get the class of the underlying data.
TFormLeafInfo * fNext
follow this to grab the inside information
The Formula class.
Definition TFormula.h:89
static TClass * Class()
static TClass * Class()
A TLeaf for the general case when using the branches created via a TStreamerInfo (i....
static TClass * Class()
A TLeaf for a general object derived from TObject.
Definition TLeafObject.h:31
static TClass * Class()
A TLeaf describes individual elements of a TBranch See TBranch structure in TTree.
Definition TLeaf.h:57
A doubly linked list.
Definition TList.h:38
void Add(TObject *obj) override
Definition TList.h:81
void Delete(Option_t *option="") override
Remove all objects from the list AND delete all heap based objects.
Definition TList.cxx:468
Method or function calling interface.
Definition TMethodCall.h:37
static const EReturnType kLong
Definition TMethodCall.h:43
static const EReturnType kString
Definition TMethodCall.h:45
static const EReturnType kOther
Definition TMethodCall.h:46
static const EReturnType kDouble
Definition TMethodCall.h:44
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:50
TNamed()
Definition TNamed.h:38
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:150
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
void AddAt(TObject *obj, Int_t idx) override
Add object at position ids.
virtual void AddAtAndExpand(TObject *obj, Int_t idx)
Add object at position idx.
void Streamer(TBuffer &) override
Stream all objects in the array to or from the I/O buffer.
Int_t GetEntries() const override
Return the number of objects in array (i.e.
void Delete(Option_t *option="") override
Remove all objects from the array AND delete all heap based objects.
TObject * At(Int_t idx) const override
Definition TObjArray.h:164
TObject * UncheckedAt(Int_t i) const
Definition TObjArray.h:84
TObject * FindObject(const char *name) const override
Find an object in this collection using its name.
Int_t GetLast() const override
Return index of last object in array.
Mother of all ROOT objects.
Definition TObject.h:41
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:203
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1040
virtual void Execute(const char *method, const char *params, Int_t *error=nullptr)
Execute method on this object with the given parameter string, e.g.
Definition TObject.cxx:377
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:847
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1054
void ResetBit(UInt_t f)
Definition TObject.h:202
Double_t Rndm() override
Machine independent random number generator.
Definition TRandom.cxx:559
static TClass * Class()
const char * GetCountName() const
Describes a persistent version of a class.
TStreamerElement * GetElement(Int_t id) const override
Basic string class.
Definition TString.h:139
const char * Data() const
Definition TString.h:376
static TClass * Class()
bool fMultiVarDim
True if one of the variable has 2 variable size dimensions.
virtual void UpdateUsedSize(Int_t &virt_dim, Int_t vsize)
Reload the array sizes.
Int_t fVirtUsedSizes[kMAXFORMDIM+1]
Virtual size of lower dimensions as seen for this formula.
Int_t fNdata
! Last value calculated by GetNdata
TArrayI * fCumulUsedVarDims
fCumulUsedSizes(1) for multi variable dimensions case
TArrayI * fVarDims[kMAXFORMDIM+1]
List of variable sizes dimensions.
virtual void EnableMultiVarDims()
Set the manager as handling a formula with multiple variable dimensions.
virtual void CancelDimension(Int_t virt_dim)
Cancel a dimension.
Int_t fCumulUsedSizes[kMAXFORMDIM+1]
Accumulated size of lower dimensions as seen for this entry.
Int_t fUsedSizes[kMAXFORMDIM+1]
Actual size of the dimensions as seen for this entry.
virtual Int_t GetNdata(bool forceLoadDim=false)
Return number of available instances in the formulas.
virtual void Add(TTreeFormula *)
Add a new formula to the list of formulas managed The manager of the formula will be changed and the ...
virtual bool Sync()
Synchronize all the formulae.
virtual void AddVarDims(Int_t virt_dim)
Add a variable dimension.
virtual void Remove(TTreeFormula *)
Remove a formula from this manager.
virtual Int_t GetMultiplicity() const
Used to pass a selection expression to the Tree drawing routine.
bool LoadCurrentDim()
Calculate the actual dimension for the current entry.
virtual void ResetLoading()
Tell the formula that we are going to request a new entry.
virtual bool IsInteger(bool fast=true) const
Return TRUE if the formula corresponds to one single Tree leaf and this leaf is short,...
bool fHasCast
Record whether the formula contain a cast operation or not.
UChar_t fHasMultipleVarDim[kMAXCODES]
True if the corresponding variable is an array with more than one variable dimension.
Int_t fMultiplicity
Indicator of the variability of the formula.
Int_t FindLeafForExpression(const char *expression, TLeaf *&leaf, TString &leftover, bool &final, UInt_t &paran_level, TObjArray &castqueue, std::vector< std::string > &aliasUsed, bool &useLeafCollectionObject, const char *fullExpression)
Look for the leaf corresponding to the start of expression.
TTreeFormula()=delete
Int_t DefineAlternate(const char *expression)
This method check for treat the case where expression contains $Atl and load up both fAliases and fEx...
TTreeFormulaManager * GetManager() const
virtual TLeaf * GetLeaf(Int_t n) const
Return leaf corresponding to serial number n.
TAxis * fAxis
! pointer to histogram axis if this is a string
Int_t fNindex
Size of fIndex.
Int_t fNcodes
Number of leaves referenced in formula.
Int_t RegisterDimensions(Int_t code, Int_t size, TFormLeafInfoMultiVarDim *multidim=nullptr)
This method stores the dimension information for later usage.
TObjArray fExternalCuts
! List of TCutG and TEntryList used in the formula
Int_t DefinedVariable(TString &variable, Int_t &action) override
Check if name is in the list of Tree/Branch leaves.
virtual Double_t GetValueFromMethod(Int_t i, TLeaf *leaf) const
Return result of a leafobject method.
virtual const char * EvalStringInstance(Int_t i=0)
Eval the instance as a string.
void Init(const char *name, const char *formula)
Initialization called from the constructors.
Int_t * fLookupType
[fNindex] Array indicating how each leaf should be looked-up
bool fQuickLoad
! If true, branch GetEntry is only called when the entry number changes.
Int_t ParseWithLeaf(TLeaf *leaf, const char *expression, bool final, UInt_t paran_level, TObjArray &castqueue, bool useLeafCollectionObject, const char *fullExpression)
Decompose 'expression' as pointing to something inside the leaf Returns:
virtual bool SwitchToFormLeafInfo(Int_t code)
Convert the underlying lookup method from the direct technique (dereferencing the address held by the...
std::vector< std::string > fAliasesUsed
! List of aliases used during the parsing of the expression.
Int_t fCodes[kMAXCODES]
List of leaf numbers referenced in formula.
virtual char * PrintValue(Int_t mode=0) const
Return value of variable as a string.
bool fNeedLoading
! If true, the current entry has not been loaded yet.
Int_t fIndexes[kMAXCODES][kMAXFORMDIM]
Index of array selected by user for each leaf.
virtual Int_t GetMultiplicity() const
void Streamer(TBuffer &) override
Stream an object of class TTreeFormula.
Int_t fCumulSizes[kMAXCODES][kMAXFORMDIM]
Accumulated sizes of lower dimensions for each leaf after variable dimensions has been calculated.
virtual bool IsString() const
Return TRUE if the formula is a string.
TList * fDimensionSetup
! list of dimension setups, for delayed creation of the dimension information.
T EvalInstance(Int_t i=0, const char *stringStack[]=nullptr)
Evaluate this treeformula.
void ResetDimensions()
Populate the TTreeFormulaManager with the dimension information.
Int_t fNdimensions[kMAXCODES]
Number of array dimensions in each leaf.
TTree * fTree
! Pointer to Tree
TLeaf * GetLeafWithDatamember(const char *topchoice, const char *nextchice, Long64_t readentry) const
Return the leaf (if any) which contains an object containing a data member which has the name provide...
TMethodCall * GetMethodCall(Int_t code) const
Return methodcall corresponding to code.
virtual void UpdateFormulaLeaves()
This function is called TTreePlayer::UpdateFormulaLeaves, itself called by TChain::LoadTree when a ne...
~TTreeFormula() override
Tree Formula default destructor.
TObjArray fAliases
! List of TTreeFormula for each alias used.
T GetConstant(Int_t k)
virtual void * EvalObject(Int_t i=0)
Evaluate this treeformula.
TObjArray fLeafNames
List of TNamed describing leaves.
bool StringToNumber(Int_t code) override
Try to 'demote' a string into an array bytes.
static TClass * Class()
virtual bool IsLeafInteger(Int_t code) const
Return TRUE if the leaf corresponding to code is short, int or unsigned short, int When a leaf is of ...
void DefineDimensions(Int_t code, Int_t size, TFormLeafInfoMultiVarDim *info, Int_t &virt_dim)
This method is used internally to decode the dimensions of the variables.
virtual bool IsLeafString(Int_t code) const
Return TRUE if the leaf or data member corresponding to code is a string.
void LoadBranches()
Make sure that all the branches have been loaded properly.
virtual TClass * EvalClass() const
Evaluate the class of this treeformula.
Int_t GetRealInstance(Int_t instance, Int_t codeindex)
Now let calculate what physical instance we really need.
virtual void SetAxis(TAxis *axis=nullptr)
Set the axis (in particular get the type).
TFormLeafInfo * GetLeafInfo(Int_t code) const
Return DataMember corresponding to code.
TObjArray fDataMembers
! List of leaf data members
bool BranchHasMethod(TLeaf *leaf, TBranch *branch, const char *method, const char *params, Long64_t readentry) const
Return the leaf (if any) of the tree with contains an object of a class having a method which has the...
TTreeFormula * fVarIndexes[kMAXCODES][kMAXFORMDIM]
Pointer to a variable index.
LongDouble_t * fConstLD
! local version of fConsts able to store bigger numbers
Int_t fFixedSizes[kMAXCODES][kMAXFORMDIM]
Physical sizes of lower dimensions for each leaf.
virtual Int_t GetNdata()
Return number of available instances in the formula.
RealInstanceCache fRealInstanceCache
! Cache accelerating the GetRealInstance function
TObjArray fMethods
! List of leaf method calls
Int_t fNdata[kMAXCODES]
! This caches the physical number of element in the leaf or data member.
TObjArray fLeaves
! List of leaf used in this formula.
bool fDidBooleanOptimization
! True if we executed one boolean optimization since the last time instance number 0 was evaluated
friend class TTreeFormulaManager
virtual void * GetValuePointerFromMethod(Int_t i, TLeaf *leaf) const
Return result of a leafobject method.
TObjArray fBranches
! List of branches to read. Similar to fLeaves but duplicates are zeroed out.
TTreeFormulaManager * fManager
! The dimension coordinator.
void Convert(UInt_t fromVersion) override
A TTree represents a columnar dataset.
Definition TTree.h:79
virtual TBranch * FindBranch(const char *name)
Return the branch that correspond to the path 'branchname', which can include the name of the tree or...
Definition TTree.cxx:4834
virtual TIterator * GetIteratorOnAllLeaves(bool dir=kIterForward)
Creates a new iterator that will go through all the leaves on the tree itself and its friend.
Definition TTree.cxx:6075
virtual Long64_t GetEntries() const
Definition TTree.h:463
virtual TLeaf * GetLeaf(const char *branchname, const char *leafname)
Return pointer to the 1st Leaf named name in any Branch of this Tree or any branch in the list of fri...
Definition TTree.cxx:6188
virtual Long64_t GetReadEntry() const
Definition TTree.h:549
virtual TObjArray * GetListOfBranches()
Definition TTree.h:528
virtual TTree * GetTree() const
Definition TTree.h:557
virtual Long64_t LoadTree(Long64_t entry)
Set current entry.
Definition TTree.cxx:6466
virtual const char * GetAlias(const char *aliasName) const
Returns the expanded value of the alias. Search in the friends if any.
Definition TTree.cxx:5219
virtual Int_t GetTreeNumber() const
Definition TTree.h:559
static TClass * Class()
virtual TLeaf * FindLeaf(const char *name)
Find leaf..
Definition TTree.cxx:4909
virtual const char * GetFriendAlias(TTree *) const
If the 'tree' is a friend, this method returns its alias name.
Definition TTree.cxx:6025
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...
virtual Bool_t HasCounter() const =0
virtual TObjArray * GetElements() const =0
RVec< PromoteTypes< T0, T1 > > fmod(const T0 &x, const RVec< T1 > &v)
Definition RVec.hxx:1834
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
tbb::task_arena is an alias of tbb::interface7::task_arena, which doesn't allow to forward declare tb...
Double_t CosH(Double_t)
Returns the hyperbolic cosine of x.
Definition TMath.h:616
Double_t ACos(Double_t)
Returns the principal value of the arc cosine of x, expressed in radians.
Definition TMath.h:636
Double_t ASin(Double_t)
Returns the principal value of the arc sine of x, expressed in radians.
Definition TMath.h:628
Double_t Exp(Double_t x)
Returns the base-e exponential function of x, which is e raised to the power x.
Definition TMath.h:713
Double_t ATan(Double_t)
Returns the principal value of the arc tangent of x, expressed in radians.
Definition TMath.h:644
Double_t ASinH(Double_t)
Returns the area hyperbolic sine of x.
Definition TMath.cxx:67
Double_t TanH(Double_t)
Returns the hyperbolic tangent of x.
Definition TMath.h:622
Double_t ACosH(Double_t)
Returns the nonnegative area hyperbolic cosine of x.
Definition TMath.cxx:81
Double_t ATan2(Double_t y, Double_t x)
Returns the principal value of the arc tangent of y/x, expressed in radians.
Definition TMath.h:650
Double_t Log(Double_t x)
Returns the natural logarithm of x.
Definition TMath.h:760
Double_t Sqrt(Double_t x)
Returns the square root of x.
Definition TMath.h:666
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Returns x raised to the power y.
Definition TMath.h:725
Double_t Cos(Double_t)
Returns the cosine of an angle of x radians.
Definition TMath.h:598
constexpr Double_t Pi()
Definition TMath.h:37
Double_t Sin(Double_t)
Returns the sine of an angle of x radians.
Definition TMath.h:592
Double_t Tan(Double_t)
Returns the tangent of an angle of x radians.
Definition TMath.h:604
Double_t ATanH(Double_t)
Returns the area hyperbolic tangent of x.
Definition TMath.cxx:95
Double_t Log10(Double_t x)
Returns the common (base-10) logarithm of x.
Definition TMath.h:766
Short_t Abs(Short_t d)
Returns the absolute value of parameter Short_t d.
Definition TMathBase.h:123
Double_t SinH(Double_t)
Returns the hyperbolic sine of `x.
Definition TMath.h:610
static const char * what
Definition stlLoader.cc:5
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4
static uint64_t sum(uint64_t i)
Definition Factory.cxx:2345
const UChar_t kTFOperShift
Definition TFormula.h:33
const Int_t kTFOperMask
Definition TFormula.h:32
const Int_t kMAXFOUND
Definition TFormula.h:31