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